123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161open!ImportmoduleChar=Base.CharmoduleInt=Base.IntmoduleString=Base.StringincludeHexdump_intfletbytes_per_line=16(* Initialize to enough lines to display 4096 bytes -- large enough that, for example, a
complete Ethernet packet can always be displayed -- including the line containing the
final index. *)letdefault_max_lines=ref((4096/bytes_per_line)+1)moduleOf_indexable2(T:Indexable2)=structmoduleHexdump=structincludeTlethex_of_pospos=Printf.sprintf"%08x"poslethex_of_chart~start~untiloffset=letpos=start+offsetinifpos>=untilthen" "elsePrintf.sprintf"%02x"(Char.to_int(gettpos));;lethex_of_linet~start~until=Printf.sprintf"%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s"(hex_of_chart~start~until0)(hex_of_chart~start~until1)(hex_of_chart~start~until2)(hex_of_chart~start~until3)(hex_of_chart~start~until4)(hex_of_chart~start~until5)(hex_of_chart~start~until6)(hex_of_chart~start~until7)(hex_of_chart~start~until8)(hex_of_chart~start~until9)(hex_of_chart~start~until10)(hex_of_chart~start~until11)(hex_of_chart~start~until12)(hex_of_chart~start~until13)(hex_of_chart~start~until14)(hex_of_chart~start~until15);;letprintable_stringt~start~until=String.init(until-start)~f:(funi->letchar=gett(start+i)inifChar.is_printcharthencharelse'.');;letlinet~pos~len~line_index=letstart=pos+(line_index*bytes_per_line)inletuntil=min(start+bytes_per_line)(pos+len)inPrintf.sprintf"%s %s |%s|"(hex_of_posstart)(hex_of_linet~start~until)(printable_stringt~start~until);;letto_sequence?max_lines?pos?lent=letpos,len=Ordered_collection_common.get_pos_len_exn()?pos?len~total_length:(lengtht)inletmax_lines=matchmax_lineswith|Somemax_lines->max_lines|None->!default_max_linesin(* always produce at least 3 lines: first line of hex, ellipsis, last line of hex *)letmax_lines=maxmax_lines3in(* unabridged lines = lines of hex + line with final index *)letunabridged_lines=Int.round_uplen~to_multiple_of:bytes_per_line/bytes_per_linein(* Figure out where we need to skip from and to if [max_lines < unabridged_lines].
Skip after half the actual hex lines (subtracting one line for the ellipsis).
Skip to near the end, less the number of lines remaining to produce, plus the
ellipsis line. *)letskip_from=(max_lines-1)/2inletskip_to=unabridged_lines-(max_lines-skip_from)+1inSequence.unfold_step~init:0~f:(funline_index->ifline_index>=unabridged_linesthenDoneelseifline_index=skip_from&&max_lines<unabridged_linesthenYield("...",skip_to)elseYield(linet~pos~len~line_index,line_index+1));;letto_string_hum?max_lines?pos?lent=to_sequence?max_lines?pos?lent|>Sequence.to_list|>String.concat~sep:"\n";;letsexp_of_t__t=to_sequencet|>Sequence.to_list|>[%sexp_of:stringlist]modulePretty=structincludeTletprintable=letrecprintable_fromt~pos~length=pos>=length||(Char.is_print(gettpos)&&printable_fromt~pos:(pos+1)~length)infunt->printable_fromt~pos:0~length:(lengtht);;letto_stringt=String.init(lengtht)~f:(funpos->gettpos)letsexp_of_tsexp_of_asexp_of_bt=ifprintabletthen[%sexp(to_stringt:string)]else[%sexp(t:(a,b)t)];;endendendmoduleOf_indexable1(T:Indexable1)=structmoduleM=Of_indexable2(structtype('a,_)t='aT.tletlength=T.lengthletget=T.getend)moduleHexdump=structincludeTletsexp_of_txt=M.Hexdump.sexp_of_tx[%sexp_of:_]tletto_sequence=M.Hexdump.to_sequenceletto_string_hum=M.Hexdump.to_string_hummodulePretty=structincludeTletsexp_of_tsexp_of_at=[%sexp(t:(a,_)M.Hexdump.Pretty.t)]endendendmoduleOf_indexable(T:Indexable)=structmoduleM=Of_indexable1(structtype_t=T.tletlength=T.lengthletget=T.getend)moduleHexdump=structincludeTletsexp_of_tt=M.Hexdump.sexp_of_t[%sexp_of:_]tletto_sequence=M.Hexdump.to_sequenceletto_string_hum=M.Hexdump.to_string_hummodulePretty=structincludeTletsexp_of_tt=[%sexp(t:_M.Hexdump.Pretty.t)]endendend