123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125(* Input scanners definition and default implementations. *)(* This file is part of ocp-ocamlres - input scanners
* (C) 2013 OCamlPro - Benjamin CANOU
*
* ocp-ocamlres 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 3.0 of the License, or (at your option) any later
* version, with linking exception.
*
* ocp-ocamlres 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 LICENSE file for more details *)openOCamlResmodulePathFilter=structtypet=Path.t->boolletany:t=fun_->trueletnone:t=fun_->falseletexclude(f:t):t=funpath->not(fpath)letall_of(fs:tlist):t=funpath->List.fold_left(funrf->r&&(fpath))truefsletany_of(fs:tlist):t=funpath->List.fold_left(funrf->r||(fpath))falsefsletlimit(lvl:int):t=letreclooplvldirs=matchdirswith|[]->true|_::tlwhenlvl>0->loop(predlvl)tl|_::tl->falseinfunpath->looplvl(fstpath)lethas_extension(exts:stringlist):t=letmoduleSS=Set.Make(String)inletexts=List.fold_rightSS.addextsSS.emptyinfunpath->matchpathwith|(_,Some(_,Someext))->SS.memextexts|(_,None)->true|_->falseendmoduleResFilter=structtype'at='aRes.node->boolletany:_t=fun_->trueletnone:_t=fun_->falseletexclude(f:'at):'at=funres->not(fres)letall_of(fs:'atlist):'at=funres->List.fold_left(funrf->r&&(fres))truefsletany_of(fs:'atlist):'at=funres->List.fold_left(funrf->r||(fres))falsefsletempty_dir:_t=functionRes.Dir(_,[])->true|_->falseendletscan_unix_dir(typet)?(prefilter=PathFilter.any)?(postfilter=ResFilter.any)?(prefixed_file=false)(moduleSF:OCamlResSubFormats.SubFormatwithtypet=t)base=letopenResinletrecscanpathnamepstr=letres=tryifnot(Sys.file_existspstr)thenSome(Error(Printf.sprintf"no such file %S"pstr))elseifSys.is_directorypstrthenifprefilter(name::path,None)thenSome(scan_dirpathnamepstr)elseNoneelseifprefilter(name::path,Some(Path.split_extname))thenmatchPath.of_stringpstrwith|_,None->assertfalse|prefix,Somename->letname=Path.string_of_namenameinletnode=scan_file(path@prefix)namepstrinifprefixed_file&&prefix<>[]thenSome(Res.add_prefix("root"::prefix)node)elseSomenodeelseNonewithexn->letmsg=Printf.sprintf"scanning file %S, %s"pstr(Printexc.to_stringexn)inSome(Errormsg)inmatchreswith|Somerwhenpostfilterr->res|_->Noneandscan_dirpathnamepstr=letfiles=Array.to_list(Sys.readdirpstr)inletpstrs=List.map(funn->n,pstr^"/"^n)filesinletnpath=name::pathinletcontents=List.map(fun(n,p)->scannpathnp)pstrsinletcontents=List.fold_left(funropt->matchoptwithNone->r|Somep->p::r)[]contentsinDir(name,contents)andscan_filepathnamepstr=letcontents=letchan=open_in_binpstrinletlen=in_channel_lengthchaninletbuffer=Bytes.createleninreally_inputchanbuffer0len;close_inchan;Bytes.unsafe_to_stringbufferinFile(name,SF.from_raw(path,Some(Path.split_extname))contents)inmatchscan[]"root"basewith|Some(Dir(_,l))->l|Some(File(_,ctns))->[File(Filename.basenamebase,ctns)]|Some(Error_aserr)->[err]|None->[]