123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605(******************************************************************************)(* ocaml-fileutils: files and filenames common operations *)(* *)(* Copyright (C) 2003-2014, Sylvain Le Gall *)(* *)(* This library is free software; you can redistribute it and/or modify it *)(* under the terms of the GNU Lesser General Public License as published by *)(* the Free Software Foundation; either version 2.1 of the License, or (at *)(* your option) any later version, with the OCaml static compilation *)(* exception. *)(* *)(* This library is distributed in the hope that it will be useful, but *)(* WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file *)(* COPYING for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this library; if not, write to the Free Software Foundation, *)(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)(******************************************************************************)openFilePath_typeexceptionBaseFilenameRelativeoffilenameexceptionUnrecognizedOSofstringexceptionEmptyFilenameexceptionNoExtensionoffilenameexceptionInvalidFilenameoffilenamemoduletypeOS_SPECIFICATION=sigvaldir_writer:(filename_partlist)->filenamevaldir_reader:filename->(filename_partlist)valpath_writer:(filenamelist)->stringvalpath_reader:string->(filenamelist)valfast_concat:filename->filename->filenamevalfast_basename:filename->filenamevalfast_dirname:filename->filenamevalfast_is_relative:filename->boolvalfast_is_current:filename->boolvalfast_is_parent:filename->boolendmoduletypePATH_SPECIFICATION=sigtypefilenametypeextensionvalstring_of_filename:filename->stringvalfilename_of_string:string->filenamevalextension_of_string:string->extensionvalstring_of_extension:extension->stringvalmake_filename:stringlist->filenamevalis_subdir:filename->filename->boolvalis_updir:filename->filename->boolvalcompare:filename->filename->intvalbasename:filename->filenamevaldirname:filename->filenamevalconcat:filename->filename->filenamevalreduce:?no_symlink:bool->filename->filenamevalmake_absolute:filename->filename->filenamevalmake_relative:filename->filename->filenamevalreparent:filename->filename->filename->filenamevalidentity:filename->filenamevalis_valid:filename->boolvalis_relative:filename->boolvalis_current:filename->boolvalis_parent:filename->boolvalchop_extension:filename->filenamevalget_extension:filename->extensionvalcheck_extension:filename->extension->boolvaladd_extension:filename->extension->filenamevalreplace_extension:filename->extension->filenamevalstring_of_path:filenamelist->stringvalpath_of_string:string->filenamelistvalcurrent_dir:filenamevalparent_dir:filenameendmoduletypePATH_STRING_SPECIFICATION=sigmoduleAbstract:PATH_SPECIFICATIONincludePATH_SPECIFICATIONwithtypefilename=stringandtypeextension=stringend(* Convert an OS_SPECIFICATION to PATH_SPECIFICATION *)moduleGenericPath=functor(OsOperation:OS_SPECIFICATION)->structtypefilename=FilePath_type.filename_partlisttypeextension=FilePath_type.extension(* Filename_from_string *)letfilename_of_stringstr=tryOsOperation.dir_readerstrwithParsing.Parse_error->raise(InvalidFilenamestr)(* String_from_filename *)letstring_of_filenamepath=OsOperation.dir_writerpath(* Reduce *)letreduce?(no_symlink=false)path=(* TODO: not tail recursive ! *)letrecreduce_auxlst=matchlstwith|ParentDir::tlwhenno_symlink->beginmatchreduce_auxtlwith|Roots::tl->Roots::tl|ParentDir::tl->ParentDir::ParentDir::tl|[]->ParentDir::tl|_::tl->tlend|ParentDir::tl->ParentDir::(reduce_auxtl)|CurrentDir_::tl|Component""::tl->(reduce_auxtl)|Components::tl->Components::(reduce_auxtl)|Roots::tl->Roots::(reduce_auxtl)|[]->[]inletrev_path=List.revpathinmatchreduce_auxrev_pathwith|[]whenno_symlink=false->(* assert
* ( List.for_all ( function | Component ""
* | CurrentDir _ -> true | _ -> false ) rev_path ) *)(try(* use last CurrentDir _ *)[List.find(function|CurrentDir_->true|_->false)rev_path]with|Not_found->[])(* Only Component "" *)|l->List.revl(* Compare, subdir, updir *)typefilename_relation=SubDir|UpDir|Equal|NoRelationofintletrelation_of_filenamepath1path2=letrecrelation_of_filename_auxpath1path2=match(path1,path2)with([],[])->Equal|(hd1::tl1,hd2::tl2)->ifhd1=hd2thenrelation_of_filename_auxtl1tl2elsebeginNoRelation(String.compare(string_of_filename[hd1])(string_of_filename[hd2]))end|(_,[])->SubDir|([],_)->UpDirinrelation_of_filename_auxpath1path2letis_subdirpath1path2=matchrelation_of_filenamepath1path2withSubDir->true|_->falseletis_updirpath1path2=matchrelation_of_filenamepath1path2withUpDir->true|_->falseletcomparepath1path2=matchrelation_of_filenamepath1path2withSubDir->-1|UpDir->1|Equal->0|NoRelationi->i(* Concat *)letconcatlst_path1lst_path2=reduce(matchlst_path2with|CurrentDirShort::tl_path2->lst_path1@tl_path2|_->lst_path1@lst_path2)(* Is_relative *)letis_relativelst_path=matchlst_pathwith(Root_)::_->false|_->true(* Is_valid *)letis_valid_=(* As we are manipulating abstract filename,
and that it has been parsed, we are
sure that all is correct *)trueletis_currentpath=matchpathwith[(CurrentDir_)]->true|_->falseletis_parentpath=matchpathwith[ParentDir]->true|_->false(* Basename *)letbasenamepath=matchList.revpathwith|hd::_->[hd]|[]->raiseEmptyFilename(* Dirname *)letdirnamepath=matchList.revpathwith|_::tl->List.revtl|[]->raiseEmptyFilename(* Extension manipulation *)letwrap_extensionfpath=matchbasenamepathwith|[Componentfn]->ffn|_->raise(NoExtension(string_of_filenamepath))letcheck_extensionpathext=wrap_extension(funfn->ExtensionPath.checkfnext)pathletget_extensionpath=wrap_extension(funfn->ExtensionPath.getfn)pathletchop_extensionpath=wrap_extension(funfn->concat(dirnamepath)[Component(ExtensionPath.chopfn)])pathletadd_extensionpathext=wrap_extension(funfn->concat(dirnamepath)[Component(ExtensionPath.addfnext)])pathletreplace_extensionpathext=wrap_extension(funfn->concat(dirnamepath)[Component(ExtensionPath.replacefnext)])pathletextension_of_stringx=xletstring_of_extensionx=x(* Make_asbolute *)letmake_absolutepath_basepath_path=reduce(ifis_relativepath_basethenraise(BaseFilenameRelative(string_of_filenamepath_base))elseifis_relativepath_paththenpath_base@path_pathelsepath_path)(* Make_relative *)letmake_relativepath_basepath_path=letrecmake_relative_auxlst_baselst_path=match(lst_base,lst_path)withx::tl_base,a::tl_pathwhenx=a->make_relative_auxtl_basetl_path|_,_->letback_to_base=List.rev_map(fun_->ParentDir)lst_baseinback_to_base@lst_pathinreduce(ifis_relativepath_basethenraise(BaseFilenameRelative(string_of_filenamepath_base))elseifis_relativepath_paththenpath_pathelsemake_relative_auxpath_basepath_path)(* Make_filename *)letmake_filenamelst_path=reduce(List.flatten(List.mapfilename_of_stringlst_path))(* Reparent *)letreparentpath_srcpath_dstpath=letpath_relative=make_relativepath_srcpathinmake_absolutepath_dstpath_relative(* Identity *)letidentitypath=path(* Manipulate path like variable *)letstring_of_pathlst=OsOperation.path_writer(List.mapstring_of_filenamelst)letpath_of_stringstr=List.mapfilename_of_string(OsOperation.path_readerstr)(* Generic filename component *)letcurrent_dir=[CurrentDirLong]letparent_dir=[ParentDir]end(* Convert an OS_SPECIFICATION to PATH_STRING_SPECIFICATION *)moduleGenericStringPath=functor(OsOperation:OS_SPECIFICATION)->structmoduleAbstract=GenericPath(OsOperation)typefilename=stringtypeextension=stringletstring_of_filenamepath=pathletfilename_of_stringpath=pathletstring_of_extensionext=extletextension_of_stringstr=strletf2s=Abstract.string_of_filenamelets2f=Abstract.filename_of_stringlete2s=Abstract.string_of_extensionlets2e=Abstract.extension_of_stringletis_subdirpath1path2=Abstract.is_subdir(s2fpath1)(s2fpath2)letis_updirpath1path2=Abstract.is_updir(s2fpath1)(s2fpath2)letcomparepath1path2=Abstract.compare(s2fpath1)(s2fpath2)letbasenamepath=tryOsOperation.fast_basenamepathwithCommonPath.CannotHandleFast->f2s(Abstract.basename(s2fpath))letdirnamepath=tryOsOperation.fast_dirnamepathwithCommonPath.CannotHandleFast->f2s(Abstract.dirname(s2fpath))letconcatpath1path2=tryOsOperation.fast_concatpath1path2withCommonPath.CannotHandleFast->f2s(Abstract.concat(s2fpath1)(s2fpath2))letmake_filenamepath_lst=f2s(Abstract.make_filenamepath_lst)letreduce?no_symlinkpath=f2s(Abstract.reduce?no_symlink(s2fpath))letmake_absolutebase_pathpath=f2s(Abstract.make_absolute(s2fbase_path)(s2fpath))letmake_relativebase_pathpath=f2s(Abstract.make_relative(s2fbase_path)(s2fpath))letreparentpath_srcpath_dstpath=f2s(Abstract.reparent(s2fpath_src)(s2fpath_dst)(s2fpath))letidentitypath=f2s(Abstract.identity(s2fpath))letis_validpath=tryAbstract.is_valid(s2fpath)withInvalidFilename_->falseletis_relativepath=tryOsOperation.fast_is_relativepathwithCommonPath.CannotHandleFast->Abstract.is_relative(s2fpath)letis_currentpath=tryOsOperation.fast_is_currentpathwithCommonPath.CannotHandleFast->Abstract.is_current(s2fpath)letis_parentpath=tryOsOperation.fast_is_parentpathwithCommonPath.CannotHandleFast->Abstract.is_parent(s2fpath)letwrap_extensionfpath=letbfn=OsOperation.fast_basenamepathinifOsOperation.fast_is_parentbfn||OsOperation.fast_is_currentbfn||not(OsOperation.fast_is_relativebfn)thenraise(NoExtensionpath)elsefbfnletchop_extensionpath=trywrap_extension(funfn->OsOperation.fast_concat(OsOperation.fast_dirnamepath)(ExtensionPath.chopfn))pathwithCommonPath.CannotHandleFast->f2s(Abstract.chop_extension(s2fpath))letget_extensionpath=trywrap_extension(funfn->ExtensionPath.getfn)pathwithCommonPath.CannotHandleFast->e2s(Abstract.get_extension(s2fpath))letcheck_extensionpathext=trywrap_extension(funfn->ExtensionPath.checkfnext)pathwithCommonPath.CannotHandleFast->Abstract.check_extension(s2fpath)(s2eext)letadd_extensionpathext=trywrap_extension(funfn->OsOperation.fast_concat(OsOperation.fast_dirnamepath)(ExtensionPath.addfnext))pathwithCommonPath.CannotHandleFast->f2s(Abstract.add_extension(s2fpath)(s2eext))letreplace_extensionpathext=trywrap_extension(funfn->OsOperation.fast_concat(OsOperation.fast_dirnamepath)(ExtensionPath.replacefnext))pathwithCommonPath.CannotHandleFast->f2s(Abstract.replace_extension(s2fpath)(s2eext))letstring_of_pathpath_lst=Abstract.string_of_path(List.maps2fpath_lst)letpath_of_stringstr=List.mapf2s(Abstract.path_of_stringstr)letcurrent_dir=f2s(Abstract.current_dir)letparent_dir=f2s(Abstract.parent_dir)endmoduleDefaultPath=GenericStringPath(structletos_dependunixwin32=matchSys.os_typewith"Unix"|"Cygwin"->unix|"Win32"->win32|s->raise(UnrecognizedOSs)letdir_writer=os_dependUnixPath.dir_writerWin32Path.dir_writerletdir_reader=os_dependUnixPath.dir_readerWin32Path.dir_readerletpath_writer=os_dependUnixPath.path_writerWin32Path.path_writerletpath_reader=os_dependUnixPath.path_readerWin32Path.path_readerletfast_concat=os_dependUnixPath.fast_concatWin32Path.fast_concatletfast_basename=os_dependUnixPath.fast_basenameWin32Path.fast_basenameletfast_dirname=os_dependUnixPath.fast_dirnameWin32Path.fast_dirnameletfast_is_relative=os_dependUnixPath.fast_is_relativeWin32Path.fast_is_relativeletfast_is_current=os_dependUnixPath.fast_is_currentWin32Path.fast_is_currentletfast_is_parent=os_dependUnixPath.fast_is_parentWin32Path.fast_is_parentend)moduleUnixPath=GenericStringPath(UnixPath)moduleWin32Path=GenericStringPath(Win32Path)moduleCygwinPath=UnixPathincludeDefaultPath