123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105(** Functional maps with [int] keys. *)moduleIntMap=Map.Make(Base.Int)(** Functional sets of integers. *)moduleIntSet=Set.Make(Base.Int)(** Functional maps with [string] keys. *)moduleStrMap=Map.Make(String)(** Functional sets of strings. *)moduleStrSet=Set.Make(String)(** [get_safe_prefix p strings] returns a string starting with [p] and so
that there is no non-negative integer [k] such that [p ^ string_of_int k]
belongs to [strings]. *)letget_safe_prefix:string->StrSet.t->string=funheadset->lethead_len=String.lengthheadinletfsacc=lets_len=String.lengthsinifhead_len<=s_len&&String.equalhead(String.subs0head_len)thentryletcurr_int=int_of_string(String.subshead_len(s_len-1))inifacc<curr_intthencurr_intelseaccwithFailure_->accelseaccinletres=StrSet.foldfset(-1)inifres=-1thenheadelsehead^string_of_int(res+1)(** [time f x] times the application of [f] to [x], and returns the evaluation
time in seconds together with the result of the application. *)lettime:('a->'b)->'a->float*'b=funfx->lett=Sys.time()inletr=fxin(Sys.time()-.t,r)(** Exception raised by the [with_timeout] function on a timeout. *)exceptionTimeout(** [with_timeout nbs f x] computes [f x] with a timeout of [nbs] seconds. The
exception [Timeout] is raised if the computation takes too long, otherwise
everything goes the usual way. *)letwith_timeout:int->('a->'b)->'a->'b=funnbsfx->letsigalrm_handler=Sys.Signal_handle(fun_->raiseTimeout)inletold_behavior=Sys.signalSys.sigalrmsigalrm_handlerinletreset_sigalrm()=let_=Unix.alarm0inSys.set_signalSys.sigalrmold_behaviorintrylet_=Unix.alarmnbsinletres=fxinreset_sigalrm();reswithe->reset_sigalrm();raisee(** [input_lines ic] reads the input channel [ic] line by line and returns its
contents. The trailing newlines are removed in lines. The input channel is
not closed by the function. *)letinput_lines:in_channel->stringlist=funic->letlines=ref[]intrywhiletruedolines:=input_lineic::!linesdone;assertfalsewithEnd_of_file->List.rev!lines(** [run_process cmd] runs the command [cmd] and returns the list of the lines
that it printed to its standard output (if the command was successful). If
the command failed somehow, then [None] is returned. *)letrun_process:string->stringlistoption=funcmd->letoc,ic,ec=Unix.open_process_fullcmd(Unix.environment())inletres=input_linesocinmatchUnix.close_process_full(oc,ic,ec)with|Unix.WEXITED0->Someres|_->None(** [file_time fname] returns the modification time of file [fname]
represented as a [float]. [neg_infinity] is returned if the file does not
exist. *)letfile_time:string->float=funfname->ifSys.file_existsfnamethenUnix.((statfname).st_mtime)elseneg_infinity(** [more_recent source target] checks whether the [target] (produced from the
[source] file) should be produced again. This is the case when [source] is
more recent than [target]. *)letmore_recent:string->string->bool=funsourcetarget->file_timesource>file_timetarget(** [files f d] returns all the filenames in [d] and its sub-directories
recursively satisfying the function [f], assuming that [d] is a
directory. *)letfiles:(string->bool)->string->stringlist=funchk->letrecfilesaccdirs=matchdirswith|[]->acc|d::dirs->letf(fnames,dnames)s=lets=Filename.concatdsinifSys.is_directorysthen(fnames,s::dnames)elseifchksthen(s::fnames,dnames)else(fnames,dnames)inletacc,dirs=Array.fold_leftf(acc,dirs)(Sys.readdird)infilesaccdirsinfund->files[][d]