On my Unix-based Mac OS, I have a command mdls -name kMDItemNumberOfPages -raw to compute the number of pages inside a pdf.
To get that integer inside an Ocaml program, I proceed as follows :
I create a temporary file with Sys.command "touch temp.txt"
Store the result in the temporary file with Sys.command "mdls -name kMDItemNumberOfPages -raw mypdf.pdf > temp.txt
Using open_in and the Buffer module, read the contents of temp.txt, then call int_of_string on that content.
Delete the temporary file with Sys.command "rm temp.txt"
This is perhaps overkill ? Perhaps one can do it using channels only and no temporary files ?
If I understand correctly, let my_channel=Unix.open_process_in "some_cmd" ;; stores the result of some_cmd in a value my_channel of type in_channel. How do I retrieve the result stored in my_channel after that ?
I tried it this morning (yesterday I just read the linked manual sections) and surprisingly it doesnβt work at all in my case. My call to Unix.open_process_in not only raises a Unix.Unix_error(Unix.EINTR, "select", "") exception, but also makes my utop toplevel quit suddenly.
Iβm using utop 2.2.0 and OCaml 4.07.0 if that matters.
UPDATE : your solution works fine if I use it outside utop, in a normal ocaml toplevel. Iβm still interested in an utop-compatible solution, however.
UPDATE 2 : I found out that utop crashes if I call Unix.open_process_in directly (by doing let chan = Unix.open_process_in cmd;;, say), but not if I wrap the call in a let (...) in ; thus utop accepts the following snippet :
let reasonable_size = 100;;
let number_of_pages_in_pdf_file pdfname =
let cmd="mdls -name kMDItemNumberOfPages -raw "^pdfname in
let chan = Unix.open_process_in cmd in
let buf = Bytes.create reasonable_size in
let final_size = input chan buf 0 reasonable_size in
let _ = Unix.close_process_in chan in
int_of_string(Bytes.sub_string buf 0 final_size) ;;
Iβm not using utop so I canβt exactly tell you. But thatβs precisely one of the reasons I donβt, its implementation fiddles with and embeds too much in your environment (notably lwt).
So I prefer to stick to ocaml in general (with rlwrap or down).
This is my βscreenshotβ. You may want to give the new version a try.
βββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬ββ
β Welcome to utop version 2.6.0 (using OCaml version 4.08.1)! β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Findlib has been successfully loaded. Additional directives:
#require "package";; to load a package
#list;; to list the available packages
#camlp4o;; to load camlp4 (standard syntax)
#camlp4r;; to load camlp4 (revised syntax)
#predicates "p,q,...";; to set these predicates
Topfind.reset();; to force that packages will be reloaded
#thread;; to enable threads
Type #utop_help for help about using utop.
β( 11:02:58 )β< command 0 >βββββββββββββββββββββββββ{ counter: 0 }β
utop # let cin= Unix.open_process_in "echo 20";;
val cin : in_channel = <abstr>
β( 11:02:59 )β< command 1 >βββββββββββββββββββββββββ{ counter: 0 }β
utop # cin |> input_line |> String.trim |> int_of_string;;
- : int = 20
β( 11:03:03 )β< command 2 >βββββββββββββββββββββββββ{ counter: 0 }β
utop # close_in cin;;
- : unit = ()
β( 11:03:05 )β< command 3 >βββββββββββββββββββββββββ{ counter: 0 }β
utop #
ββββββββββββββββ¬βββββββββββββββ¬ββββββββββββββββ¬ββββββ¬βββββ¬ββββ¬βββββ
βAfl_instrumentβAlias_analysisβAllocated_constβAnnotβArchβArgβArg_β
ββββββββββββββββ΄βββββββββββββββ΄ββββββββββββββββ΄ββββββ΄βββββ΄ββββ΄βββββ