123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839(**************************************************************************)(* *)(* Copyright 2012-2015 OCamlPro *)(* Copyright 2012 INRIA *)(* *)(* All rights reserved. This file is distributed under the terms of the *)(* GNU Lesser General Public License version 2.1, with the special *)(* exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)openOpamCompat(* Global configuration *)letdebug()=OpamCoreConfig.(!r.debug_level)>0letverbose()=OpamCoreConfig.(!r.verbose_level)>0letdumb_term=lazy(tryOpamStd.Env.get"TERM"="dumb"withNot_found->notSys.win32)letcolor=letauto=lazy(OpamStd.Sys.tty_out&¬(Lazy.forcedumb_term))infun()->matchOpamCoreConfig.(!r.color)with|`Always->true|`Never->false|`Auto->Lazy.forceautoletdisp_status_line()=matchOpamCoreConfig.(!r.disp_status_line)with|`Always->true|`Never->false|`Auto->OpamStd.Sys.tty_out&&(color()||not(Lazy.forcedumb_term))letutf8,utf8_extended=letauto=lazy(ifSys.win32thenletattempthandle=let(info:OpamStubs.console_font_infoex)=lethConsoleOutput=OpamStubs.getStdHandlehandleinOpamStubs.getCurrentConsoleFontExhConsoleOutputfalsein(*
* The Windows Console will be able to output Unicode as long as a
* TrueType font has been selected (Consolas or Lucida Console are
* installed by default) and the output code page has been set to
* CP_UTF8 (65001)
* TMPF_TRUETYPE = 0x4 (wingdi.h)
*)info.fontFamilyland0x4<>0&&OpamStubs.getConsoleOutputCP()=65001intryattemptOpamStubs.STD_OUTPUT_HANDLEwithNot_found->tryattemptOpamStubs.STD_INPUT_HANDLEwithNot_found->falseelseletcheckvv=trySome(OpamStd.String.ends_with~suffix:"UTF-8"(OpamStd.Env.getv))withNot_found->NoneinOpamStd.Option.Op.(checkv"LC_ALL"++checkv"LANG"+!false))in(fun()->matchOpamCoreConfig.(!r.utf8)with|`Always|`Extended->true|`Never->false|`Auto->Lazy.forceauto),(fun()->matchOpamCoreConfig.(!r.utf8)with|`Extended->notSys.win32|`Always|`Never->false|`Auto->Lazy.forceauto&&OpamStd.Sys.(os()=Darwin))moduleSymbols=structletrightwards_arrow=Uchar.of_int0x2192letbox_drawings_light_down_and_right=Uchar.of_int0x250cletbox_drawings_light_horizontal=Uchar.of_int0x2500letbox_drawings_light_vertical=Uchar.of_int0x2502letbox_drawings_light_up_and_right=Uchar.of_int0x2514letbox_drawings_light_right=Uchar.of_int0x2576letcircled_division_slash=Uchar.of_int0x2298letasterisk_operator=Uchar.of_int0x2217letnorth_east_arrow=Uchar.of_int0x2197letsouth_east_arrow=Uchar.of_int0x2198letclockwise_open_circle_arrow=Uchar.of_int0x21bbletgreek_small_letter_lambda=Uchar.of_int0x03bbletlatin_capital_letter_o_with_stroke=Uchar.of_int0x00d8letsix_pointed_black_star=Uchar.of_int0x2736letupwards_arrow=Uchar.of_int0x2191letdownwards_arrow=Uchar.of_int0x2193letup_down_arrow=Uchar.of_int0x2195endtypewin32_glyph_checker={font:string;checker:OpamStubs.handle*OpamStubs.handle;glyphs:(Uchar.t,bool)Hashtbl.t;}letwin32_glyph_checker=refNonelet()=ifSys.win32thenletrelease_checkerchecker()=matchcheckerwith|{contents=Some{checker;_}}->OpamStubs.delete_glyph_checkerchecker|_->()inat_exit(release_checkerwin32_glyph_checker)letutf8_symbolmain?(alternates=[])s=ifutf8()thentryletscalar=ifSys.win32thenletcurrent_font=letopenOpamStubsintryletstdout=getStdHandleOpamStubs.STD_OUTPUT_HANDLEin(getCurrentConsoleFontExstdoutfalse).faceNamewithNot_found->letstderr=getStdHandleOpamStubs.STD_ERROR_HANDLEin(getCurrentConsoleFontExstderrfalse).faceNameinletchecker=letnew_checker=lazy{font=current_font;checker=OpamStubs.create_glyph_checkercurrent_font;glyphs=Hashtbl.create16}inmatchwin32_glyph_checkerwith|{contents=Some{font;checker;_}}whenfont<>current_font->OpamStubs.delete_glyph_checkerchecker;letchecker=Lazy.forcenew_checkerinwin32_glyph_checker:=Somechecker;checker|{contents=None}->letchecker=Lazy.forcenew_checkerinwin32_glyph_checker:=Somechecker;checker|{contents=Somechecker}->checkerinletcheck_glyphscalar=tryHashtbl.findchecker.glyphsscalarwithNot_found->lethas_glyph=OpamStubs.has_glyphchecker.checkerscalarinHashtbl.addchecker.glyphsscalarhas_glyph;has_glyphinList.findcheck_glyph(main::alternates)elsemaininletb=Buffer.create4inBuffer.add_utf_8_ucharbscalar;Buffer.contentsbwithFailure_|Not_found->selseslettimer()=ifdebug()thenlett=Unix.gettimeofday()infun()->Unix.gettimeofday()-.telsefun()->0.letglobal_start_time=Unix.gettimeofday()typetext_style=[`bold|`underline|`crossed|`black|`red|`green|`yellow|`blue|`magenta|`cyan|`white]letstyle_code(c:text_style)=matchcwith|`bold->"01"|`underline->"04"|`crossed->"09"|`black->"30"|`red->"31"|`green->"32"|`yellow->"33"|`blue->"1;34"(* most terminals make blue unreadable unless bold *)|`magenta->"35"|`cyan->"36"|`white->"37"(* not nestable *)letcolorisestyles=ifnot(color())thenselsePrintf.sprintf"\027[%sm%s\027[0m"(style_codestyle)sletcolorise'styless=ifnot(color())thenselsePrintf.sprintf"\027[%sm%s\027[0m"(String.concat";"(List.mapstyle_codestyles))sletacolor_with_widthwidthc()s=letstr=colorisecsinstr^matchwidthwith|None->""|Somew->ifString.lengthstr>=wthen""elseString.make(w-String.lengthstr)' 'letacolorc()=colorisecletacolor_wwidthcocs=output_stringoc(acolor_with_width(Somewidth)c()s)typewin32_color_mode=Shim|VT100type_shim_return=|Handle:(OpamStubs.handle*win32_color_mode)shim_return|Mode:win32_color_modeshim_return|Peek:(win32_color_mode->bool)shim_returnletenable_win32_vt100ch=lethConsoleOutput=OpamStubs.getStdHandlechintryletmode=OpamStubs.getConsoleModehConsoleOutputin(* ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4 *)letvt100_on=0x4inifmodelandvt100_on<>0then(hConsoleOutput,VT100)elseifOpamStubs.setConsoleModehConsoleOutput(modelorvt100_on)thenbeginletrestore_console()=letmode=OpamStubs.getConsoleModehConsoleOutputland(lnotvt100_on)inOpamStubs.setConsoleModehConsoleOutputmode|>ignoreinat_exitrestore_console;(hConsoleOutput,VT100)endelse(hConsoleOutput,Shim)withNot_found->(hConsoleOutput,VT100)letstdout_state=lazy(enable_win32_vt100OpamStubs.STD_OUTPUT_HANDLE)letstderr_state=lazy(enable_win32_vt100OpamStubs.STD_ERROR_HANDLE)letget_win32_console_shim:types.[`stdout|`stderr]->sshim_return->s=funch->letch=ifch=`stdoutthenstdout_stateelsestderr_stateinfunction|Handle->Lazy.forcech|Mode->Lazy.forcech|>snd|Peek->funmode->ifLazy.is_valchthensnd(Lazy.forcech)=modeelsefalse(*
* Layout of attributes (wincon.h)
*
* Bit 0 - Blue --\
* Bit 1 - Green } Foreground
* Bit 2 - Red /
* Bit 3 - Bold -/
* Bit 4 - Blue --\
* Bit 5 - Green } Background
* Bit 6 - Red /
* Bit 7 - Bold -/
* Bit 8 - Leading Byte
* Bit 9 - Trailing Byte
* Bit a - Top horizontal
* Bit b - Left vertical
* Bit c - Right vertical
* Bit d - unused
* Bit e - Reverse video
* Bit f - Underscore
*)letis_windows_10=lazy(let(v,_,_,_)=OpamStubs.getWindowsVersion()inv>=10)letwin32_print_messagechmsg=letocaml_ch=matchchwith|`stdout->stdout|`stderr->stderrinifget_win32_console_shimchPeekVT100thenPrintf.fprintfocaml_ch"%s%!"msgelselet(hConsoleOutput,mode)=get_win32_console_shimchHandleinifmode=VT100thenbeginoutput_stringocaml_chmsg;flushocaml_chendelselet{OpamStubs.attributes;_}=OpamStubs.getConsoleScreenBufferInfohConsoleOutputinletbackground=(attributesland0b1110000)lsr4inletlength=String.lengthmsginletexecute_code=letcolor=ref(attributesland0b1111)inletblend?(inheritbold=true)bits=letbits=ifinheritboldthen(!colorland0b1000)lor(bitsland0b111)elsebitsinletresult=(attributesland(lnot0b1111))lor(bitsland0b1000)lor((bitsland0b111)lxorbackground)incolor:=(resultland0b1111);resultinfuncode->letl=String.lengthcodeinassert(l>0&&code.[0]='[');letattributes=OpamStd.String.split(String.subcode1(l-1))';'inletattributes=ifattributes=[]then[""]elseattributesinletfattributesattribute=matchattributewith|"1"|"01"->blend~inheritbold:false(!colorlor0b1000)|"4"|"04"->ifLazy.forceis_windows_10thenattributeslor0b1000000000000000else(* Don't have underline, so change the background *)(attributesland(lnot0b11111111))lor0b01110000|"30"->blend0b000|"31"->blend0b100|"32"->blend0b010|"33"->blend0b110|"34"->blend~inheritbold:false0b001|"35"->blend0b101|"36"->blend0b011|"37"->blend0b111|"0"|""->blend~inheritbold:false0b0111|_->assertfalseinletattrs=(List.fold_leftf(blend!color)attributes)inOpamStubs.setConsoleTextAttributehConsoleOutputattrsinletrecfindexstartin_code=ifindex<lengththenletc=msg.[index]inifc='\027'thenbeginassert(notin_code);letfragment=String.submsgstart(index-start)inletindex=succindexiniffragment<>""thenPrintf.fprintfocaml_ch"%s%!"fragment;findexindextrueendelseifin_code&&c='m'thenletfragment=String.submsgstart(index-start)inletindex=succindexinexecute_codefragment;findexindexfalseelsef(succindex)startin_codeelseletfragment=String.submsgstart(index-start)iniffragment<>""thenifin_codethenexecute_codefragmentelsePrintf.fprintfocaml_ch"%s%!"fragmentelseflushocaml_chinflushocaml_ch;f00falseletcarriage_delete_unix_=print_string"\r\027[K"letcarriage_delete_windows()=let(hConsoleOutput,mode)=get_win32_console_shim`stdoutHandleinmatchmodewith|Shim->let{OpamStubs.size=(w,_);cursorPosition=(_,row);_}=OpamStubs.getConsoleScreenBufferInfohConsoleOutputinPrintf.printf"\r%!";OpamStubs.fillConsoleOutputCharacterhConsoleOutput'\000'w(0,row)|>ignore|VT100->carriage_delete_unix()letcarriage_delete=ifSys.win32thenletcarriage_delete=lazy(matchget_win32_console_shim`stdoutModewith|Shim->carriage_delete_windows|VT100->carriage_delete_unix)infun()->Lazy.forcecarriage_delete()elsecarriage_delete_unixletdisplaying_status=reffalseletclear_status_unix()=if!displaying_statusthenbeginflushstdout;displaying_status:=falseendletclear_status=ifSys.win32thenletclear_status=lazy(matchget_win32_console_shim`stdoutModewith|Shim->fun()->carriage_delete_windows();displaying_status:=false|VT100->clear_status_unix)infun()->Lazy.forceclear_status()elseclear_status_unixletprint_message=ifSys.win32thenfunchfmt->flush(ifch=`stdoutthenstderrelsestdout);clear_status();(* win32_print_message *always* flushes *)Printf.ksprintf(win32_print_messagech)fmtelsefunchfmt->letoutput_string=letoutput_stringchs=output_stringchs;flushchinmatchchwith|`stdout->flushstderr;output_stringstdout|`stderr->flushstdout;output_stringstderrinPrintf.ksprintfoutput_stringfmtlettimestamp()=lettime=Unix.gettimeofday()-.global_start_timeinlettm=Unix.gmtimetimeinletmsec=time-.(floortime)inPrintf.ksprintf(colorise`blue)"%.2d:%.2d.%.3d"(tm.Unix.tm_hour*60+tm.Unix.tm_min)tm.Unix.tm_sec(int_of_float(1000.0*.msec))letlogsection?(level=1)fmt=iflevel<=OpamCoreConfig.(!r.debug_level)thenlet()=clear_status()inifSys.win32thenbegin(*
* In order not to break [slog], split the output into two. A side-effect
* of this is that logging lines may not use colour.
*)win32_print_message`stderr(Printf.sprintf"%s %a "(timestamp())(acolor_with_width(Some30)`yellow)section);Printf.fprintfstderr(fmt^^"\n%!")endelsePrintf.fprintfstderr("%s %a "^^fmt^^"\n%!")(timestamp())(acolor_w30`yellow)sectionelsePrintf.ifprintfstderrfmt(* Helper to pass stringifiers to log (use [log "%a" (slog to_string) x]
rather than [log "%s" (to_string x)] to avoid costly unneeded
stringifications *)letslogto_stringchannelx=output_stringchannel(to_stringx)leterrorfmt=Printf.ksprintf(funstr->print_message`stderr"%a %s\n"(acolor`red)"[ERROR]"(OpamStd.Format.reformat~start_column:8~indent:8str))fmtletwarningfmt=Printf.ksprintf(funstr->print_message`stderr"%a %s\n"(acolor`yellow)"[WARNING]"(OpamStd.Format.reformat~start_column:10~indent:10str))fmtletnotefmt=Printf.ksprintf(funstr->print_message`stderr"%a %s\n"(acolor`blue)"[NOTE]"(OpamStd.Format.reformat~start_column:7~indent:7str))fmtleterrmsgfmt=print_message`stderrfmtleterror_and_exitreasonfmt=Printf.ksprintf(funstr->error"%s"str;OpamStd.Sys.exit_becausereason)fmtletmsgfmt=print_message`stdoutfmtletformatted_msg?indentfmt=Printf.ksprintf(funs->print_message`stdout"%s"(OpamStd.Format.reformat?indents))fmtletlast_status=ref""letwrite_status_unixfmt=letprint_strings=print_strings;flushstdout;carriage_delete_unix();displaying_status:=trueinPrintf.ksprintfprint_string("\r\027[K"^^fmt)letwrite_status_windowsfmt=letprint_strings=carriage_delete();win32_print_message`stdouts;displaying_status:=trueinPrintf.ksprintfprint_stringfmtletwin32_print_functions=lazy(matchget_win32_console_shim`stdoutModewith|Shim->(true,(funs->win32_print_message`stdout(s^"\n")))|VT100->(false,print_endline))letstatus_linefmt=letbatch=debug()||not(disp_status_line())inlet(use_shim,print_msg)=ifSys.win32thenLazy.forcewin32_print_functionselse(false,print_endline)inifbatchthenPrintf.ksprintf(funs->ifs<>!last_statusthen(last_status:=s;print_msgs))fmtelseifuse_shimthenwrite_status_windowsfmtelsewrite_status_unixfmtletheader_width()=min80(OpamStd.Sys.terminal_columns())letheader_msgfmt=letutf8camel="\xF0\x9F\x90\xAB "in(* UTF-8 <U+1F42B, U+0020> *)letpadding="<><><><><><><><><><><><><><><><><><><><>\
<><><><><><><><><><><><><><><><><><><><><>"inPrintf.ksprintf(funstr->letwpad=header_width()-String.lengthstr-2inletwpadl=4inletwpadr=wpad-wpadl-ifutf8_extended()then4else0inprint_message`stdout"\n%s %s %s%s\n"(colorise`cyan(String.subpadding0wpadl))(colorise`boldstr)(ifwpadr>0thenletpadding=String.subpadding(String.lengthpadding-wpadr)wpadrincolorise`cyanpaddingelse"")(ifwpadr>=0&&utf8_extended()then" "^(colorise`yellowutf8camel)else"");)fmtletheader_errorfmt=letpadding="#=======================================\
========================================#"inPrintf.ksprintf(funheadfmt->Printf.ksprintf(funcontents->letwpad=header_width()-String.lengthhead-8inletwpadl=4inletwpadr=wpad-wpadlinprint_message`stderr"\n%s %s %s %s\n%s\n"(colorise`red(String.subpadding0wpadl))(colorise`bold"ERROR")(colorise`boldhead)(ifwpadr>0thenletpadding=String.subpadding(String.lengthpadding-wpadr)wpadrincolorise`redpaddingelse"")contents)fmt)fmtletconfirm?(default=true)fmt=Printf.ksprintf(funs->tryifOpamCoreConfig.(!r.safe_mode)thenfalseelseletprompt()=formatted_msg"%s [%s] "s(ifdefaultthen"Y/n"else"y/N")inifOpamCoreConfig.(!r.answer)=Sometruethen(prompt();msg"y\n";true)elseifOpamCoreConfig.(!r.answer)=Somefalse||OpamStd.Sys.(nottty_in)then(prompt();msg"n\n";false)elseifOpamStd.Sys.(nottty_out||os()=Win32||os()=Cygwin)thenletrecloop()=prompt();matchString.lowercase_ascii(read_line())with|"y"|"yes"->true|"n"|"no"->false|""->default|_->loop()inloop()elseletopenUnixinprompt();letbuf=Bytes.create1inletrecloop()=letans=tryifreadstdinbuf01=0thenraiseEnd_of_fileelseSome(Char.lowercase_ascii(Bytes.getbuf0))with|Unix.Unix_error(Unix.EINTR,_,_)->None|Unix.Unix_error_->raiseEnd_of_fileinmatchanswith|Some'y'->print_endline(Bytes.to_stringbuf);true|Some'n'->print_endline(Bytes.to_stringbuf);false|Some'\n'->print_endline(ifdefaultthen"y"else"n");default|_->loop()inletattr=tcgetattrstdininletreset()=tcsetattrstdinTCSAFLUSHattr;tcflushstdinTCIFLUSH;intrytcsetattrstdinTCSAFLUSH{attrwithc_icanon=false;c_echo=false};tcflushstdinTCIFLUSH;letr=loop()inreset();rwithe->reset();raiseewith|Unix.Unix_error_|End_of_file->msg"%s\n"(ifdefaultthen"y"else"n");default|Sys.Breakase->msg"\n";raisee)fmtletreadfmt=Printf.ksprintf(funs->formatted_msg"%s "s;ifOpamCoreConfig.(!r.answer=None&¬!r.safe_mode)then(trymatchread_line()with|""->None|s->Someswith|End_of_file->msg"\n";None|Sys.Breakase->msg"\n";raisee)elseNone)fmtletprint_table?cutoc~septable=letopenOpamStd.Formatinletcut=matchcutwith|None->ifoc=stdout||oc=stderrthen`Wrap""else`None|Somec->cinletoutput_strings=ifoc=stdoutthenmsg"%s\n"selseifoc=stderrthenerrmsg"%s\n"selsebeginoutput_stringocs;output_charoc'\n'endinletreplace_newlinesby=Re.(replace_string(compile(char'\n'))~by)inletcleanup_trailingsl=letreccleanacc=function|s::r->lets'=OpamStd.String.strip_rightsinifs'=""thencleanaccrelseList.rev_appendr(s'::acc)|[]->accinclean[](List.revsl)inletprint_linel=matchcutwith|`None->lets=List.map(replace_newlines"\\n")l|>String.concatsepinoutput_strings;|`Truncate->lets=List.map(replace_newlines" ")l|>String.concatsepinoutput_string(cut_at_visuals(OpamStd.Sys.terminal_columns()));|`Wrapwrap_sep->letwidth=OpamStd.Sys.terminal_columns()inletbase_indent=10inletsep_len=visual_lengthsepinletwrap_sep_len=visual_lengthwrap_sepinletmax_sep_len=maxsep_lenwrap_sep_leninletindent_string=String.make(max0(base_indent-wrap_sep_len))' '^wrap_sepinletmargin=visual_lengthindent_stringinletmin_reformat_width=30inletrecsplit_at_overflowsstart_colacccur=letappend=function|[]->acc|last::r->List.rev(OpamStd.String.strip_rightlast::r)::accinfunction|[]->List.rev(appendcur)|cell::rest->letmultiline=String.containscell'\n'inletcell_lines=OpamStd.String.splitcell'\n'inletcell_width=List.fold_leftmax0(List.mapvisual_lengthcell_lines)inlettext_width=List.fold_leftmax0(List.map(funs->visual_length(OpamStd.String.strip_rights))cell_lines)inletend_col=start_col+sep_len+cell_widthinletindent~sepncell=letspc=ifsepthenString.make(max0(ifsepthenn-wrap_sep_lenelsen))' '^wrap_sepelseString.maken' 'inOpamStd.List.concat_map("\n"^spc)OpamStd.String.strip_right(OpamStd.String.splitcell'\n')inifstart_col+sep_len+text_width<=widththenifmultilinethenletcell=indent~sep:truestart_col(OpamStd.String.strip_rightcell)insplit_at_overflowsmargin(append(cell::cur))[]restelsesplit_at_overflowsend_colacc(cell::cur)restelseifrest=[]&&acc=[]&¬multiline&&width-start_col-max_sep_len>=min_reformat_widththenletcell=OpamStd.String.strip_rightcell|>funcell->reformat~width:(width-start_col-max_sep_len)cell|>indent~sep:truestart_colinsplit_at_overflowsmarginacc(cell::cur)[]elseifmultiline||margin+cell_width>=widththenletcell=OpamStd.String.strip_rightcell|>funcell->reformat~width:(width-margin)cell|>funcell->OpamStd.String.splitcell'\n'|>OpamStd.List.concat_map("\n"^indent_string)OpamStd.String.strip_rightinsplit_at_overflowsmargin([cell]::appendcur)[]restelsesplit_at_overflows(margin+cell_width)(appendcur)[cell]restinletsplits=split_at_overflows0[][]linletstr=OpamStd.List.concat_map("\n"^String.makebase_indent' ')(String.concatsep)splitsinoutput_stringstr;inList.iter(funl->print_line(cleanup_trailingl))table(* This allows OpamStd.Config.env to display warning messages *)let()=OpamStd.Sys.(set_warning_printer{warning})