(* open Lazylist *)openStream_intf(* CR jfuruse: buf and buffer are lousy *)typebuf={base:Sstring.t;(* underlying stream *)buf_pos:int;(* the abs position of the head of buf *)rel_pos:int;(* from the buf head in bytes from 0 *)abs_pos:Position.File.t;(* from the first of the stream *)}letdefault_buf={base=Sstring.the_null;buf_pos=-1;rel_pos=-1;abs_pos=Position.File.none}letposition_of_bufbuf=buf.abs_posmoduletypeX=sigtypet(** the type of the stream *)valcreate:buf->t(** Create a stream from a buffer *)valsubstr:t->int->int->string*t(** [substr t from len] returns a substring of [len] chars from [t] from its absolute char position [from], and a stream which starts at the end of the substring. It may raise an exception if [from] and [len] point outside of the stream *)valtakeWhile:(char->bool)->t->string*t(** [takeWhile p t] returns the longest prefix of [t] all whose characters suffices the predicate [p], and the stream which starts at the end of the prefix. *)valbytes:t->int(** [bytes t] returns the head position of the stream as the nubmer of bytes. *)valfrom_string:filename:string->string->tvalfrom_chan:filename:string->in_channel->t(** Creation functions of buffered streams *)valset_position:t->Position.File.t->t(** [set_position t pos] returns the same stream as [t] but with the head position is changed by [pos] *)endmoduleExtend(Base:sigincludeStream_intf.SwithtypeElem.t=charandtypePos.t=Position.File.tvalbuf:t->bufvalcreate_attr:buf->Attr.tend)=structopenBasetypet=Base.tletbytest=(buft).buf_pos+(buft).rel_posletadvance_charabs_pos=function|'\n'->Position.File.add_newlinesabs_pos1|_->Position.File.add_columnsabs_pos1letadvance_stringabs_poss=letslen=String.lengthsinletrecfoldabs_pos=function|nwhenn=slen->abs_pos|n->fold(advance_charabs_pos(String.unsafe_getsn))(n+1)infoldabs_pos0letreccreate:buf->t=funi->matchSstring.peeki.basewith|None->null(create_attri)|Some(elem,buf')->ifi.rel_pos>=String.lengthelemthenbegin(* If the position is out of the head *)create{iwithbase=buf';buf_pos=i.buf_pos+String.lengthelem;rel_pos=i.rel_pos-String.lengthelem}endelseletchar=String.unsafe_getelemi.rel_posinletabs_pos'=advance_chari.abs_poscharinleti'={iwithrel_pos=i.rel_pos+1;abs_pos=abs_pos'}inlazy(cons_descchar(create_attri)(createi'))letset_position:t->Position.File.t->t=funtpos->create{(buft)withabs_pos=pos}letsubstrtstart_abs_poslen=leti=buftinifi.abs_pos.Position.File.byte>start_abs_posthenfailwith"Sbuffer.substr: start_abs_pos is over";letbuffer=Buffer.createleninletrecsubstrstreamstream_pos(* abs position of head of buf *)poslen=matchSstring.peekstreamwith|None->failwith"Sbuffer.substr: end of stream"|Some(string,stream')->(* Format.eprintf "substr.substr %d %d %d %s@." stream_pos pos len (try String.sub string 0 40 with _ -> string); *)letlen_string=String.lengthstringinletstream_pos'=stream_pos+len_stringin(* abs position of head of stream' *)ifstream_pos'<=posthensubstrstream'stream_pos'poslen(* [string] is before [pos] *)else(* [string] contains [pos] *)letstart=pos-stream_posinletcopy_len=minlen(len_string-start)inBuffer.add_substringbufferstringstartcopy_len;letlen'=len-copy_leniniflen'<=0then(* [pos + len] is in [string]. End of substr *)lets=Buffer.contentsbufferins,{base=stream;buf_pos=stream_pos;rel_pos=start+len;abs_pos=advance_stringi.abs_poss}elsesubstrstream'stream_pos'stream_pos'len'inlets,buf=substri.basei.buf_posstart_abs_posleninassert(String.lengths=len);s,createbuflettakeWhilept=leti=buftinletbuffer=Buffer.create10inletreciterstreambuf_posrel_pos=letfinishrel_pos=lets=Buffer.contentsbufferins,{base=stream;buf_pos=buf_pos;rel_pos=rel_pos;abs_pos=advance_stringi.abs_poss}inmatchSstring.peekstreamwith|None->finishrel_pos|Some(string,stream')->letlen_string=String.lengthstringinletreciter_internal=function|nwhenlen_string=n->(* try on the next string *)iterstream'(buf_pos+len_string)0|n->letchar=String.unsafe_getstringninifpcharthenbeginBuffer.add_charbufferchar;iter_internal(n+1)endelsefinishniniter_internalrel_posinlets,buf=iteri.basei.buf_posi.rel_posins,createbufletfrom_string~filenamestr=create{base=Sstring.from_stringstr;buf_pos=0;rel_pos=0;abs_pos=Position.File.topfilename}letfrom_chan~filenameic=create{base=Sstring.from_chanic;buf_pos=0;rel_pos=0;abs_pos=Position.File.topfilename}end