Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file write.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242openCore_kernelopen!Int.Replace_polymorphic_comparemoduletypeTo_string=Write_intf.To_stringtype-'at={headers:stringlist;to_columns:'a->tail:stringlist->stringlist}[@@derivingfields]letempty={headers=[];to_columns=(fun_~tail->tail)}letcolumnto_string~header={headers=[header];to_columns=(funx~tail->to_stringx::tail)};;letappendlr=letto_columns_l=l.to_columnsandto_columns_r=r.to_columnsin{headers=List.appendl.headersr.headers;to_columns=(funx~tail->to_columns_lx~tail:(to_columns_rx~tail))};;letof_list=function|[]->empty|[x]->x|first::others->List.foldothers~init:first~f:append;;letcontra_mapx~f=letto_columns=x.to_columnsin{xwithto_columns=(funx~tail->to_columns(fx)~tail)};;letmap_headerst~f={twithheaders=List.mapt.headers~f}letto_columnstx=to_columnstx~tail:[]moduleFields_O=structlet(!!)to_stringfield=letread_field=Field.getfieldincolumn(funr->to_string(read_fieldr))~header:(Field.namefield);;let(!>)innerfield=map_headersinner~f:(letprefix=Field.namefield^"_"infunname->prefix^name)|>contra_map~f:(Field.getfield);;endmoduleO=structlet(<<|)tf=contra_mapt~flet(<>)=appendendletto_string_m(typet)(moduleT:To_stringwithtypet=t)=T.to_stringletcolumn_mm~header=column(to_string_mm)~headerletcolumn_m_opt?(default="")m~header=column(Option.value_map~default~f:(to_string_mm))~header;;moduleExpert=struct(* The standard string transformations are split in two:
- one to get the length of the result (can work on substring)
- another one to perform the action (with string blit semmantic)
Common arguments
-> to figure out how to escape/print quote and separators.
-> to operate on substrings : pos len
-> to perform string transformations: all the blit arguments
*)(* Field handling *)letrecquote_blit_loop~quote~src~dst~src_pos~dst_possrc_end=ifsrc_pos=src_endthendst_poselse(matchsrc.[src_pos]with|cwhenChar.equalcquote->Bytes.setdstdst_posquote;Bytes.setdst(dst_pos+1)quote;quote_blit_loop~quote~src~dst~src_pos:(src_pos+1)~dst_pos:(dst_pos+2)src_end|c->Bytes.setdstdst_posc;quote_blit_loop~quote~src~dst~src_pos:(src_pos+1)~dst_pos:(dst_pos+1)src_end);;letquote_blit~(quote:char)~src~dst~src_pos~dst_pos~len=quote_blit_loop~quote~src~dst~src_pos~dst_pos(src_pos+len);;(** Find the length of a quoted field... *)letrecquote_len_loop~quote~sep~pos~end_pos~should_escapesacc=ifpos=end_posthenifshould_escapethenSomeaccelseNoneelse(matchs.[pos]with|cwhenChar.equalcquote->quote_len_loops~quote~sep~pos:(pos+1)~end_pos~should_escape:true(acc+1)|cwhenChar.equalcsep->quote_len_loops~quote~sep~pos:(pos+1)~end_pos~should_escape:trueacc|'\n'->quote_len_loops~quote~sep~pos:(pos+1)~end_pos~should_escape:trueacc|_->quote_len_loops~quote~sep~pos:(pos+1)~end_pos~should_escapeacc);;letquote_len~quote~sep~pos~lens=iflen=0thenNoneelse(lettrailling_ws=Char.is_whitespaces.[pos]||Char.is_whitespaces.[pos+len-1]inquote_len_loops~quote~sep~pos~end_pos:(len+pos)~should_escape:trailling_wslen);;(** Tables *)letmaybe_escape_field?(quote='"')?(sep=',')s=letlen=String.lengthsinmatchquote_lens~quote~sep~len~pos:0with|None->s|Someqlen->letres=Bytes.create(qlen+2)inBytes.setres0quote;Bytes.setres(qlen+1)quote;ignore(quote_blit~quote~src:s~src_pos:0~dst:res~dst_pos:1~len:int);Bytes.unsafe_to_string~no_mutation_while_string_reachable:res;;letescape_field?(quote='"')s=letlen=String.lengthsinmatchquote_lens~quote~sep:','~len~pos:0with|None->letres=Bytes.create(len+2)inBytes.setres0quote;Bytes.setres(len+1)quote;Bytes.From_string.blit~src_pos:0~dst_pos:1~len~src:s~dst:res;Bytes.unsafe_to_string~no_mutation_while_string_reachable:res|Someqlen->letres=Bytes.create(qlen+2)inBytes.setres0quote;Bytes.setres(qlen+1)quote;ignore(quote_blit~quote~src:s~src_pos:0~dst:res~dst_pos:1~len:int);Bytes.unsafe_to_string~no_mutation_while_string_reachable:res;;endmoduleBy_row=structtyperow=stringlist(** Line handling *)letrecline_spec_loop~quote~sepesc_accsizeacc=matchacc,esc_accwith|[],[]->[],0|[],_->List.revesc_acc,size-1(* We overshot our count by one comma*)|h::t,_->letlen=String.lengthhin(matchExpert.quote_lenh~quote~sep~len~pos:0with|None->line_spec_loop~quote~sep((false,h)::esc_acc)(size+len+1)t|Someqlen->line_spec_loop~quote~sep((true,h)::esc_acc)(size+qlen+3)t);;letfield_blit~quote~dst~pos=function|true,h->Bytes.setdstposquote;letlen=String.lengthhinletqpos=Expert.quote_blit~quote~src:h~src_pos:0~dst~dst_pos:(pos+1)~leninBytes.setdstqposquote;qpos+1|false,h->letlen=String.lengthhinBytes.From_string.blit~dst_pos:pos~src_pos:0~dst~src:h~len;pos+len;;letrecline_blit_loop~quote~sep~dst~pos=function|[]->pos|[v]->field_blit~quote:'"'~dst~posv|v::(_::_ast)->letpos=field_blit~quote:'"'~dst~posvinBytes.setdstpossep;line_blit_loop~quote~sep~dst~pos:(pos+1)t;;letline_to_string?(quote='"')?(sep=',')l=letspec,len=line_spec_loop~quote~sep[]0linletres=Bytes.createleninignore(line_blit_loop~quote~sep~dst:res~pos:0spec:int);Bytes.unsafe_to_string~no_mutation_while_string_reachable:res;;letrecoutput_lines_loop~quote~sep~buff~eoloc=function|[]->()|h::t->letspec,len=line_spec_loop~quote~sep[]0hinletbuff=ifBytes.lengthbuff<lenthenBytes.create(2*len)elsebuffinignore(line_blit_loop~quote~sep~dst:buff~pos:0spec:int);Out_channel.outputoc~buf:buff~pos:0~len;Out_channel.output_stringoceol;output_lines_loop~quote~sep~buff~eoloct;;letoutput_lines?(quote='"')?(sep=',')?(eol=`Dos)ocl=leteol=matcheolwith|`Dos->"\r\n"|`Unix->"\n"inoutput_lines_loop~quote~sep~buff:(Bytes.create256)~eolocl;;end