123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886(*
* IO - Abstract input/output
* Copyright (C) 2003 Nicolas Cannasse
*
* 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 special exception on linking described in file LICENSE.
*
* 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 GNU
* Lesser General Public License 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)#ifOCAML<407moduleStdlib=Pervasives#endiftypeinput={mutablein_read:unit->char;mutablein_input:Bytes.t->int->int->int;mutablein_close:unit->unit;}type'aoutput={mutableout_write:char->unit;mutableout_output:Bytes.t->int->int->int;mutableout_close:unit->'a;mutableout_flush:unit->unit;}exceptionNo_more_inputexceptionInput_closedexceptionOutput_closed(* -------------------------------------------------------------- *)(* API *)letdefault_close=(fun()->())letcreate_in~read~input~close={in_read=read;in_input=input;in_close=close;}letcreate_out~write~output~flush~close={out_write=write;out_output=output;out_close=close;out_flush=flush;}letreadi=i.in_read()letnreadin=ifn<0theninvalid_arg"IO.nread";ifn=0thenBytes.emptyelselets=Bytes.createninletl=refninletp=ref0intrywhile!l>0doletr=i.in_inputs!p!linifr=0thenraiseNo_more_input;p:=!p+r;l:=!l-r;done;swithNo_more_inputase->if!p=0thenraisee;Bytes.subs0!pletnread_stringin=(* [nread] transfers ownership of the returned string, so
[unsafe_to_string] is safe here *)Bytes.unsafe_to_string(nreadin)letreally_outputospl'=letsl=Bytes.lengthsinifp+l'>sl||p<0||l'<0theninvalid_arg"IO.really_output";letl=refl'inletp=refpinwhile!l>0doletw=o.out_outputs!p!linifw=0thenraiseSys_blocked_io;p:=!p+w;l:=!l-w;done;l'letinputispl=letsl=Bytes.lengthsinifp+l>sl||p<0||l<0theninvalid_arg"IO.input";ifl=0then0elsei.in_inputsplletreally_inputispl'=letsl=Bytes.lengthsinifp+l'>sl||p<0||l'<0theninvalid_arg"IO.really_input";letl=refl'inletp=refpinwhile!l>0doletr=i.in_inputs!p!linifr=0thenraiseSys_blocked_io;p:=!p+r;l:=!l-r;done;l'letreally_nreadin=ifn<0theninvalid_arg"IO.really_nread";ifn=0thenBytes.emptyelselets=Bytes.createninignore(really_inputis0n);sletreally_nread_stringin=(* [really_nread] transfers ownership of the returned string,
so [unsafe_to_string] is safe here *)Bytes.unsafe_to_string(really_nreadin)letclose_ini=letf_=raiseInput_closedini.in_close();i.in_read<-f;i.in_input<-f;i.in_close<-fletwriteox=o.out_writexletnwriteos=letp=ref0inletl=ref(Bytes.lengths)inwhile!l>0doletw=o.out_outputs!p!linifw=0thenraiseSys_blocked_io;p:=!p+w;l:=!l-w;doneletnwrite_stringos=(* [nwrite] does not mutate or capture its [bytes] input,
so using [Bytes.unsafe_of_string] is safe here *)nwriteo(Bytes.unsafe_of_strings)letoutputospl=letsl=Bytes.lengthsinifp+l>sl||p<0||l<0theninvalid_arg"IO.output";o.out_outputsplletscanfifmt=letib=Scanf.Scanning.from_function(fun()->tryreadiwithNo_more_input->raiseEnd_of_file)inScanf.kscanfib(fun_exn->raiseexn)fmtletprintfofmt=Printf.kprintf(funs->nwrite_stringos)fmtletflusho=o.out_flush()letclose_outo=letf_=raiseOutput_closedinletr=o.out_close()ino.out_write<-f;o.out_output<-f;o.out_close<-f;o.out_flush<-f;rletread_alli=letmaxlen=1024inletstr=ref[]inletpos=ref0inletrecloop()=lets=nreadimaxleninstr:=(s,!pos)::!str;pos:=!pos+Bytes.lengths;loop()intryloop()withNo_more_input->letbuf=Bytes.create!posinList.iter(fun(s,p)->Bytes.blits0bufp(Bytes.lengths))!str;(* 'buf' doesn't escape, it won't be mutated again *)Bytes.unsafe_to_stringbufletpos_ini=letp=ref0in{in_read=(fun()->letc=i.in_read()inincrp;c);in_input=(funsspl->letn=i.in_inputssplinp:=!p+n;n);in_close=i.in_close},(fun()->!p)letpos_outo=letp=ref0in{out_write=(func->o.out_writec;incrp);out_output=(funsspl->letn=o.out_outputssplinp:=!p+n;n);out_close=o.out_close;out_flush=o.out_flush;},(fun()->!p)(* -------------------------------------------------------------- *)(* Standard IO *)letinput_bytess=letpos=ref0inletlen=Bytes.lengthsin{in_read=(fun()->if!pos>=lenthenraiseNo_more_input;letc=Bytes.unsafe_gets!posinincrpos;c);in_input=(funsoutpl->if!pos>=lenthenraiseNo_more_input;letn=(if!pos+l>lenthenlen-!poselsel)inBytes.unsafe_blits!possoutpn;pos:=!pos+n;n);in_close=(fun()->());}letinput_strings=(* Bytes.unsafe_of_string is safe here as input_bytes does not
mutate the byte sequence *)input_bytes(Bytes.unsafe_of_strings)openExtBufferletoutput_bufferclose=letb=Buffer.create0in{out_write=(func->Buffer.add_charbc);out_output=(funspl->Buffer.add_subbytesbspl;l);out_close=(fun()->closeb);out_flush=(fun()->());}letoutput_string()=output_bufferBuffer.contentsletoutput_bytes()=output_bufferBuffer.to_bytesletoutput_strings()=letsl=ref[]inletsize=ref0inletb=Buffer.create0in{out_write=(func->if!size=Sys.max_string_lengththenbeginsl:=Buffer.contentsb::!sl;Buffer.clearb;size:=0;endelseincrsize;Buffer.add_charbc);out_output=(funspl->if!size+l>Sys.max_string_lengththenbeginsl:=Buffer.contentsb::!sl;Buffer.clearb;size:=0;endelsesize:=!size+l;Buffer.add_subbytesbspl;l);out_close=(fun()->sl:=Buffer.contentsb::!sl;List.rev(!sl));out_flush=(fun()->());}letinput_channelch={in_read=(fun()->tryinput_charchwithEnd_of_file->raiseNo_more_input);in_input=(funspl->letn=Stdlib.inputchsplinifn=0thenraiseNo_more_input;n);in_close=(fun()->Stdlib.close_inch);}letoutput_channelch={out_write=(func->output_charchc);out_output=(funspl->Stdlib.outputchspl;l);out_close=(fun()->Stdlib.close_outch);out_flush=(fun()->Stdlib.flushch);}letinput_enume=letpos=ref0in{in_read=(fun()->matchEnum.getewith|None->raiseNo_more_input|Somec->incrpos;c);in_input=(funspl->letreclooppl=ifl=0then0elsematchEnum.getewith|None->l|Somec->Bytes.unsafe_setspc;loop(p+1)(l-1)inletk=loopplinifk=lthenraiseNo_more_input;l-k);in_close=(fun()->());}letoutput_enum()=letb=Buffer.create0in{out_write=(funx->Buffer.add_charbx);out_output=(funspl->Buffer.add_subbytesbspl;l);out_close=(fun()->lets=Buffer.contentsbinExtString.String.enums);out_flush=(fun()->());}letpipe()=letinput=ref""inletinpos=ref0inletoutput=Buffer.create0inletflush()=input:=Buffer.contentsoutput;inpos:=0;Buffer.resetoutput;ifString.length!input=0thenraiseNo_more_inputinletread()=if!inpos=String.length!inputthenflush();letc=String.unsafe_get!input!inposinincrinpos;cinletinputspl=if!inpos=String.length!inputthenflush();letr=(if!inpos+l>String.length!inputthenString.length!input-!inposelsel)inString.unsafe_blit!input!inposspr;inpos:=!inpos+r;rinletwritec=Buffer.add_charoutputcinletoutputspl=Buffer.add_subbytesoutputspl;linletinput={in_read=read;in_input=input;in_close=(fun()->());}inletoutput={out_write=write;out_output=output;out_close=(fun()->());out_flush=(fun()->());}ininput,outputexternalcast_output:'aoutput->unitoutput="%identity"(* -------------------------------------------------------------- *)(* BINARY APIs *)exceptionOverflowofstringletread_bytei=int_of_char(i.in_read())letread_signed_bytei=letc=int_of_char(i.in_read())inifcland128<>0thenc-256elsecletread_string_into_bufferi=letb=Buffer.create8inletrecloop()=letc=i.in_read()inifc<>'\000'thenbeginBuffer.add_charbc;loop();end;inloop();bletread_stringi=Buffer.contents(read_string_into_bufferi)letread_bytesi=Buffer.to_bytes(read_string_into_bufferi)letread_linei=letb=Buffer.create8inletcr=reffalseinletrecloop()=letc=i.in_read()inmatchcwith|'\n'->()|'\r'->cr:=true;loop()|_when!cr->cr:=false;Buffer.add_charb'\r';Buffer.add_charbc;loop();|_->Buffer.add_charbc;loop();intryloop();Buffer.contentsbwithNo_more_input->if!crthenBuffer.add_charb'\r';ifBuffer.lengthb>0thenBuffer.contentsbelseraiseNo_more_inputletread_ui16i=letch1=read_byteiinletch2=read_byteiinch1lor(ch2lsl8)letread_i16i=letch1=read_byteiinletch2=read_byteiinletn=ch1lor(ch2lsl8)inifch2land128<>0thenn-65536elsenletsign_bit_i32=lnot0x7FFF_FFFFletread_32~i31ch=letch1=read_bytechinletch2=read_bytechinletch3=read_bytechinletch4=read_bytechinifch4land128<>0thenbeginifi31&&ch4land64=0thenraise(Overflow"read_i31");ch1lor(ch2lsl8)lor(ch3lsl16)lor((ch4land127)lsl24)lorsign_bit_i32endelsebeginifi31&&ch4land64<>0thenraise(Overflow"read_i31");ch1lor(ch2lsl8)lor(ch3lsl16)lor(ch4lsl24)endletread_i31ch=read_32~i31:truechletread_i32_as_intch=read_32~i31:falsechletread_i32=read_i31letread_real_i32ch=letch1=read_bytechinletch2=read_bytechinletch3=read_bytechinletbase=Int32.of_int(ch1lor(ch2lsl8)lor(ch3lsl16))inletbig=Int32.shift_left(Int32.of_int(read_bytech))24inInt32.logorbasebigletread_i64ch=letch1=read_bytechinletch2=read_bytechinletch3=read_bytechinletch4=read_bytechinletbase=Int64.of_int(ch1lor(ch2lsl8)lor(ch3lsl16))inletsmall=Int64.logorbase(Int64.shift_left(Int64.of_intch4)24)inletbig=Int64.of_int32(read_real_i32ch)inInt64.logor(Int64.shift_leftbig32)smallletread_float32ch=Int32.float_of_bits(read_real_i32ch)letread_doublech=Int64.float_of_bits(read_i64ch)letwrite_byteon=(* doesn't test bounds of n in order to keep semantics of Stdlib.output_byte *)writeo(Char.unsafe_chr(nland0xFF))letwrite_stringos=nwrite_stringos;writeo'\000'letwrite_bytesos=nwriteos;writeo'\000'letwrite_lineos=nwrite_stringos;writeo'\n'letwrite_ui16chn=ifn<0||n>0xFFFFthenraise(Overflow"write_ui16");write_bytechn;write_bytech(nlsr8)letwrite_i16chn=ifn<-0x8000||n>0x7FFFthenraise(Overflow"write_i16");ifn<0thenwrite_ui16ch(65536+n)elsewrite_ui16chnletwrite_32chn=write_bytechn;write_bytech(nlsr8);write_bytech(nlsr16);write_bytech(nasr24)letwrite_i31chn=#ifndefWORD_SIZE_32ifn<-0x4000_0000||n>0x3FFF_FFFFthenraise(Overflow"write_i31");#endifwrite_32chnletwrite_i32chn=#ifndefWORD_SIZE_32ifn<-0x8000_0000||n>0x7FFF_FFFFthenraise(Overflow"write_i32");#endifwrite_32chnletwrite_real_i32chn=letbase=Int32.to_intninletbig=Int32.to_int(Int32.shift_right_logicaln24)inwrite_bytechbase;write_bytech(baselsr8);write_bytech(baselsr16);write_bytechbigletwrite_i64chn=write_real_i32ch(Int64.to_int32n);write_real_i32ch(Int64.to_int32(Int64.shift_right_logicaln32))letwrite_float32chf=write_real_i32ch(Int32.bits_of_floatf)letwrite_doublechf=write_i64ch(Int64.bits_of_floatf)(* -------------------------------------------------------------- *)(* Big Endians *)moduleBigEndian=structletread_ui16i=letch2=read_byteiinletch1=read_byteiinch1lor(ch2lsl8)letread_i16i=letch2=read_byteiinletch1=read_byteiinletn=ch1lor(ch2lsl8)inifch2land128<>0thenn-65536elsenletsign_bit_i32=lnot0x7FFF_FFFFletread_32~i31ch=letch4=read_bytechinletch3=read_bytechinletch2=read_bytechinletch1=read_bytechinifch4land128<>0thenbeginifi31&&ch4land64=0thenraise(Overflow"read_i31");ch1lor(ch2lsl8)lor(ch3lsl16)lor((ch4land127)lsl24)lorsign_bit_i32endelsebeginifi31&&ch4land64<>0thenraise(Overflow"read_i31");ch1lor(ch2lsl8)lor(ch3lsl16)lor(ch4lsl24)endletread_i31ch=read_32~i31:truechletread_i32_as_intch=read_32~i31:falsechletread_i32=read_i31letread_real_i32ch=letbig=Int32.shift_left(Int32.of_int(read_bytech))24inletch3=read_bytechinletch2=read_bytechinletch1=read_bytechinletbase=Int32.of_int(ch1lor(ch2lsl8)lor(ch3lsl16))inInt32.logorbasebigletread_i64ch=letbig=Int64.of_int32(read_real_i32ch)inletch4=read_bytechinletch3=read_bytechinletch2=read_bytechinletch1=read_bytechinletbase=Int64.of_int(ch1lor(ch2lsl8)lor(ch3lsl16))inletsmall=Int64.logorbase(Int64.shift_left(Int64.of_intch4)24)inInt64.logor(Int64.shift_leftbig32)smallletread_float32ch=Int32.float_of_bits(read_real_i32ch)letread_doublech=Int64.float_of_bits(read_i64ch)letwrite_ui16chn=ifn<0||n>0xFFFFthenraise(Overflow"write_ui16");write_bytech(nlsr8);write_bytechnletwrite_i16chn=ifn<-0x8000||n>0x7FFFthenraise(Overflow"write_i16");ifn<0thenwrite_ui16ch(65536+n)elsewrite_ui16chnletwrite_32chn=write_bytech(nasr24);write_bytech(nlsr16);write_bytech(nlsr8);write_bytechnletwrite_i31chn=#ifndefWORD_SIZE_32ifn<-0x4000_0000||n>0x3FFF_FFFFthenraise(Overflow"write_i31");#endifwrite_32chnletwrite_i32chn=#ifndefWORD_SIZE_32ifn<-0x8000_0000||n>0x7FFF_FFFFthenraise(Overflow"write_i32");#endifwrite_32chnletwrite_real_i32chn=letbase=Int32.to_intninletbig=Int32.to_int(Int32.shift_right_logicaln24)inwrite_bytechbig;write_bytech(baselsr16);write_bytech(baselsr8);write_bytechbaseletwrite_i64chn=write_real_i32ch(Int64.to_int32(Int64.shift_right_logicaln32));write_real_i32ch(Int64.to_int32n)letwrite_float32chf=write_real_i32ch(Int32.bits_of_floatf)letwrite_doublechf=write_i64ch(Int64.bits_of_floatf)end(* -------------------------------------------------------------- *)(* Bits API *)type'abc={ch:'a;mutablenbits:int;mutablebits:int;}typein_bits=inputbctypeout_bits=unitoutputbcexceptionBits_errorletinput_bitsch={ch=ch;nbits=0;bits=0;}letoutput_bitsch={ch=cast_outputch;nbits=0;bits=0;}letrecread_bitsbn=ifb.nbits>=nthenbeginletc=b.nbits-ninletk=(b.bitsasrc)land((1lsln)-1)inb.nbits<-c;kendelsebeginletk=read_byteb.chinifb.nbits>=24thenbeginifn>31thenraiseBits_error;letc=8+b.nbits-ninletd=b.bitsland((1lslb.nbits)-1)inletd=(dlsl(8-c))lor(klsrc)inb.bits<-k;b.nbits<-c;dendelsebeginb.bits<-(b.bitslsl8)lork;b.nbits<-b.nbits+8;read_bitsbn;endendletdrop_bitsb=b.nbits<-0letrecwrite_bitsb~nbitsx=letn=nbitsinifn+b.nbits>=32thenbeginifn>31thenraiseBits_error;letn2=32-b.nbits-1inletn3=n-n2inwrite_bitsb~nbits:n2(xasrn3);write_bitsb~nbits:n3(xland((1lsln3)-1));endelsebeginifn<0thenraiseBits_error;if(x<0||x>(1lsln-1))&&n<>31thenraiseBits_error;b.bits<-(b.bitslsln)lorx;b.nbits<-b.nbits+n;whileb.nbits>=8dob.nbits<-b.nbits-8;write_byteb.ch(b.bitsasrb.nbits)doneendletflush_bitsb=ifb.nbits>0thenwrite_bitsb(8-b.nbits)0(* -------------------------------------------------------------- *)(* Generic IO *)classin_channelch=objectmethodinputsposlen=inputchsposlenmethodclose_in()=close_inchendclassout_channelch=objectmethodoutputsposlen=outputchsposlenmethodflush()=flushchmethodclose_out()=ignore(close_outch)endclassin_charsch=objectmethodget()=tryreadchwithNo_more_input->raiseEnd_of_filemethodclose_in()=close_inchendclassout_charsch=objectmethodputt=writechtmethodflush()=flushchmethodclose_out()=ignore(close_outch)endletfrom_in_channelch=letcbuf=Bytes.create1inletread()=tryifch#inputcbuf01=0thenraiseSys_blocked_io;Bytes.unsafe_getcbuf0withEnd_of_file->raiseNo_more_inputinletinputspl=ch#inputsplincreate_in~read~input~close:ch#close_inletfrom_out_channelch=letcbuf=Bytes.create1inletwritec=Bytes.unsafe_setcbuf0c;ifch#outputcbuf01=0thenraiseSys_blocked_io;inletoutputspl=ch#outputsplincreate_out~write~output~flush:ch#flush~close:ch#close_outletfrom_in_charsch=letinputspl=leti=ref0intrywhile!i<ldoBytes.unsafe_sets(p+!i)(ch#get());incridone;lwithEnd_of_filewhen!i>0->!iincreate_in~read:ch#get~input~close:ch#close_inletfrom_out_charsch=letoutputspl=fori=ptop+l-1doch#put(Bytes.unsafe_getsi)done;lincreate_out~write:ch#put~output~flush:ch#flush~close:ch#close_out