123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214letclose_in=close_inletclose_out=close_outletclose_both(ic,oc)=matchclose_outocwith|()->close_inic|exceptionexn->close_inic;Exn.reraiseexnletinput_lines=letrecloopicacc=matchinput_lineicwith|exceptionEnd_of_file->List.revacc|line->loopic(line::acc)infunic->loopic[]letcopy_channels=letbuf_len=65536inletbuf=Bytes.createbuf_leninletrecloopicoc=matchinputicbuf0buf_lenwith|0->()|n->outputocbuf0n;loopicocinloopmoduleMake(Path:sigtypetvalto_string:t->stringend)=structtypepath=Path.tletopen_in?(binary=true)p=letfn=Path.to_stringpinifbinarythenStdlib.open_in_binfnelseStdlib.open_infnletopen_out?(binary=true)p=letfn=Path.to_stringpinifbinarythenStdlib.open_out_binfnelseStdlib.open_outfnletwith_file_in?binaryfn~f=Exn.protectx(open_in?binaryfn)~finally:close_in~fletwith_file_out?binaryp~f=Exn.protectx(open_out?binaryp)~finally:close_out~fletwith_lexbuf_from_filefn~f=with_file_infn~f:(funic->letlb=Lexing.from_channelicinlb.lex_curr_p<-{pos_fname=Path.to_stringfn;pos_lnum=1;pos_bol=0;pos_cnum=0};flb)letread_all=(* We use 65536 because that is the size of OCaml's IO buffers. *)letchunk_size=65536in(* Generic function for channels such that seeking is unsupported or broken *)letread_all_generictbuffer=letrecloop()=Buffer.add_channelbuffertchunk_size;loop()intryloop()withEnd_of_file->Buffer.contentsbufferinfunt->(* Optimisation for regular files: if the channel supports seeking, we
compute the length of the file so that we read exactly what we need and
avoid an extra memory copy. We expect that most files Dune reads are
regular files so this optimizations seems worth it. *)matchin_channel_lengthtwith|exception_->read_all_generict(Buffer.createchunk_size)|n->(lets=really_input_stringtnin(* For some files [in_channel_length] returns an invalid value. For
instance for files in /proc it returns [0]. So we try to read one
more character to make sure we did indeed reach the end of the file *)matchinput_chartwith|exceptionEnd_of_file->s|c->(* The [+ chunk_size] is to make sure there is at least [chunk_size]
free space so that the first [Buffer.add_channel buffer t
chunk_size] in [read_all_generic] does not grow the buffer. *)letbuffer=Buffer.create(String.lengths+1+chunk_size)inBuffer.add_stringbuffers;Buffer.add_charbufferc;read_all_generictbuffer)letread_file?binaryfn=with_file_infn~f:read_all?binaryletlines_of_filefn=with_file_infn~f:input_lines~binary:falseletwrite_file?binaryfndata=with_file_out?binaryfn~f:(funoc->output_stringocdata)letwrite_lines?binaryfnlines=with_file_out?binaryfn~f:(funoc->List.iter~f:(funline->output_stringocline;output_stringoc"\n")lines)letread_file_and_normalize_eolsfn=ifnotStdlib.Sys.win32thenread_filefnelseletsrc=read_filefninletlen=String.lengthsrcinletdst=Bytes.createleninletrecfind_next_crnli=matchString.index_fromsrci'\r'with|None->None|Somej->ifj+1<len&&src.[j+1]='\n'thenSomejelsefind_next_crnl(j+1)inletrecloopsrc_posdst_pos=matchfind_next_crnlsrc_poswith|None->letlen=iflen>src_pos&&src.[len-1]='\r'thenlen-1-src_poselselen-src_posinBytes.blit_string~src~src_pos~dst~dst_pos~len;Bytes.sub_stringdst~pos:0~len:(dst_pos+len)|Somei->letlen=i-src_posinBytes.blit_string~src~src_pos~dst~dst_pos~len;letdst_pos=dst_pos+leninBytes.setdstdst_pos'\n';loop(i+2)(dst_pos+1)inloop00letcompare_text_filesfn1fn2=lets1=read_file_and_normalize_eolsfn1inlets2=read_file_and_normalize_eolsfn2inString.compares1s2letcompare_filesfn1fn2=lets1=read_filefn1inlets2=read_filefn2inString.compares1s2letsetup_copy?(chmod=Fun.id)~src~dst()=letic=open_insrcinletoc=tryletperm=(Unix.fstat(Unix.descr_of_in_channelic)).st_perm|>chmodinStdlib.open_out_gen[Open_wronly;Open_creat;Open_trunc;Open_binary]perm(Path.to_stringdst)withexn->close_inic;Exn.reraiseexnin(ic,oc)letcopy_file?chmod~src~dst()=Exn.protectx(setup_copy?chmod~src~dst())~finally:close_both~f:(fun(ic,oc)->copy_channelsicoc)letfile_linepathn=with_file_in~binary:falsepath~f:(funic->for_=1ton-1doignore(input_lineic)done;input_lineic)letfile_linespath~start~stop=with_file_in~binary:truepath~f:(funic->letrecauxacclnum=iflnum>stopthenList.revaccelseiflnum<startthen(ignore(input_lineic);auxacc(lnum+1))elseletline=input_lineicinaux((string_of_intlnum,line)::acc)(lnum+1)inaux[]1)endincludeMake(Path)moduleString_path=Make(structtypet=stringletto_stringx=xend)