@@ -408,61 +408,102 @@ const ascii_names = [_][]const u8{
408408 "BS" , "TAB" , "LF" , "VT" , "FF" , "CR" , "SO" , "SI" ,
409409 "DLE" , "DC1" , "DC2" , "DC3" , "DC4" , "NAK" , "SYN" , "ETB" ,
410410 "CAN" , "EM" , "SUB" , "ESC" , "FS" , "GS" , "RS" , "US" ,
411- "SPACE" , "! " , "\" " , "# " , "$ " , "% " , "& " , "'" ,
412- "( " , ") " , "* " , "+ " , ", " , "- " , ". " , "/ " ,
413- "0 " , "1 " , "2 " , "3 " , "4 " , "5 " , "6 " , "7 " ,
414- "8 " , "9 " , ": " , "; " , "< " , "= " , "> " , "? " ,
415- "@ " , "A " , "B " , "C " , "D " , "E " , "F " , "G " ,
416- "H " , "I " , "J " , "K " , "L " , "M " , "N " , "O " ,
417- "P " , "Q " , "R " , "S " , "T " , "U " , "V " , "W " ,
418- "X " , "Y " , "Z " , "[ " , "\\ " , "] " , "^ " , "_ " ,
419- "` " , "a " , "b " , "c " , "d " , "e " , "f " , "g " ,
420- "h " , "i " , "j " , "k " , "l " , "m " , "n " , "o " ,
421- "p " , "q " , "r " , "s " , "t " , "u " , "v " , "w " ,
422- "x " , "y " , "z " , "{ " , "| " , "} " , "~ " , "DEL" ,
411+ "SPACE" , "'!' " , "' \" ' " , "'#' " , "'$' " , "'%' " , "'&' " , "' \\ ' '" ,
412+ "'(' " , "')' " , "'*' " , "'+' " , "',' " , "'-' " , "'.' " , "'/' " ,
413+ "'0' " , "'1' " , "'2' " , "'3' " , "'4' " , "'5' " , "'6' " , "'7' " ,
414+ "'8' " , "'9' " , "':' " , "';' " , "'<' " , "'=' " , "'>' " , "'?' " ,
415+ "'@' " , "'A' " , "'B' " , "'C' " , "'D' " , "'E' " , "'F' " , "'G' " ,
416+ "'H' " , "'I' " , "'J' " , "'K' " , "'L' " , "'M' " , "'N' " , "'O' " ,
417+ "'P' " , "'Q' " , "'R' " , "'S' " , "'T' " , "'U' " , "'V' " , "'W' " ,
418+ "'X' " , "'Y' " , "'Z' " , "'[' " , "' \\\\ ' " , "']' " , "'^' " , "'_' " ,
419+ "'`' " , "'a' " , "'b' " , "'c' " , "'d' " , "'e' " , "'f' " , "'g' " ,
420+ "'h' " , "'i' " , "'j' " , "'k' " , "'l' " , "'m' " , "'n' " , "'o' " ,
421+ "'p' " , "'q' " , "'r' " , "'s' " , "'t' " , "'u' " , "'v' " , "'w' " ,
422+ "'x' " , "'y' " , "'z' " , "'{' " , "'|' " , "'}' " , "'~' " , "DEL" ,
423423};
424424
425425fn writeStdout (data : []const u8 ) void {
426426 rawWriteAll (std .Io .File .stdout (), data );
427427}
428428
429+ // Append `s` to `buf` (at *len), doubling any '"' so the result is a safe CSV
430+ // field body (RFC 4180). Returns the new length.
431+ fn csvEscapeInto (buf : []u8 , len_in : usize , s : []const u8 ) usize {
432+ var len = len_in ;
433+ for (s ) | c | {
434+ if (c == '"' ) {
435+ if (len + 2 > buf .len ) return len ;
436+ buf [len ] = '"' ;
437+ buf [len + 1 ] = '"' ;
438+ len += 2 ;
439+ } else {
440+ if (len + 1 > buf .len ) return len ;
441+ buf [len ] = c ;
442+ len += 1 ;
443+ }
444+ }
445+ return len ;
446+ }
447+
448+ // Append `s` to `buf`, escaping '"' and '\\' for a JSON string body.
449+ fn jsonEscapeInto (buf : []u8 , len_in : usize , s : []const u8 ) usize {
450+ var len = len_in ;
451+ for (s ) | c | {
452+ if (c == '"' or c == '\\ ' ) {
453+ if (len + 2 > buf .len ) return len ;
454+ buf [len ] = '\\ ' ;
455+ buf [len + 1 ] = c ;
456+ len += 2 ;
457+ } else {
458+ if (len + 1 > buf .len ) return len ;
459+ buf [len ] = c ;
460+ len += 1 ;
461+ }
462+ }
463+ return len ;
464+ }
465+
429466fn printMappings (mode : MappingsMode ) ! void {
430467 var line_buf : [256 ]u8 = undefined ;
431468 switch (mode ) {
432469 .table = > {
433470 writeStdout ("Byte Dec ASCII Mapping\n " );
434471 for (0.. 256) | i | {
435- const ascii_name = if (i < 128 ) ascii_names [i ] else "" ;
472+ var hex_ascii : [8 ]u8 = undefined ;
473+ const ascii_name = if (i < 128 ) ascii_names [i ] else (std .fmt .bufPrint (& hex_ascii , "0x{X:0>2}" , .{i }) catch "" );
436474 const line = std .fmt .bufPrint (& line_buf , "0x{X:0>2} {d:<5} {s:<12} {s}\n " , .{
437475 i , i , ascii_name , pb .character_map [i ],
438476 }) catch continue ;
439477 writeStdout (line );
440478 }
441479 },
442480 .json = > {
443- writeStdout ("[\n " );
481+ writeStdout ("[" );
444482 for (0.. 256) | i | {
445- const raw_ascii = if (i < 128 ) ascii_names [i ] else "" ;
446- // Escape special JSON characters
447- const ascii_escaped = if (std .mem .eql (u8 , raw_ascii , "\" " ))
448- "\\ \" "
449- else if (std .mem .eql (u8 , raw_ascii , "\\ " ))
450- "\\\\ "
451- else
452- raw_ascii ;
453- const line = std .fmt .bufPrint (& line_buf , " {{\" byte\" : {d}, \" ascii\" : \" {s}\" , \" mapping\" : \" {s}\" }}{s}\n " , .{
454- i , ascii_escaped , pb .character_map [i ], if (i < 255 ) "," else "" ,
483+ var hex_ascii : [8 ]u8 = undefined ;
484+ const raw_ascii = if (i < 128 ) ascii_names [i ] else (std .fmt .bufPrint (& hex_ascii , "0x{X:0>2}" , .{i }) catch "" );
485+ var ab : [64 ]u8 = undefined ;
486+ const ascii_len = jsonEscapeInto (& ab , 0 , raw_ascii );
487+ var mb : [64 ]u8 = undefined ;
488+ const map_len = jsonEscapeInto (& mb , 0 , pb .character_map [i ]);
489+ const line = std .fmt .bufPrint (& line_buf , "{s}\n {{\" byte\" : {d}, \" hex\" : \" 0x{X:0>2}\" , \" dec\" : {d}, \" ascii\" : \" {s}\" , \" mapping\" : \" {s}\" }}" , .{
490+ if (i == 0 ) "" else "," , i , i , i , ab [0.. ascii_len ], mb [0.. map_len ],
455491 }) catch continue ;
456492 writeStdout (line );
457493 }
458- writeStdout ("]\n " );
494+ writeStdout ("\n ]\n " );
459495 },
460496 .csv = > {
461497 writeStdout ("byte,hex,dec,ascii,mapping\n " );
462498 for (0.. 256) | i | {
463- const raw_ascii = if (i < 128 ) ascii_names [i ] else "" ;
499+ var hex_ascii : [8 ]u8 = undefined ;
500+ const raw_ascii = if (i < 128 ) ascii_names [i ] else (std .fmt .bufPrint (& hex_ascii , "0x{X:0>2}" , .{i }) catch "" );
501+ var ab : [64 ]u8 = undefined ;
502+ const ascii_len = csvEscapeInto (& ab , 0 , raw_ascii );
503+ var mb : [64 ]u8 = undefined ;
504+ const map_len = csvEscapeInto (& mb , 0 , pb .character_map [i ]);
464505 const line = std .fmt .bufPrint (& line_buf , "{d},0x{X:0>2},{d},\" {s}\" ,\" {s}\" \n " , .{
465- i , i , i , raw_ascii , pb . character_map [ i ],
506+ i , i , i , ab [0 .. ascii_len ], mb [0 .. map_len ],
466507 }) catch continue ;
467508 writeStdout (line );
468509 }
0 commit comments