9 type platform
= | Punknown
| Plinux
| Pmacos
| Pbsd
;;
11 let asciilower = let auld = Char.code 'A'
- Char.code '
a'
in
13 | ('A'
..'Z'
) as c
-> Char.code c
- auld |> Char.chr
17 let tempfailureretry f
a =
19 try f
a with Unix.Unix_error
(Unix.EINTR
, _
, _
) -> g ()
23 external measurestr
: int -> string -> float = "ml_measure_string";;
24 external cloexec
: Unix.file_descr
-> unit = "ml_cloexec";;
25 external hasdata
: Unix.file_descr
-> bool = "ml_hasdata";;
26 external toutf8
: int -> string = "ml_keysymtoutf8";;
27 external mbtoutf8
: string -> string = "ml_mbtoutf8";;
28 external spawn
: string -> (Unix.file_descr
* int) list
-> int = "ml_spawn";;
29 external platform
: unit -> (platform
* string array
) = "ml_platform";;
31 let now = Unix.gettimeofday
;;
32 let platform, uname
= platform ();;
33 let dolog fmt
= Format.ksprintf prerr_endline fmt
;;
36 | Unix.Unix_error
(e
, s, a) ->
37 Printf.sprintf
"%s(%s) : %s (%d)" s a (Unix.error_message e
) (Obj.magic e
)
38 | exn
-> Printexc.to_string exn
41 let error fmt
= Printf.kprintf
(fun s -> failwith
s) fmt
;;
43 module IntSet
= Set.Make
(struct type t
= int let compare = (-) end);;
45 let emptystr s = String.length
s = 0;;
46 let nonemptystr s = String.length
s > 0;;
47 let bound v minv maxv
= max minv
(min maxv v
);;
50 type t
= private string
51 val of_string
: string -> t
52 val to_string
: t
-> string
60 let (~
<) = Opaque.of_string;;
61 let (~
>) = Opaque.to_string;;
63 let int_of_string_with_suffix s =
64 let l = String.length
s in
70 | 'k'
| 'K'
-> String.sub
s 0 p, 10
71 | 'm'
| 'M'
-> String.sub
s 0 p, 20
72 | '
g'
| 'G'
-> String.sub
s 0 p, 30
76 let n = int_of_string
s1 in
77 let m = n lsl shift
in
79 then error "value too large"
83 let string_with_suffix_of_int n =
84 let rec find = function
85 | [] -> Printf.sprintf
"%#d" n
86 | (shift
, suffix
) :: rest
->
87 if (n land ((1 lsl shift
) - 1)) = 0
88 then Printf.sprintf
"%#d%c" (n lsr shift
) suffix
91 if n = 0 then "0" else find [(30, 'G'
); (20, 'M'
); (10, 'K'
)]
94 let color_of_string s =
95 Scanf.sscanf
s "%d/%d/%d" (fun r
g b ->
96 (float r
/. 255.0, float g /. 255.0, float b /. 255.0)
100 let rgba_of_string s =
102 s "%d/%d/%d/%d" (fun r
g b a ->
103 (float r
/. 255.0, float g /. 255.0, float b /. 255.0, float a /. 255.0)
107 let color_to_string (r
, g, b) =
108 let r = truncate
(r *. 255.0)
109 and g = truncate
(g *. 255.0)
110 and b = truncate
(b *. 255.0) in
111 Printf.sprintf
"%d/%d/%d" r g b
114 let rgba_to_string (r, g, b, a) =
115 let r = truncate
(r *. 255.0)
116 and g = truncate
(g *. 255.0)
117 and b = truncate
(b *. 255.0)
118 and a = truncate
(a *. 255.0) in
119 Printf.sprintf
"%d/%d/%d/%d" r g b a
123 if Filename.is_relative path
125 let cwd = Sys.getcwd
() in
126 if Filename.is_implicit path
127 then Filename.concat
cwd path
128 else Filename.concat
cwd (Filename.basename path
)
133 let index s c
= try String.index s c
with Not_found
-> -1;;
135 try tempfailureretry Unix.close fd
136 with exn
-> f
@@ exntos exn
140 let getoptdef def
= function
145 let getenvdef name def
=
146 match Sys.getenv name
with
148 | exception Not_found
-> def
152 let crlf = Str.regexp
"[\r\n]";;
153 let percent = Str.regexp
"%s";;
154 let whitespace = Str.regexp
"[ \t]";;
158 let b = Buffer.create
(String.length
s + 1) in
159 Buffer.add_string
b s;
164 let btod b = if b then 1 else 0;;
166 let splitatchar s c
= let open String
in
168 | pos
-> sub
s 0 pos
, sub
s (pos
+1) (length
s - pos
- 1)
169 | exception Not_found
-> s, E.s
172 let boundastep h step
=
174 then bound step ~
-h
0
178 let withoutlastutf8 s =
179 let len = String.length
s in
187 let b = Char.code
s.[pos
] in
188 if b land 0b11000000 = 0b11000000
193 if Char.code
s.[len-1] land 0x80 = 0
197 String.sub
s 0 first;
202 let b = Buffer.create
l in
203 let s = Bytes.create
l in
205 let n = tempfailureretry (Unix.read fd
s 0) l in
207 then Buffer.contents
b
209 Buffer.add_subbytes
b s 0 n;
216 let filecontents path
=
217 let fd = Unix.openfile path
[Unix.O_RDONLY
] 0o0
in
218 match fdcontents fd with
220 error "failed to read contents of %s: %s" path
@@ exntos exn
222 Ne.clo fd @@ error "failed to close descriptor for %s: %s" path
;
226 let getcmdoutput errfun cmd
=
227 let reperror fmt
= Printf.kprintf errfun fmt
in
228 let clofail s e
= error "failed to close %s: %s" s e
in
229 match Unix.pipe
() with
231 reperror "pipe failed: %s" @@ exntos exn
;
234 match spawn cmd
[r, -1; w
, 1] with
236 reperror "failed to execute %S: %s" cmd
@@ exntos exn
;
239 Ne.clo w
@@ clofail "write end of the pipe";
241 match Unix.waitpid
[] pid
with
243 reperror "waitpid on %S %d failed: %s" cmd pid
@@ exntos exn
;
245 | _pid
, Unix.WEXITED
0 ->
247 match fdcontents r with
249 reperror "failed to read output of %S: %s" cmd
@@ exntos exn
;
252 let l = String.length
s in
253 if l > 0 && s.[l-1] = '
\n'
254 then String.sub
s 0 (l-1)
257 | _pid
, Unix.WEXITED
n ->
258 reperror "%S exited with error code %d" cmd
n;
260 | _pid
, Unix.WSIGNALED
n ->
261 reperror "%S was killed with signal %d" cmd
n;
263 | _pid
, Unix.WSTOPPED
n ->
264 reperror "%S was stopped by signal %d" cmd
n;
267 Ne.clo r @@ clofail "read end of the pipe";
272 let re = Str.regexp
{|.*\
(\
(https?\
|ftp\
|mailto\
|file\
)://[^
]+\
).*|} in
273 fun s -> if Str.string_match
re s 0
274 then Str.matched_group
1 s
278 let substratis s pos subs
=
279 let subslen = String.length subs
in
280 if String.length
s - pos
>= subslen
282 let rec cmp i
= i
= subslen || (s.[pos
+i
] = subs
.[i
]) && cmp (i
+1)
287 let w8 s pos i
= Bytes.set
s pos
(Char.chr
(i
land 0xff));;
288 let r8 s pos
= Char.code
(Bytes.get
s pos
);;
292 w8 s (pos
+1) (i
lsr 8)
297 w16 s (pos
+2) (i
lsr 16)
301 let rb pos1
= Char.code
(Bytes.get
s (pos
+ pos1
)) in
302 (rb 0) lor ((rb 1) lsl 8)
307 i - ((i land 0x8000) lsl 1)
311 let rb pos1
= Char.code
(Bytes.get
s (pos
+ pos1
)) in
312 let l = (rb 0) lor ((rb 1) lsl 8)
313 and u
= (rb 2) lor ((rb 3) lsl 8) in
318 if Sys.word_size
> 32
320 let rb pos1
= Char.code
(Bytes.get
s (pos
+ pos1
)) in
321 let v0 = rb 0 and v1
= rb 1 and v2
= rb 2 and v3
= rb 3 in
322 let v = v0 lor (v1
lsl 8) lor (v2
lsl 16) lor (v3
lsl 24) in
325 else (v - (1 lsl 32))
326 else fun _ _
-> error "r32s: not implemented for word_size <= 32"
329 let vlogf = ref ignore
;;
330 let vlog fmt
= Printf.kprintf
!vlogf fmt
;;
332 let pipef ?
(closew
=true) cap f cmd
=
333 match Unix.pipe
() with
334 | exception exn
-> dolog "%s cannot create pipe: %S" cap
@@ exntos exn
336 begin match spawn cmd
[r, 0; w
, -1] with
337 | exception exn
-> dolog "%s: cannot execute %S: %s" cap cmd
@@ exntos exn
340 Ne.clo r (dolog "%s failed to close r: %s" cap
);
341 if closew
then Ne.clo w
(dolog "%s failed to close w: %s" cap
);
344 let selstring selcmd
s =
345 pipef "selstring" (fun w
->
347 let l = String.length
s in
348 let bytes = Bytes.unsafe_of_string
s in
349 let n = tempfailureretry (Unix.write w
bytes 0) l in
351 then dolog "failed to write %d characters to sel pipe, wrote %d" l n;
352 with exn
-> dolog "failed to write to sel pipe: %s" @@ exntos exn