Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt code to string immutability #98

Closed
wants to merge 71 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
1f2ffbf
Remove duplicated header.
carlonluca Jul 22, 2022
543a24b
Merge remote-tracking branch 'upstream/master' into dev
carlonluca Jul 20, 2023
2eafa00
Build fix: the compress_string function must be taken from the
carlonluca Jul 21, 2023
6fbc501
Merge branch 'zlib-fix' into dev
carlonluca Jul 21, 2023
497e8d7
Update syslog module from upstream
carlonluca Jun 4, 2024
4f649a8
Make the decode64 function compatible with immutable strings.
carlonluca Jun 4, 2024
7cfcf83
Make strings immutable in tcpbufferedsocket.
carlonluca Jun 4, 2024
0657f8c
Updated the bitstring library for string immutability.
carlonluca Jun 4, 2024
2307ee1
Updated http client implementation for string immutability.
carlonluca Jun 4, 2024
c0bb859
Ported base64 implementation to immutable strings.
carlonluca Jun 4, 2024
e997cc3
Ported commonFile to immutable strings.
carlonluca Jun 4, 2024
28f5791
Ported commonUploads to immutable strings.
carlonluca Jun 4, 2024
48d5f5f
Ported commonWeb to immutable strings.
carlonluca Jun 4, 2024
8476c2d
Ported giftDecoding to immutable strings.
carlonluca Jun 4, 2024
b7fa734
Ported gui encoding/decoding to immutable strings.
carlonluca Jun 4, 2024
90c7d8b
Ported driverCommands to immutable strings.
carlonluca Jun 5, 2024
422ade2
Ported daemon drivers to immutable strings.
carlonluca Jun 5, 2024
b2bd7d7
Ported mailer to immutable strings.
carlonluca Jun 5, 2024
044bd39
Ported udpsocket to immutable strings.
carlonluca Jun 5, 2024
5998414
Ported mp3tag to immutable strings.
carlonluca Jun 5, 2024
ba4764b
Ported utils to string immutability.
carlonluca Jun 5, 2024
2f85333
Ported cdk to string immutability.
carlonluca Jun 5, 2024
d39b60b
Ported gnutella to string immutability.
carlonluca Jun 5, 2024
ef7cc73
Ported filetp to string immutability.
carlonluca Jun 5, 2024
46643d8
Ported fasttrack to string immutability.
carlonluca Jun 5, 2024
b746d81
Ported direct_connect to string immutability.
carlonluca Jun 5, 2024
6ade6db
Ported svg_converter to string immutability.
carlonluca Jun 5, 2024
99b55ca
Ported donkey protocol to string immutability.
carlonluca Jun 5, 2024
18787df
Enable safe strings.
carlonluca Jun 5, 2024
57c47da
Ported to string immutability.
carlonluca Jun 6, 2024
32e3507
Fixed lexer.
carlonluca Jun 6, 2024
4e80f51
Minor change.
carlonluca Jun 6, 2024
25745f3
Minor change.
carlonluca Jun 6, 2024
f12c7ff
Minor change.
carlonluca Jun 6, 2024
0355136
Use a specific function to compare bytes and string literal.
carlonluca Jun 6, 2024
2333115
Improvements.
carlonluca Jun 6, 2024
a705213
Use bytes in gzip implementation.
carlonluca Jun 6, 2024
830a24c
Minor change.
carlonluca Jun 6, 2024
0b7014e
Improvement.
carlonluca Jun 6, 2024
20a6266
Minor change.
carlonluca Jun 6, 2024
c19f843
Avoid copies.
carlonluca Jun 6, 2024
c45e0f1
Performance improvement.
carlonluca Jun 6, 2024
541dd70
Performance improvement.
carlonluca Jun 6, 2024
03c82ef
Performance improvement.
carlonluca Jun 7, 2024
f4ace52
Performance improvement.
carlonluca Jun 7, 2024
5f7e467
Performance improvement.
carlonluca Jun 7, 2024
922c80d
Performance improvement.
carlonluca Jun 7, 2024
f0861fe
Avoid conversion.
carlonluca Jun 7, 2024
b72c6da
Avoid conversion.
carlonluca Jun 7, 2024
12265fd
Performance improvement.
carlonluca Jun 7, 2024
e1d628f
Performance improvement.
carlonluca Jun 7, 2024
4fbc27d
Performance improvement.
carlonluca Jun 7, 2024
4956e3c
Fixed warning.
carlonluca Jun 7, 2024
ca06b87
Fixed warning.
carlonluca Jun 7, 2024
b1ba27a
Fixed warning.
carlonluca Jun 7, 2024
da5af29
Fixed warnings.
carlonluca Jun 7, 2024
1b39956
String immutability in C code.
carlonluca Jun 7, 2024
5ce542e
Fixed warnings.
carlonluca Jun 7, 2024
668541b
Fixed hash functions.
carlonluca Jun 7, 2024
35faf07
Fixed warnings.
carlonluca Jun 7, 2024
83c5dfc
Fixed string immutability in c code.
carlonluca Jun 7, 2024
10bad81
Restore exception.
carlonluca Jun 7, 2024
2e1773a
Define CAML_NAME_SPACE before including caml/config.h header to avoid…
carlonluca Jun 8, 2024
71870fc
Use unsafe functions to improve performance.
carlonluca Jun 8, 2024
cc8d93d
Sync with upstream.
carlonluca Jun 22, 2024
be396bd
Sync with upstream.
carlonluca Jun 27, 2024
be98e72
Sync with upstream.
carlonluca Jun 27, 2024
2655cb5
Sync with upstream.
carlonluca Jun 28, 2024
0168c29
Sync with upstream.
carlonluca Jun 28, 2024
be7ea25
Fix typo.
carlonluca Jun 28, 2024
687e04b
Fix build.
carlonluca Jun 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions config/configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -690,10 +690,6 @@ if test "$OCAMLVERSION" \< "$MINIMUM_OCAML"; then
exit 1
fi

if test ! "$OCAMLVERSION" \< "4.03.0"; then
OCAMLC="$OCAMLC -unsafe-string"
fi

if test "$OCAMLOPT" = "no"; then
TARGET_TYPE=byte
OCAMLLIB_EXT=cma
Expand All @@ -707,11 +703,6 @@ else
echo "******** Expected ocamlopt version $OCAMLVERSION , but got $OCAMLOPTVERSION *********" 1>&2;
echo "******* Check http://ocaml.org/ ********" 1>&2;
exit 1; }

if test ! "$OCAMLVERSION" \< "4.03.0"; then
OCAMLOPT="$OCAMLOPT -unsafe-string"
fi

fi

echo "-------------------------------------------"
Expand Down
2 changes: 1 addition & 1 deletion src/config/unix/os_stubs_c.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ int64_t os_getfdsize(OS_FD fd)

*******************************************************************/

int64_t os_getfilesize(char *path)
int64_t os_getfilesize(const char *path)
{
struct stat buf;

Expand Down
4 changes: 2 additions & 2 deletions src/daemon/common/commonComplexOptions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1156,9 +1156,9 @@ let backup_tar archive files =
t_devminor = 0;
t_prefix = "";
t_gnu = None;} in
let s = String.create size in
let s = Bytes.create size in
Pervasives.really_input ic s 0 size;
header, s) in
header, Bytes.unsafe_to_string s) in
Tar.output otar header s
with
| e ->
Expand Down
2 changes: 1 addition & 1 deletion src/daemon/common/commonDownloads.ml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ module Make(M: sig
in
let final_pos = Unix32.seek64 (file_fd file) d.download_pos
Unix.SEEK_SET in *)
Unix32.write (file_fd file) d.download_pos b.buf b.pos b.len;
Unix32.write_bytes (file_fd file) d.download_pos b.buf b.pos b.len;
(* end; *)
(* lprintf "DIFF %d/%d\n" nread b.len; *)
d.download_pos <- d.download_pos ++ (Int64.of_int b.len);
Expand Down
4 changes: 2 additions & 2 deletions src/daemon/common/commonFile.ml
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,7 @@ let recover_bytes file =
if pos = max then
iter_file_out file_pos segments
else
if s.[pos] = '\000' then
if Bytes.get s pos = '\000' then
iter_string_out file_pos (pos+1) max segments
else
let begin_pos = file_pos -- (Int64.of_int (max - pos)) in
Expand All @@ -995,7 +995,7 @@ let recover_bytes file =
if pos = max then
iter_file_in file_pos begin_pos segments
else
if s.[pos] = '\000' then
if Bytes.get s pos = '\000' then
let end_pos = file_pos -- (Int64.of_int (max - pos)) in
(* lprintf " 0 byte at %Ld\n" end_pos; *)
iter_string_out file_pos (pos+1) max
Expand Down
27 changes: 9 additions & 18 deletions src/daemon/common/commonMultimedia.ml
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ let input_int ic =
let i1 = input_int16 ic in
i0 lor (i1 lsl 16)

let input_string4 ic =
let s = String.create 4 in
really_input ic s 0 4;
s
let input_string4 ic = really_input_string ic 4

let print_string4 v s =
lprintf "%s :" v;
Expand Down Expand Up @@ -230,7 +227,7 @@ let rec page_seek ic s pos =
else begin
really_input ic s 0 4;
seek_in ic (pos_in ic - 3);
if s = "OggS"
if Misc.bytes_equal_string s "OggS"
then seek_in ic (pos_in ic + 3)
else page_seek ic s pos
end
Expand Down Expand Up @@ -278,12 +275,10 @@ let rec next_ogg_stream ic ogg_infos str stream_number =
lprintf "Stream Serial Number: %0.f\n" stream_number;
*)
seek_in ic (pos+24);
let content_type = String.create 1 in
really_input ic content_type 0 1;
let content_type = really_input_string ic 1 in
let content_type = int_of_char content_type.[0] in
seek_in ic (pos+25);
let stream_type = String.create 8 in
really_input ic stream_type 0 8;
let stream_type = really_input_string ic 8 in
let stream_type = normalize_stream_type stream_type content_type in
incr stream_number;
let pos = pos_in ic in
Expand All @@ -299,8 +294,7 @@ let rec next_ogg_stream ic ogg_infos str stream_number =
| OGG_THEORA_STREAM -> get_ogg_theora_info ic ogg_infos str stream_number

and get_ogg_video_info ic ogg_infos str sizeof_packet stream_number =
let s = String.create sizeof_packet in
really_input ic s 0 sizeof_packet;
let s = really_input_string ic sizeof_packet in
let codec = String.lowercase (String.sub s 0 4) in
let time_unit = read64 (String.sub s 8 8) in
let video_width =
Expand All @@ -326,8 +320,7 @@ and get_ogg_video_info ic ogg_infos str sizeof_packet stream_number =
next_ogg_stream ic ogg_infos str stream_number

and get_ogg_audio_info ic ogg_infos str sizeof_packet stream_number =
let s = String.create sizeof_packet in
really_input ic s 0 sizeof_packet;
let s = really_input_string ic sizeof_packet in
let codec = get_audio_codec (String.sub s 0 4) in
let sample_per_unit = read64 (String.sub s 16 8) in
let channels =
Expand Down Expand Up @@ -359,8 +352,7 @@ and get_ogg_audio_info ic ogg_infos str sizeof_packet stream_number =

and get_ogg_vorbis_info ic ogg_infos str stream_number =
seek_in ic (pos_in ic - 2); (* ogm sets 8 octets in the common header as vorbis uses 6 octects for 'vorbis' *)
let s = String.create 22 in
really_input ic s 0 22;
let s = really_input_string ic 22 in
let version = read32 (String.sub s 0 4) in
let audio_channels = int_of_char s.[4] in
let sample_rate = read32 (String.sub s 5 4) in
Expand Down Expand Up @@ -389,8 +381,7 @@ and get_ogg_vorbis_info ic ogg_infos str stream_number =

and get_ogg_theora_info ic ogg_infos str stream_number =
seek_in ic (pos_in ic - 2); (* ogm sets 8 octets in the common header as theora uses 6 octects for 'theora' *)
let s = String.create 34 in
really_input ic s 0 34;
let s = really_input_string ic 34 in
let vmaj = int_of_char s.[0] in
let vmin = int_of_char s.[1] in
let vrev = int_of_char s.[2] in
Expand Down Expand Up @@ -451,7 +442,7 @@ and get_ogg_index_info ic ogg_infos str stream_number =

let search_info_ogg ic =
let stream_number = ref 0 in
let str = String.create 4 in
let str = Bytes.create 4 in
let ogg_infos = ref [] in
(* make sure the current reading position is at the file beginning *)
seek_in ic 0;
Expand Down
20 changes: 10 additions & 10 deletions src/daemon/common/commonSwarming.ml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ and swarmer = {
mutable s_strategy : swarming_strategy;

mutable s_verified_bitmap : VerificationBitmap.t;
mutable s_priorities_bitmap : string;
mutable s_priorities_bitmap : bytes;
mutable s_priorities_intervals : (int64 * int) list;
(* beginning, priority *)
mutable s_disk_allocated : Bitv.t;
Expand Down Expand Up @@ -579,7 +579,7 @@ let dummy_swarmer = {
s_networks = [];
s_strategy = AdvancedStrategy;
s_verified_bitmap = VB.create 0 VB.State_missing;
s_priorities_bitmap = "";
s_priorities_bitmap = Bytes.empty;
s_priorities_intervals = [(zero, 1)];
s_disk_allocated = Bitv.create 0 false;
s_blocks = [||];
Expand Down Expand Up @@ -639,7 +639,7 @@ let priority_zero = Char.chr 0

let swarmer_recompute_priorities_bitmap s =
String.fill s.s_priorities_bitmap 0
(String.length s.s_priorities_bitmap) priority_zero;
(Bytes.length s.s_priorities_bitmap) priority_zero;
let mark interval_begin interval_end priority =
if interval_end > interval_begin && s.s_size >= interval_end && interval_begin >= 0L then
if priority = 0 then
Expand Down Expand Up @@ -704,7 +704,7 @@ let create_swarmer file_name file_size =
s_strategy = AdvancedStrategy;

s_verified_bitmap = VB.create nblocks VB.State_missing;
s_priorities_bitmap = String.make nblocks priority_zero;
s_priorities_bitmap = Bytes.make nblocks priority_zero;
s_priorities_intervals = [(zero, 1)]; (* JAVE init all prios to 1, thus all chunks will be downloaded as usual *)
s_disk_allocated = Bitv.create ndiskblocks false;
s_blocks = Array.make nblocks EmptyBlock ;
Expand Down Expand Up @@ -837,7 +837,7 @@ let split_blocks s chunk_size =

s.s_blocks <- Array.make nblocks EmptyBlock;
s.s_verified_bitmap <- VB.create nblocks VB.State_missing;
s.s_priorities_bitmap <- String.make nblocks priority_zero;
s.s_priorities_bitmap <- Bytes.make nblocks priority_zero;
s.s_block_pos <- Array.make nblocks zero;
s.s_availability <- Array.make nblocks 0; (* not preserved ? *)
s.s_nuploading <- Array.make nblocks 0; (* not preserved ? *)
Expand Down Expand Up @@ -2041,7 +2041,7 @@ let linear_select_blocks up =
up.up_npartial <- n-1;
let t = up.up_t in
let s = t.t_s in
if s.s_priorities_bitmap.[b] = priority_zero then iter_partial up else
if (Bytes.get s.s_priorities_bitmap b) = priority_zero then iter_partial up else
let chunk = t.t_chunk_of_block.(b) in
match s.s_blocks.(b) with
| CompleteBlock | VerifiedBlock ->
Expand All @@ -2067,7 +2067,7 @@ let linear_select_blocks up =
up.up_ncomplete <- n-1;
let t = up.up_t in
let s = t.t_s in
if s.s_priorities_bitmap.[b] = priority_zero then iter_complete up else
if (Bytes.get s.s_priorities_bitmap b) = priority_zero then iter_complete up else
let chunk = t.t_chunk_of_block.(b) in
match s.s_blocks.(b) with
| CompleteBlock | VerifiedBlock ->
Expand Down Expand Up @@ -2238,7 +2238,7 @@ let select_blocks up =
{
choice_num = n;
choice_block = b;
choice_user_priority = Char.code s.s_priorities_bitmap.[b];
choice_user_priority = Char.code (Bytes.get s.s_priorities_bitmap b);
choice_remaining = remaining;
choice_preallocated = is_fully_preallocated t block_begin block_end;
choice_unselected_remaining = unselected_remaining;
Expand Down Expand Up @@ -2387,7 +2387,7 @@ let select_blocks up =
Array2.subarray_fold_lefti (fun
((current_chunk_num, current_chunk_blocks_indexes,
best_choices, specimen) as acc) n b ->
if s.s_priorities_bitmap.[b] = priority_zero ||
if (Bytes.get s.s_priorities_bitmap b) = priority_zero ||
not (should_download_block s b) then acc
else
let chunk_num = t.t_chunk_of_block.(b) in
Expand Down Expand Up @@ -2733,7 +2733,7 @@ let find_range up range_size =
let block = up.up_complete_blocks.(i) in
if not (List.exists (fun b -> b.up_block.block_num = block
) up.up_blocks) then
if s.s_priorities_bitmap.[block] <> priority_zero &&
if (Bytes.get s.s_priorities_bitmap block) <> priority_zero &&
should_download_block s block then
let partial_found = match s.s_blocks.(block) with
| EmptyBlock -> true
Expand Down
20 changes: 10 additions & 10 deletions src/daemon/common/commonUploads.ml
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ let shared_tree = new_shared_dir ""

let md4_of_list md4s =
let len = List.length md4s in
let s = String.create (len * 16) in
let s = Bytes.create (len * 16) in
let rec iter list i =
match list with
[] -> ()
Expand All @@ -300,7 +300,7 @@ let md4_of_list md4s =
iter tail (i+16)
in
iter md4s 0;
Md4.string s
Md4.string @@ Bytes.unsafe_to_string s

let rec tiger_of_array array pos block =
if block = 1 then
Expand All @@ -312,11 +312,11 @@ let rec tiger_of_array array pos block =
else
let d1 = tiger_of_array array pos (block/2) in
let d2 = tiger_of_array array (pos+block/2) (block/2) in
let s = String.create (1 + Tiger.length * 2) in
let s = Bytes.create (1 + Tiger.length * 2) in
s.[0] <- '\001';
String.blit (TigerTree.direct_to_string d1) 0 s 1 Tiger.length;
String.blit (TigerTree.direct_to_string d2) 0 s (1+Tiger.length) Tiger.length;
let t = Tiger.string s in
let t = Tiger.string @@ Bytes.unsafe_to_string s in
let t = TigerTree.direct_of_string (Tiger.direct_to_string t) in
t

Expand Down Expand Up @@ -345,11 +345,11 @@ let rec tiger_pos2 nblocks =
pos, list

let tiger_node d1 d2 =
let s = String.create (1 + Tiger.length * 2) in
let s = Bytes.create (1 + Tiger.length * 2) in
s.[0] <- '\001';
String.blit (TigerTree.direct_to_string d1) 0 s 1 Tiger.length;
String.blit (TigerTree.direct_to_string d2) 0 s (1+Tiger.length) Tiger.length;
let t = Tiger.string s in
let t = Tiger.string @@ Bytes.unsafe_to_string s in
let t = TigerTree.direct_of_string (Tiger.direct_to_string t) in
t

Expand Down Expand Up @@ -386,12 +386,12 @@ let rec fill_tiger_tree s list =

let flatten_tiger_array array =
let len = Array.length array in
let s = String.create ( len * TigerTree.length) in
let s = Bytes.create ( len * TigerTree.length) in
for i = 0 to len - 1 do
String.blit (TigerTree.direct_to_string array.(i)) 0
s (i * TigerTree.length) TigerTree.length
done;
s
Bytes.unsafe_to_string s

let unflatten_tiger_array s =
let len = String.length s / TigerTree.length in
Expand Down Expand Up @@ -504,9 +504,9 @@ computation ??? *)
let file_size = Unix32.getsize64 fd in
let len64 = min 307200L file_size in
let len = Int64.to_int len64 in
let s = String.create len in
let s = Bytes.create len in
Unix32.read fd zero s 0 len;
Md5Ext.string s
Md5Ext.string @@ Bytes.unsafe_to_string s
with e ->
current_job := None;
raise e
Expand Down
2 changes: 1 addition & 1 deletion src/daemon/common/commonWeb.ml
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ let _ =
while true do
let nread = Unix.read pipe_out buffer 0 buffersize in
if nread = 0 then raise End_of_file;
Buffer.add_substring output buffer 0 nread
Buffer.add_subbytes output buffer 0 nread
done
with
| End_of_file -> ()
Expand Down
6 changes: 3 additions & 3 deletions src/daemon/common/giftDecoding.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ let gui_cut_messages f sock nread =
try
let rec iter pos len =
if len = 0 then raise Not_found;
if b.buf.[pos] = ';' && (
if Bytes.get b.buf pos = ';' && (
pos = b.pos ||
(pos > b.pos && b.buf.[pos-1] <> '\\')) then begin
(pos > b.pos && Bytes.get b.buf (pos-1) <> '\\')) then begin
let len = pos - b.pos+1 in
let s = String.sub b.buf b.pos len in
let s = Bytes.sub_string b.buf b.pos len in
buf_used b len;
f s;
iter b.pos b.len
Expand Down
4 changes: 2 additions & 2 deletions src/daemon/common/guiDecoding.ml
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ let gui_cut_messages f sock nread =
let b = buf sock in
try
while b.len >= 4 do
let msg_len = get_int b.buf b.pos in
let msg_len = get_int (Bytes.unsafe_to_string b.buf) b.pos in
if b.len >= 4 + msg_len then
begin
let s = String.sub b.buf (b.pos+4) msg_len in
let s = Bytes.sub_string b.buf (b.pos+4) msg_len in
buf_used b (msg_len + 4);
let opcode = get_int16 s 0 in
(f opcode s : unit)
Expand Down
6 changes: 3 additions & 3 deletions src/daemon/common/guiEncoding.ml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ let gui_send writer sock t =
Buffer.reset buf;
buf_int buf 0;
writer buf t;
let s = Buffer.contents buf in
let len = String.length s - 4 in
let s = Buffer.to_bytes buf in
let len = Bytes.length s - 4 in
str_int s 0 len;
write_string sock s;
write_bytes sock s
with UnsupportedGuiMessage -> ()

(***************
Expand Down
6 changes: 3 additions & 3 deletions src/daemon/driver/driverCommands.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1389,12 +1389,12 @@ let _ =
(* can't close pipe_out in the already forked+executed process... *)
let output = Buffer.create 1024 in
let buffersize = 1024 in
let buffer = String.create buffersize in
let buffer = Bytes.create buffersize in
(try
while true do
let nread = Unix.read pipe_out buffer 0 buffersize in
if nread = 0 then raise End_of_file;
Buffer.add_substring output buffer 0 nread
Buffer.add_subbytes output buffer 0 nread
done
with
| End_of_file -> ()
Expand Down Expand Up @@ -3897,7 +3897,7 @@ let _ =
let downloaded = CommonSwarming.get_swarmer_block_verified swarmer in
pr "\\<code\\>";
pr "priorities: ";
String.iter (fun c ->
Bytes.iter (fun c ->
let c = max 0 (min 9 (Char.code c)) in
let c = Char.chr (c + Char.code '0') in
Buffer.add_char buf c) prio;
Expand Down
Loading
Loading