1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
(** String utilities *)
open Util
(** split a string according to char_sep predicate *)
let split_str char_sep str =
let len = String.length str in
if len = 0 then [] else
let rec skip_sep cur =
if cur >= len then cur else
if char_sep str.[cur] then skip_sep (succ cur)
else cur in
let rec split beg cur =
if cur >= len then
if beg = cur then []
else [String.sub str beg (len - beg)] else
if char_sep str.[cur] then
let nextw = skip_sep cur in
String.sub str beg (cur - beg) :: split nextw nextw
else split beg (succ cur) in
let wstart = skip_sep 0 in
split wstart wstart
let split_str_quoted char_sep str =
let len = String.length str in
if len = 0 then [] else
let cword = ref "" in
let rec skip_sep cur =
if cur >= len then cur else
if char_sep str.[cur] then skip_sep (succ cur)
else cur in
let rec close_quote cur =
if cur >= len then cur else
if str.[cur] = '"' then cur else begin
cword := !cword ^ String.make 1 str.[cur];
close_quote (succ cur)
end in
let rec split beg cur =
if cur >= len then
if beg = cur then [] else [!cword] else
if str.[cur] = '"' then
let endquote = close_quote (succ cur) in
split beg (succ endquote) else
if char_sep str.[cur] then
let nextw = skip_sep cur in
let word = !cword in
cword := "";
word :: split nextw nextw
else begin
cword := !cword ^ String.make 1 str.[cur];
split beg (succ cur)
end in
let wstart = skip_sep 0 in
split wstart wstart
let get_suffix s =
try
let dotpos = succ (String.rindex s '.') in
String.sub s dotpos (String.length s - dotpos)
with
| Not_found -> ""
let hex_to_dec c = match c with
| '0'..'9' -> int_of_char c - 48
| 'a'..'f' -> int_of_char c - 87
| 'A'..'F' -> int_of_char c - 55
| _ -> failwith "hex_to_dec"
let dec_to_hex i =
if i < 10 then char_of_int (i + 48)
else char_of_int (i + 55)
let hex_to_string s =
let len = String.length s / 2 in
String.init len @@ fun i ->
char_of_int ( 16 * (hex_to_dec s.[i + i]) + hex_to_dec s.[i + i + 1])
let gensym =
let cnter = ref 0 in
(fun n ->
incr cnter;
n ^ string_of_int !cnter)
let rem_trailing_sp s =
let l = String.length s in
let pos = ref (l - 1) in
while !pos >= 0 && List.mem s.[!pos] [' '; '\t'] do decr pos done;
if !pos = l - 1 then s
else String.sub s 0 (succ !pos)
let catenate_sep = String.concat
(** Filters CRLF:
- CR -> LF
- CRLF -> LF
- LF -> LF
We do this on successive chunks of a stream, so we need to consider
the case when the chunk finishes on CR.
Assume len > 0
*)
let norm_crlf lastwascr buf offs len =
let rpos = ref offs
and wpos = ref 0
and dest = Bytes.create (len + 1)
and limit = offs + len - 1
and lastiscr = ref false in
if lastwascr then
if buf.[!rpos] = '\n' then begin
dest << !wpos & '\n';
incr rpos; incr wpos
end else begin
dest << !wpos & '\n'; incr wpos
end;
while !rpos < limit do
match buf.[!rpos] with
| '\n' -> dest << !wpos & '\n'; incr rpos; incr wpos
| '\r' ->
if buf.[!rpos + 1] = '\n' then begin
dest << !wpos & '\n'; rpos := !rpos + 2; incr wpos
end else begin
dest << !wpos & '\n'; incr rpos; incr wpos end
| c -> dest << !wpos & c; incr rpos; incr wpos
done;
begin match buf.[offs+len-1] with
| '\n' -> dest << !wpos & '\n'; incr wpos
| '\r' -> lastiscr := true
| c -> dest << !wpos & c; incr wpos
end;
Bytes.sub_string dest 0 !wpos, !lastiscr
let hexchar c =
let i = int_of_char c in
String.init 3 @@ function
| 0 -> '%'
| 1 -> dec_to_hex (i / 16)
| 2 -> dec_to_hex (i mod 16)
| _ -> assert false