code wiki / (root) / nx_tools_argv_unicode_gate.nx

nx_tools_argv_unicode_gate.nx source

↩ module page · 224 lines · 12718 B

1import "nx_tools_api.nx" 2import "nx_gate_verdict.nx" 3 4func tug_case(label: *u8, body: *u8, want: i64, expected: *u8, cap: i64, maxn: i64, ctr: *i64) -> i64 { 5 let scratch: *u8 = sys_mmap(cap + 8) 6 let av: *i64 = sys_mmap((maxn + 3)*8) as *i64 7 var j: i64 = 0 8 while j < maxn + 3 { av[j] = 85; j = j + 1 } 9 j = cap 10 while j < cap + 8 { scratch[j] = 85 as u8; j = j + 1 } 11 let result: i64 = ta_json_str_array(body, jx_len(body), "\"argv\"" as *u8, av, 1, maxn, scratch, cap) 12 var ok: i64 = result == want 13 var ep: *u8 = expected 14 var k: i64 = 0 15 if ok == 1 { if result >= 0 { if result <= maxn { 16 while k < result { 17 let addr: i64 = av[k + 1] 18 var valid_ptr: i64 = 1 19 if addr < (scratch as i64) { valid_ptr = 0 } 20 if addr >= (scratch as i64) + cap { valid_ptr = 0 } 21 if valid_ptr == 0 { ok = 0 } 22 else { 23 let got: *u8 = addr as *u8 24 let remain: i64 = cap - (addr - (scratch as i64)) 25 var gn: i64 = 0 26 var scan: i64 = 1 27 while scan == 1 { 28 if gn >= remain { scan = 0 } 29 else { if got[gn] == (0 as u8) { scan = 0 } else { gn = gn + 1 } } 30 } 31 let en: i64 = jx_len(ep) 32 if gn != en { ok = 0 } 33 if gn >= remain { ok = 0 } 34 j = 0 35 while j < gn { if j < en { if got[j] != ep[j] { ok = 0 } } j = j + 1 } 36 ep = ((ep as i64) + en + 1) as *u8 37 } 38 k = k + 1 39 } 40 j = result + 1 41 while j <= maxn { if av[j] != 85 { ok = 0 } j = j + 1 } 42 } else { ok = 0 } } } 43 if av[0] != 85 { ok = 0 } 44 if av[maxn + 1] != 85 { ok = 0 } 45 if av[maxn + 2] != 85 { ok = 0 } 46 j = cap 47 while j < cap + 8 { if scratch[j] != (85 as u8) { ok = 0 }; j = j + 1 } 48 gv_check(label, ok, ctr) 49 return ok 50} 51 52// Frozen current-original loop is a test oracle for unchanged legacy modes, not a runtime decoder. 53func tug_original_ctl(buf: *u8, n: i64, vstart: i64, out: *u8, outcap: i64, keep_ctl: i64) -> i64 { 54 var i: i64 = vstart 55 var o: i64 = 0 56 while i < n { 57 let c: i64 = buf[i] as i64 58 if c == 92 { // backslash escape 59 if i + 1 < n { 60 var e: i64 = buf[i + 1] as i64 61 if e == 117 { // \uXXXX 62 var cp: i64 = jx_hex4(buf, n, i + 2) 63 if cp < 0 { 64 // malformed escape: emit nothing for it and step past the 'u' rather than 65 // re-emitting the digits as text (that is exactly the old corruption). 66 i = i + 2 67 } else { 68 var adv: i64 = 6 69 if cp >= 55296 { if cp < 56320 { // high surrogate D800-DBFF 70 if i + 7 < n { if (buf[i + 6] as i64) == 92 { if (buf[i + 7] as i64) == 117 { 71 let lo: i64 = jx_hex4(buf, n, i + 8) 72 if lo >= 56320 { if lo < 57344 { 73 cp = 65536 + ((cp - 55296) * 1024) + (lo - 56320) 74 adv = 12 75 } } 76 } } } 77 } } 78 if keep_ctl == 0 { 79 if cp == 9 { cp = 32 } 80 if cp == 10 { cp = 32 } 81 if cp == 13 { cp = 32 } 82 } 83 o = jx_emit_utf8(out, o, outcap, cp) 84 i = i + adv 85 } 86 } else { 87 if keep_ctl == 1 { 88 if e == 116 { e = 9 } // t -> TAB 89 if e == 110 { e = 10 } // n -> LF 90 if e == 114 { e = 13 } // r -> CR 91 if e == 98 { e = 8 } // b -> BS 92 if e == 102 { e = 12 } // f -> FF 93 } else { 94 if e == 116 { e = 32 } // t -> space 95 if e == 110 { e = 32 } // n -> space 96 if e == 114 { e = 32 } // r -> space 97 } 98 if o < outcap - 1 { out[o] = e as u8; o = o + 1 } 99 i = i + 2 100 } 101 } else { i = i + 1 } 102 } else { 103 if c == 34 { out[o] = 0 as u8; return i + 1 } // closing quote 104 var cc: i64 = c 105 if keep_ctl == 0 { 106 if cc == 9 { cc = 32 } 107 if cc == 10 { cc = 32 } 108 if cc == 13 { cc = 32 } 109 } 110 if o < outcap - 1 { out[o] = cc as u8; o = o + 1 } 111 i = i + 1 112 } 113 } 114 out[o] = 0 as u8 115 return 0 - 1 116} 117 118func tug_legacy(label: *u8, src: *u8, cap: i64, ctr: *i64) -> i64 { 119 let a: *u8 = sys_mmap(cap + 8); let b: *u8 = sys_mmap(cap + 8) 120 var mode: i64 = 0; var ok: i64 = 1 121 while mode <= 1 { 122 var j: i64 = 0 123 while j < cap + 8 { a[j] = 85 as u8; b[j] = 85 as u8; j = j + 1 } 124 let before: i64 = tug_original_ctl(src, jx_len(src), 0, a, cap, mode) 125 let after: i64 = jx_copy_str_ctl(src, jx_len(src), 0, b, cap, mode) 126 if before != after { ok = 0 } 127 j = 0 128 while j < cap + 8 { if a[j] != b[j] { ok = 0 } j = j + 1 } 129 mode = mode + 1 130 } 131 gv_check(label, ok, ctr); return ok 132} 133 134func main() -> i64 { 135 let ctr: *i64 = gv_ctr() 136 gv_head("TOOLS-ARGV-UNICODE" as *u8) 137 let eacute: *u8 = sys_mmap(3) 138 eacute[0] = 195 as u8; eacute[1] = 169 as u8; eacute[2] = 0 as u8 139 let euro: *u8 = sys_mmap(4) 140 euro[0] = 226 as u8; euro[1] = 130 as u8; euro[2] = 172 as u8; euro[3] = 0 as u8 141 let astral: *u8 = sys_mmap(5) 142 astral[0] = 240 as u8; astral[1] = 159 as u8; astral[2] = 152 as u8; astral[3] = 128 as u8; astral[4] = 0 as u8 143 let unicode: *u8 = sys_mmap(10) 144 var u: i64 = 0 145 while u < 2 { unicode[u] = eacute[u]; u = u + 1 } 146 u = 0 147 while u < 3 { unicode[2 + u] = euro[u]; u = u + 1 } 148 u = 0 149 while u < 4 { unicode[5 + u] = astral[u]; u = u + 1 } 150 unicode[9] = 0 as u8 151 let rawbody: *u8 = sys_mmap(32) 152 var rawlen: i64 = ta_cat(rawbody, 0, "{\"argv\":[\"" as *u8) 153 u = 0 154 while u < 9 { rawbody[rawlen + u] = unicode[u]; u = u + 1 } 155 rawlen = ta_cat(rawbody, rawlen + 9, "\"]}" as *u8) 156 rawbody[rawlen] = 0 as u8 157 let pair: *u8 = sys_mmap(4) 158 pair[0] = 97 as u8; pair[1] = 0 as u8; pair[2] = 98 as u8; pair[3] = 0 as u8 159 let controls: *u8 = sys_mmap(6) 160 controls[0] = 8 as u8; controls[1] = 12 as u8; controls[2] = 10 as u8 161 controls[3] = 13 as u8; controls[4] = 9 as u8; controls[5] = 0 as u8 162 tug_case("literal greater-than" as *u8, "{\"argv\":[\">\"]}" as *u8, 1, ">" as *u8, 64, 4, ctr) 163 tug_case("PowerShell Unicode escape exact" as *u8, "{\"argv\":[\"\\u003e\"]}" as *u8, 1, ">" as *u8, 64, 4, ctr) 164 tug_case("uppercase hex escape" as *u8, "{\"argv\":[\"\\u003E\"]}" as *u8, 1, ">" as *u8, 64, 4, ctr) 165 tug_case("BMP two-byte" as *u8, "{\"argv\":[\"\\u00e9\"]}" as *u8, 1, eacute, 64, 4, ctr) 166 tug_case("BMP three-byte" as *u8, "{\"argv\":[\"\\u20ac\"]}" as *u8, 1, euro, 64, 4, ctr) 167 tug_case("surrogate pair" as *u8, "{\"argv\":[\"\\uD83D\\uDE00\"]}" as *u8, 1, astral, 64, 4, ctr) 168 tug_case("literal UTF-8 unchanged" as *u8, rawbody, 1, unicode, 64, 4, ctr) 169 tug_case("isolated high surrogate refused" as *u8, "{\"argv\":[\"\\ud800\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 170 tug_case("isolated low surrogate refused" as *u8, "{\"argv\":[\"\\udc00\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 171 tug_case("wrong surrogate pair refused" as *u8, "{\"argv\":[\"\\ud800\\u0041\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 172 tug_case("invalid hex refused" as *u8, "{\"argv\":[\"\\u00xz\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 173 tug_case("short Unicode refused" as *u8, "{\"argv\":[\"\\u123\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 174 tug_case("unknown escape refused" as *u8, "{\"argv\":[\"\\q\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 175 tug_case("NUL escape refused" as *u8, "{\"argv\":[\"\\u0000\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 176 tug_case("escaped controls retained" as *u8, "{\"argv\":[\"\\b\\f\\n\\r\\t\"]}" as *u8, 1, controls, 64, 4, ctr) 177 tug_case("quote backslash slash retained" as *u8, "{\"argv\":[\"\\\"\\\\\\/\"]}" as *u8, 1, "\"\\/" as *u8, 64, 4, ctr) 178 tug_case("raw newline refused" as *u8, "{\"argv\":[\"a\nb\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 179 tug_case("scratch exact ASCII fit" as *u8, "{\"argv\":[\"abc\"]}" as *u8, 1, "abc" as *u8, 4, 4, ctr) 180 tug_case("scratch shortage refused" as *u8, "{\"argv\":[\"abc\"]}" as *u8, -1, "" as *u8, 3, 4, ctr) 181 tug_case("scratch exact astral fit" as *u8, "{\"argv\":[\"\\ud83d\\ude00\"]}" as *u8, 1, astral, 5, 4, ctr) 182 tug_case("scratch astral shortage refused" as *u8, "{\"argv\":[\"\\ud83d\\ude00\"]}" as *u8, -1, "" as *u8, 4, 4, ctr) 183 tug_case("empty argument exact fit" as *u8, "{\"argv\":[\"\"]}" as *u8, 1, "" as *u8, 1, 4, ctr) 184 tug_case("argument maximum exact" as *u8, "{\"argv\":[\"a\",\"b\"]}" as *u8, 2, pair, 64, 2, ctr) 185 tug_case("argument maximum exceeded" as *u8, "{\"argv\":[\"a\",\"b\",\"c\"]}" as *u8, -1, "" as *u8, 64, 2, ctr) 186 tug_case("empty array" as *u8, "{\"argv\":[]}" as *u8, 0, "" as *u8, 64, 4, ctr) 187 tug_case("absent array" as *u8, "{}" as *u8, 0, "" as *u8, 64, 4, ctr) 188 tug_case("nonarray refused" as *u8, "{\"argv\":\"a\"}" as *u8, -1, "" as *u8, 64, 4, ctr) 189 tug_case("nonstring member refused" as *u8, "{\"argv\":[1]}" as *u8, -1, "" as *u8, 64, 4, ctr) 190 tug_case("missing comma refused" as *u8, "{\"argv\":[\"a\" \"b\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 191 tug_case("trailing comma refused" as *u8, "{\"argv\":[\"a\",]}" as *u8, -1, "" as *u8, 64, 4, ctr) 192 tug_case("unterminated string refused" as *u8, "{\"argv\":[\"abc" as *u8, -1, "" as *u8, 64, 4, ctr) 193 tug_case("unterminated array refused" as *u8, "{\"argv\":[\"abc\"" as *u8, -1, "" as *u8, 64, 4, ctr) 194 tug_case("missing colon refused" as *u8, "{\"argv\"[\"abc\"]}" as *u8, -1, "" as *u8, 64, 4, ctr) 195 tug_case("whitespace syntax accepted" as *u8, "{\"argv\" \r\n : \t [ \"abc\" ]}" as *u8, 1, "abc" as *u8, 64, 4, ctr) 196 let src: *u8 = "a\\nb\"" as *u8 197 let out: *u8 = sys_mmap(32) 198 let tsv_end: i64 = jx_copy_str(src, jx_len(src), 0, out, 32) 199 gv_check("legacy TSV controls stay spaces" as *u8, out[1] == (32 as u8), ctr) 200 let raw_end: i64 = jx_copy_str_raw(src, jx_len(src), 0, out, 32) 201 gv_check("legacy raw controls stay newline" as *u8, out[1] == (10 as u8), ctr) 202 gv_check("legacy wrappers retain ending cursor" as *u8, tsv_end == raw_end, ctr) 203 // Invalid raw UTF-8 cannot be represented as a source string literal: inject exact bytes. 204 let bad: *u8 = sys_mmap(3) 205 bad[0] = 192 as u8; bad[1] = 128 as u8; bad[2] = 34 as u8 206 gv_check("overlong UTF-8 refused" as *u8, jx_copy_str_argv(bad, 3, 0, out, 32) < 0, ctr) 207 bad[0] = 237 as u8; bad[1] = 160 as u8; bad[2] = 128 as u8 208 gv_check("raw UTF-8 surrogate refused" as *u8, jx_copy_str_argv(bad, 3, 0, out, 32) < 0, ctr) 209 tug_legacy("legacy ASCII output/cursor" as *u8, "abc\"" as *u8, 16, ctr) 210 tug_legacy("legacy unknown escape behavior" as *u8, "\\q\"" as *u8, 16, ctr) 211 tug_legacy("legacy escaped controls behavior" as *u8, "\\b\\f\\n\\r\\t\"" as *u8, 16, ctr) 212 tug_legacy("legacy raw controls behavior" as *u8, "a\nb\rc\td\"" as *u8, 16, ctr) 213 tug_legacy("legacy Unicode BMP behavior" as *u8, "\\u00e9\\u20ac\"" as *u8, 16, ctr) 214 tug_legacy("legacy surrogate pair behavior" as *u8, "\\ud83d\\ude00\"" as *u8, 16, ctr) 215 tug_legacy("legacy lone surrogate behavior" as *u8, "\\ud800\"" as *u8, 16, ctr) 216 tug_legacy("legacy malformed Unicode behavior" as *u8, "\\u00xz\"" as *u8, 16, ctr) 217 tug_legacy("legacy output truncation behavior" as *u8, "abcdef\"" as *u8, 3, ctr) 218 tug_legacy("legacy Unicode truncation behavior" as *u8, "\\ud83d\\ude00x\"" as *u8, 3, ctr) 219 tug_legacy("legacy trailing backslash behavior" as *u8, "abc\\" as *u8, 16, ctr) 220 tug_legacy("legacy unterminated behavior" as *u8, "abc" as *u8, 16, ctr) 221 tug_legacy("legacy minimum capacity behavior" as *u8, "abc\"" as *u8, 1, ctr) 222 let rc: i64 = gv_verdict("TOOLS-ARGV-UNICODE" as *u8, ctr, "native argv preserves exact Unicode and escaped controls; malformed or truncated arguments are refused" as *u8) 223 sys_exit(rc); return rc 224}