123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189(* Formatters for the main resource tree structure *)(* This file is part of ocp-ocamlres - formats
* (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 *)openOCamlRes.PathopenOCamlRes.ResopenOCamlResSubFormatsopenPPrintmoduletypeFormat=sigtypedatatypeparamsvaloutput:params->dataroot->unitendtypeocaml_format_params={width:int;out_channel:out_channel}moduleOCaml(SF:SubFormat)=structtypedata=SF.ttypeparams=ocaml_format_paramsletescname=letres=Bytes.of_stringnameinfori=0toBytes.lengthres-1domatchname.[i]with|'0'..'9'|'_'|'a'..'z'|'A'..'Z'->()|_->Bytes.setresi'_'done;Bytes.unsafe_to_stringresletesc_namename=ifname=""then"void"elseletres=escnameinmatchname.[0]with|'A'..'Z'|'0'..'9'->"_"^res|_->resletesc_dirname=ifname=""then"Void"elseletres=escnameinmatchname.[0]with|'0'..'9'->"M_"^res|'_'->"M"^res|'a'..'z'->Astring.String.Ascii.capitalizeres|_->resletoutputparamsroot=lethd=ref[]andft=ref[]inletrecoutputdirsnode=matchnodewith|Errormsg->!^"(* Error: "^^!^msg^^!^" *)"|Dir(name,nodes)->letitems=separate_map(break1)(output(name::dirs))nodesingroup(!^"module "^^!^(esc_dirname)^^!^" = struct"^^nest2(break1^^items)^^break1^^!^"end")|File(name,d)->letp=(List.revdirs,Some(split_extname))inletout=SF.pprintpdin(matchSF.pprint_headerpdwithNone->()|Somep->hd:=p::!hd);(matchSF.pprint_footerpdwithNone->()|Somep->ft:=p::!ft);group(!^"let "^^!^(esc_namename)^^!^" ="^^nest2(break1^^out))inletdefs=List.map(funnode->output[]node)rootinletres=separatehardline(List.rev!hd@defs@List.rev!ft)inPPrint.ToChannel.pretty0.8params.widthparams.out_channel(res^^hardline)endtyperes_format_params={width:int;out_channel:out_channel;use_variants_for_leaves:bool;use_variants_for_nodes:bool}moduleRes(SF:SubFormat)=structtypedata=SF.ttypeparams=res_format_paramsletoutputparamsroot=lethd=ref[]andft=ref[]inletbox=letmoduleSM=Map.Make(String)inletreccollectdirsacc=function|Dir(d,nodes)->List.fold_left(collect(d::dirs))accnodes|Error_->acc|File(name,data)->letp=List.revdirs,Some(split_extname)inSM.add(SF.namepdata)(SF.type_namepdata)accinmatchSM.bindings(List.fold_left(collect[])SM.emptyroot)with|[]|[_]->false|l->ifnotparams.use_variants_for_leavesthenbeginletcases=separate_maphardline(fun(c,t)->!^"| "^^!^(Astring.String.Ascii.capitalizec)^^!^" of "^^!^t)linhd:=[group(!^"type content ="^^nest2(hardline^^cases))]end;trueinletres_cstrext=ifnotboxthen!^""else!^((ifparams.use_variants_for_leavesthen"`"else"")^Astring.String.Ascii.capitalizeext^" ")inletnode_cstrext=!^((ifparams.use_variants_for_nodesthen"`"else"")^Astring.String.Ascii.capitalizeext^" ")inletrecoutputdirsnode=matchnodewith|Errormsg->!^"(* Error: "^^!^msg^^!^" *)"|Dir(d,nodes)->letitems=separate_map(!^" ;"^^break1)(output(d::dirs))nodesingroup(node_cstr"Dir"^^!^" (\""^^!^d^^!^"\", ["^^nest2(break1^^items)^^!^"])")|File(name,d)->letp=(List.revdirs,Some(split_extname))inletout=SF.pprintpdin(matchSF.pprint_headerpdwithNone->()|Somep->hd:=p::!hd);(matchSF.pprint_footerpdwithNone->()|Somep->ft:=p::!ft);letcstr_name=SF.namepdingroup(node_cstr"File"^^!^" (\""^^!^name^^!^"\","^^nest2(break1^^res_cstrcstr_name^^out^^!^")"))inletitems=(separate_map(!^" ;"^^break1)(output[])root)inletbody=!^"let root = "^^(ifparams.use_variants_for_nodesthen!^"["else!^"OCamlRes.Res.([")^^nest2(break1^^items)^^break1^^(ifparams.use_variants_for_nodesthen!^"]"else!^"])")inletres=separatehardline(List.rev(!ft@[body]@!hd))inPPrint.ToChannel.pretty0.8params.widthparams.out_channel(res^^hardline)endtypefiles_format_params={base_output_dir:string;}moduleFiles(SF:SubFormat)=structtypedata=SF.ttypeparams=files_format_paramsletoutputparamsroot=letrecoutputdirsnode=matchnodewith|Errormsg->Printf.eprintf"Error: %s\n%!"msg|Dir(d,nodes)->letp=(List.revdirs,Some(d,None))inletfspath=params.base_output_dir^OCamlRes.Path.to_stringpinUnix.handle_unix_error(Unix.mkdirfspath)0o750;List.iter(output(d::dirs))nodes;|File(name,data)->letp=(List.revdirs,Some(split_extname))inletfspath=params.base_output_dir^OCamlRes.Path.to_stringpinletchan=open_out_binfspathinoutput_stringchan(SF.to_rawpdata);close_outchaninifnot(Sys.file_existsparams.base_output_dir)thenUnix.handle_unix_error(Unix.mkdirparams.base_output_dir)0o750;List.iter(funnode->output[]node)rootend