nx_hex_dump.nx source
↩ module page · 133 lines · 3967 B
1// nx_hex_dump.nx -- bits-up hex+ASCII dump of a byte buffer to an fd.
2//
3// Replaces external tools (xxd, hexdump, hd) with a native NishiLang
4// primitive. Substrate diagnostics MUST use bits-up tools per
5// [[feedback-no-third-party-in-build-path-source-of-truth-is-bits-up]];
6// if reaching for Wireshark/xxd would diagnose the bug, the
7// substrate needs that capability natively.
8//
9// Output format (16 bytes per line):
10// 00000000 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e |https://example.|
11//
12// API:
13// nx_hex_dump_to_fd(fd, label, label_len, bytes, len) -- emit
14// labeled dump on fd (stderr is fd 2). label/label_len may be
15// 0/0 for no label. Returns 0.
16//
17// Per Cardinals 9 (single-responsibility -- one diagnostic primitive),
18// 22 (composition over configuration -- callers choose fd).
19//
20// license_tier: ORIGINAL
21// lineage_id: nishi_hex_dump_q10
22
23import "nx_syscalls.nx"
24
25func _hexnib(v: i64) -> i64 {
26 if v < 10 { return 0x30 + v }
27 return 0x61 + (v - 10)
28}
29
30func _emit_offset(fd: i64, off: i64) -> i64 {
31 let buf: *u8 = sys_mmap(16)
32 var i: i64 = 7
33 var v: i64 = off
34 while i >= 0 {
35 buf[i] = _hexnib(v & 0xf) as u8
36 v = v >> 4
37 i = i - 1
38 }
39 buf[8] = 0x20; buf[9] = 0x20
40 sys_write(fd, buf, 10)
41 return 0
42}
43
44// Emit one line: 16 bytes starting at off, padded with spaces if the
45// line is short. Each byte = "XX " (3 chars), with an extra space
46// between groups of 8.
47func _emit_line(fd: i64, bytes: *u8, off: i64, total: i64) -> i64 {
48 _emit_offset(fd, off)
49
50 // Hex section: 16 bytes, "XX " each + extra space after byte 7.
51 let hexbuf: *u8 = sys_mmap(64)
52 var i: i64 = 0
53 var pos: i64 = 0
54 while i < 16 {
55 if off + i < total {
56 let b: i64 = bytes[off + i] & 0xff
57 hexbuf[pos] = _hexnib((b >> 4) & 0xf) as u8
58 hexbuf[pos + 1] = _hexnib(b & 0xf) as u8
59 } else {
60 hexbuf[pos] = 0x20
61 hexbuf[pos + 1] = 0x20
62 }
63 hexbuf[pos + 2] = 0x20
64 pos = pos + 3
65 if i == 7 { hexbuf[pos] = 0x20; pos = pos + 1 }
66 i = i + 1
67 }
68 hexbuf[pos] = 0x7C // '|'
69 pos = pos + 1
70 sys_write(fd, hexbuf, pos)
71
72 // ASCII gutter
73 let asc: *u8 = sys_mmap(32)
74 var ap: i64 = 0
75 i = 0
76 while i < 16 {
77 if off + i < total {
78 let b: i64 = bytes[off + i] & 0xff
79 if b < 0x20 { asc[ap] = 0x2E }
80 else { if b > 0x7e { asc[ap] = 0x2E } else { asc[ap] = b as u8 } }
81 } else {
82 asc[ap] = 0x20
83 }
84 ap = ap + 1
85 i = i + 1
86 }
87 asc[ap] = 0x7C // '|'
88 asc[ap + 1] = 0x0A // newline
89 sys_write(fd, asc, ap + 2)
90 return 0
91}
92
93// Public API. Emits an optional label header line followed by a
94// canonical xxd-style hex+ASCII dump of bytes[0..len).
95func nx_hex_dump_to_fd(fd: i64, label: *u8, label_len: i64,
96 bytes: *u8, len: i64) -> i64 {
97 if label_len > 0 {
98 sys_write(fd, label, label_len)
99 let arrow: *u8 = sys_mmap(8)
100 arrow[0]=0x20; arrow[1]=0x28; arrow[2]=0x6C; arrow[3]=0x65
101 arrow[4]=0x6E; arrow[5]=0x3D
102 sys_write(fd, arrow, 6)
103 // Length as decimal
104 let lbuf: *u8 = sys_mmap(16)
105 var pos: i64 = 0
106 var x: i64 = len
107 if x == 0 { lbuf[0] = 0x30; pos = 1 }
108 while x > 0 {
109 lbuf[pos] = (0x30 + (x % 10)) as u8
110 x = x / 10
111 pos = pos + 1
112 }
113 // Reverse
114 let lout: *u8 = sys_mmap(16)
115 var li: i64 = 0
116 while li < pos { lout[li] = lbuf[pos - 1 - li]; li = li + 1 }
117 sys_write(fd, lout, pos)
118 let tail: *u8 = sys_mmap(8)
119 tail[0] = 0x29; tail[1] = 0x0A
120 sys_write(fd, tail, 2)
121 }
122
123 var off: i64 = 0
124 while off < len {
125 _emit_line(fd, bytes, off, len)
126 off = off + 16
127 }
128 return 0
129}
130
131func main() -> i64 {
132 return 0
133}