123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187(*
* Copyright (c) 2016 Thomas Refis <trefis@janestreet.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openStdLabelsopenOr_errortypedirectory=Fpath.ttypefile=Fpath.tmoduleFile=structtypet=fileletdirname=Fpath.parentletbasename=Fpath.baseletappend=Fpath.appendletset_extep=Fpath.set_exteplethas_extep=Fpath.has_extepletget_exte=Fpath.get_exteletcreate~directory~name=matchFpath.of_stringnamewith|Result.Error(`Msge)->invalid_arg("Odoc.Fs.File.create: "^e)|Result.Okpsuf->Fpath.(normalize@@(directory//psuf))letto_string=Fpath.to_stringletsegs=Fpath.segsletof_strings=matchFpath.of_stringswith|Result.Error(`Msge)->invalid_arg("Odoc.Fs.File.of_string: "^e)|Result.Okp->pletreadfile=letwith_ic~closeicf=letcloseic=trycloseicwithSys_error_->()inmatchficwith|v->closeic;v|exceptione->closeic;raiseeinletinput_one_shotlenic=letbuf=Bytes.createleninreally_inputicbuf0len;close_inic;Result.Ok(Bytes.unsafe_to_stringbuf)inletinput_streamfileic=letbsize=65536(* IO_BUFFER_SIZE *)inletbuf=Buffer.createbsizeinletrecloop()=matchBuffer.add_channelbuficbsizewith|()->loop()|exceptionEnd_of_file->Result.Ok(Buffer.contentsbuf)|exceptionFailure_->Result.Error(`Msg(Printf.sprintf"%s: input too large"file))inloop()intryletfile=Fpath.to_stringfileinletis_dash=file="-"inletic=ifis_dashthenstdinelseopen_in_binfileinletcloseic=ifis_dashthen()elseclose_inicinwith_ic~closeic@@funic->matchin_channel_lengthicwith|0(* e.g. stdin or /dev/stdin *)->input_streamfileic|lenwhenlen<=Sys.max_string_length->input_one_shotlenic|len->leterr=Printf.sprintf"%s: file too large (%d bytes)"fileleninResult.Error(`Msgerr)withSys_errore->Result.Error(`Msge)letexistsfile=Sys.file_exists(Fpath.to_stringfile)moduleTable=Hashtbl.Make(structtypenonrect=tletequal=Fpath.equallethash=Hashtbl.hashend)endmoduleDirectory=structtypet=directoryletdirname=Fpath.parentletbasename=Fpath.baseletappend=Fpath.appendletmake_pathpname=matchFpath.of_stringnamewith|Result.Error_ase->e|Result.Okpsuf->Result.OkFpath.(normalize@@to_dir_path@@(p//psuf))letreach_from~dirpath=matchmake_pathdirpathwith|Result.Error(`Msge)->invalid_arg("Odoc.Fs.Directory.create: "^e)|Result.Okpath->letpstr=Fpath.to_stringpathinifSys.file_existspstr&¬(Sys.is_directorypstr)theninvalid_arg"Odoc.Fs.Directory.create: not a directory";pathletmkdir_pdir=letmkdird=tryUnix.mkdir(Fpath.to_stringd)0o755with|Unix.Unix_error(Unix.EEXIST,_,_)->()|exn->raiseexninletrecdirs_to_createpacc=ifSys.file_exists(Fpath.to_stringp)thenaccelsedirs_to_create(Fpath.parentp)(p::acc)inList.iter(dirs_to_createdir[])~f:mkdirletto_string=Fpath.to_stringletof_strings=matchFpath.of_stringswith|Result.Error(`Msge)->invalid_arg("Odoc.Fs.Directory.of_string: "^e)|Result.Okp->Fpath.to_dir_pathpletfold_files_rec?(ext="")faccd=letfold_non_dirsextfaccfiles=letis_dird=trySys.is_directorydwithSys_error_->falseinlethas_extextfile=Filename.check_suffixfileextinletdirs,files=List.partition~f:is_dirfilesinletfiles=List.find_all~f:(has_extext)filesinletfaccfn=facc(Fpath.vfn)in(List.fold_left~f~init:accfiles,dirs)inletrecloopextfacc=function|(d::ds)::up->letrdird=tryArray.to_list(Sys.readdird)withSys_error_->[]inletfiles=List.rev(List.rev_map~f:(Filename.concatd)(rdird))inletacc,dirs=fold_non_dirsextfaccfilesinloopextfacc(dirs::ds::up)|[]::up->loopextfaccup|[]->accinloopextfacc[[Fpath.to_stringd]]exceptionStop_iterofmsgletfold_files_rec_result?extfaccd=letfaccfn=matchfaccfnwithOkacc->acc|Errore->raise(Stop_itere)intryOk(fold_files_rec?extfaccd)withStop_iter(`Msg_ase)->ErroremoduleTable=Hashtbl.Make(structtypenonrect=tletequal=Fpath.equallethash=Hashtbl.hashend)end