code wiki / _hdl_build / nx_uiq_console_lib.nx
nx_uiq_console_lib.nx source
↩ module page · 489 lines · 19694 B
1// nx_uiq_console_lib.nx -- F106a console/error capture: the console-analog defect signal, COMPUTED.
2// SOTA ground truth (banked 07-21): console/CSP capture is the highest-ROI automated defect signal
3// (WAREX/CovAgent). For sovereign static surfaces the console-equivalent classes ARE computable
4// from source, deterministically, no fakes:
5// ERRORS: var_undef var(--x) used, never defined, no fallback -> invalid property value
6// dup_id duplicate id= -> broken fragment/aria targets
7// dead_frag href="#x" with no matching id= in the page
8// mixed src="http://..." or <link href="http://..."> on an https page
9// empty_src src="" -> the browser fetches the page itself
10// tag_imbalance unclosed container tag (div/section/table/... open!=close)
11// WARNINGS: var_undef_fb (undefined but fallback saves it) img_noalt (a11y console class) empty_href
12// HONEST ENVELOPE (declared in output): static source scan; <script> BODIES are masked before the
13// HTML-structure scans; lowercase html; CSS-defined custom properties only (JS setProperty unseen);
14// space-separated attributes. Runtime JS errors / real CSP reports need a JS engine = browser-lane,
15// NOT faked here. license_tier: ORIGINAL genealogy: F106a experiential; family nx_uiq_color/contrast/perf
16import "nx_uiq_color.nx"
17
18const CS_CAP_BUF: i64 = 1048576
19const CS_CAP_IDS: i64 = 1024
20const CS_CAP_DETAIL: i64 = 48
21const CS_FIX_FAIL: *u8 = "<html><body><style>:root{--ok:#fff}.a{color:var(--miss)}.b{color:var(--gone,#000)}.c{color:var(--ok)}</style><div id=\"d1\"></div><div id=\"d1\"></div><a href=\"#nope\">x</a><a href=\"#d1\">y</a><a href=\"\">z</a><img src=\"x.png\"><img src=\"y.png\" alt=\"y\"><script src=\"http://x.js\"></script><img src=\"\" alt=\"e\"><div><span>s</span></body></html>" as *u8
22const CS_FIX_PASS: *u8 = "<html><body><style>:root{--ok:#111}.a{color:var(--ok)}</style><div id=\"a\"></div><a href=\"#a\">x</a><img src=\"i.png\" alt=\"i\"><script>let v=1</script><i>var(--)</i></body></html>" as *u8
23const CS_FIX_LIAR: *u8 = "<html><body><style>:root{--ok:#111}.a{color:var(--ok)}</style><div id=\"a\"></div><a href=\"#a\">x</a><img src=\"i.png\" alt=\"i\"><script>let v=1</script><b style=\"color:var(--nope)\">q</b></body></html>" as *u8
24const CS_FIX_MASK: *u8 = "<script>let s='<div id=\"q\">'</script><div></div>" as *u8
25
26static g_doff: *i64
27static g_dlen: *i64
28static g_dcls: *i64
29static g_dn: i64
30static g_dcapped: i64
31static g_cls: *i64
32
33func cs_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8) { n=n+1 } return n }
34
35func cs_namec(c: i64) -> i64 {
36 if c>=97 { if c<=122 { return 1 } }
37 if c>=65 { if c<=90 { return 1 } }
38 if c>=48 { if c<=57 { return 1 } }
39 if c==45 { return 1 }
40 if c==95 { return 1 }
41 return 0
42}
43
44func cs_find_from(buf: *u8, n: i64, start: i64, pat: *u8) -> i64 {
45 var pl: i64=0
46 while pat[pl]!=(0 as u8) { pl=pl+1 }
47 if pl==0 { return 0-1 }
48 var i: i64=start
49 if i<0 { i=0 }
50 var res: i64=0-1
51 var done: i64=0
52 while done==0 {
53 if i+pl>n { done=1 } else {
54 var k: i64=0
55 var ok: i64=1
56 while k<pl { let bc: i64=buf[i+k] as i64; let pc: i64=pat[k] as i64; if bc!=pc { ok=0; k=pl } else { k=k+1 } }
57 if ok==1 { res=i; done=1 } else { i=i+1 }
58 }
59 }
60 return res
61}
62
63func cs_span_eq(buf: *u8, o1: i64, l1: i64, o2: i64, l2: i64) -> i64 {
64 if l1!=l2 { return 0 }
65 var k: i64=0
66 while k<l1 { let a: i64=buf[o1+k] as i64; let b: i64=buf[o2+k] as i64; if a!=b { return 0 } k=k+1 }
67 return 1
68}
69
70// detail accumulator: class id + a (off,len) span into the AUDITED buffer. Capped, cap declared.
71func cs_detail(cls: i64, off: i64, len: i64) -> i64 {
72 let dn: i64 = g_dn
73 if dn>=CS_CAP_DETAIL { g_dcapped=1; return 0 }
74 let po: *i64 = g_doff
75 let pl: *i64 = g_dlen
76 let pc: *i64 = g_dcls
77 po[dn]=off
78 pl[dn]=len
79 pc[dn]=cls
80 g_dn=dn+1
81 return 0
82}
83
84// copy src->dst and blank <script>...</script> BODIES (tags kept) so HTML-in-JS-strings
85// never miscounts the structure scans.
86func cs_mask_scripts(src: *u8, n: i64, dst: *u8) -> i64 {
87 var i: i64=0
88 while i<n { dst[i]=src[i]; i=i+1 }
89 var off: i64=0
90 var done: i64=0
91 while done==0 {
92 let so: i64 = cs_find_from(dst, n, off, "<script" as *u8)
93 if so<0 { done=1 } else {
94 var j: i64=so
95 var g: i64=0-1
96 var d2: i64=0
97 while d2==0 { if j>=n { d2=1 } else { let c: i64=dst[j] as i64; if c==62 { g=j; d2=1 } else { j=j+1 } } }
98 if g<0 { done=1 } else {
99 let ce: i64 = cs_find_from(dst, n, g+1, "</script" as *u8)
100 if ce<0 { done=1 } else {
101 var b: i64=g+1
102 while b<ce { dst[b]=(32 as u8); b=b+1 }
103 off=ce+8
104 }
105 }
106 }
107 }
108 return 0
109}
110
111// does a DEFINITION site "--name :" exist anywhere? (use sites are followed by ')' or ',')
112func cs_has_def(buf: *u8, n: i64, noff: i64, nlen: i64) -> i64 {
113 var off: i64=0
114 var res: i64=0
115 var done: i64=0
116 while done==0 {
117 let o: i64 = cs_find_from(buf, n, off, "--" as *u8)
118 if o<0 { done=1 } else {
119 var e: i64=o+2
120 var d2: i64=0
121 while d2==0 { if e>=n { d2=1 } else { let c: i64=buf[e] as i64; let isn: i64=cs_namec(c); if isn==1 { e=e+1 } else { d2=1 } } }
122 let sl: i64=e-o
123 let same: i64 = cs_span_eq(buf, o, sl, noff, nlen)
124 if same==1 {
125 var j: i64=e
126 var d3: i64=0
127 while d3==0 { if j>=n { d3=1 } else { let c2: i64=buf[j] as i64; if c2==32 || c2==9 || c2==10 || c2==13 { j=j+1 } else { d3=1 } } }
128 if j<n { let c3: i64=buf[j] as i64; if c3==58 { res=1; done=1 } }
129 }
130 if done==0 { off=o+2 }
131 }
132 }
133 return res
134}
135
136// cnt[0]=var_undef (error) cnt[1]=var_undef_fb (warning). Scans the FULL buffer (CSS lives everywhere).
137func cs_scan_vars(buf: *u8, n: i64, cnt: *i64) -> i64 {
138 var off: i64=0
139 var done: i64=0
140 while done==0 {
141 let o: i64 = cs_find_from(buf, n, off, "var(--" as *u8)
142 if o<0 { done=1 } else {
143 let ns: i64=o+4
144 var e: i64=ns+2
145 var d2: i64=0
146 while d2==0 { if e>=n { d2=1 } else { let c: i64=buf[e] as i64; let isn: i64=cs_namec(c); if isn==1 { e=e+1 } else { d2=1 } } }
147 let nl: i64=e-ns
148 var j: i64=e
149 var d3: i64=0
150 while d3==0 { if j>=n { d3=1 } else { let c2: i64=buf[j] as i64; if c2==32 { j=j+1 } else { d3=1 } } }
151 var fb: i64=0
152 if j<n { let c3: i64=buf[j] as i64; if c3==44 { fb=1 } }
153 var hd: i64 = 1
154 if nl>2 { hd = cs_has_def(buf, n, ns, nl) }
155 if hd==0 {
156 if fb==1 { cnt[1]=cnt[1]+1; cs_detail(2,ns,nl) } else { cnt[0]=cnt[0]+1; cs_detail(1,ns,nl) }
157 }
158 off=o+6
159 }
160 }
161 return 0
162}
163
164// collect unique ids; each RE-occurrence of a seen id counts as one dup error. Returns unique count.
165func cs_scan_ids(buf: *u8, n: i64, ioff: *i64, ilen: *i64, cap: i64, dupout: *i64) -> i64 {
166 var off: i64=0
167 var un: i64=0
168 var done: i64=0
169 while done==0 {
170 let o: i64 = cs_find_from(buf, n, off, " id=\"" as *u8)
171 if o<0 { done=1 } else {
172 let vs: i64=o+5
173 var e: i64=vs
174 var d2: i64=0
175 while d2==0 { if e>=n { d2=1 } else { let c: i64=buf[e] as i64; if c==34 { d2=1 } else { e=e+1 } } }
176 let vl: i64=e-vs
177 var isdup: i64=0
178 var u: i64=0
179 while u<un { let sm: i64 = cs_span_eq(buf, ioff[u], ilen[u], vs, vl); if sm==1 { isdup=1; u=un } else { u=u+1 } }
180 if isdup==1 { dupout[0]=dupout[0]+1; cs_detail(4,vs,vl) } else { if un<cap { ioff[un]=vs; ilen[un]=vl; un=un+1 } }
181 off=e+1
182 }
183 }
184 return un
185}
186
187func cs_scan_frags(buf: *u8, n: i64, ioff: *i64, ilen: *i64, un: i64, cnt: *i64) -> i64 {
188 var off: i64=0
189 var done: i64=0
190 while done==0 {
191 let o: i64 = cs_find_from(buf, n, off, "href=\"#" as *u8)
192 if o<0 { done=1 } else {
193 let fs: i64=o+7
194 var e: i64=fs
195 var d2: i64=0
196 while d2==0 { if e>=n { d2=1 } else { let c: i64=buf[e] as i64; if c==34 { d2=1 } else { e=e+1 } } }
197 let fl: i64=e-fs
198 if fl>0 {
199 var found: i64=0
200 var u: i64=0
201 while u<un { let sm: i64 = cs_span_eq(buf, ioff[u], ilen[u], fs, fl); if sm==1 { found=1; u=un } else { u=u+1 } }
202 if found==0 { cnt[0]=cnt[0]+1; cs_detail(3,fs,fl) }
203 }
204 off=e+1
205 }
206 }
207 return 0
208}
209
210func cs_scan_imgs(buf: *u8, n: i64, cnt: *i64) -> i64 {
211 var off: i64=0
212 var done: i64=0
213 while done==0 {
214 let o: i64 = cs_find_from(buf, n, off, "<img" as *u8)
215 if o<0 { done=1 } else {
216 var j: i64=o
217 var g: i64=0-1
218 var d2: i64=0
219 while d2==0 { if j>=n { d2=1 } else { let c: i64=buf[j] as i64; if c==62 { g=j; d2=1 } else { j=j+1 } } }
220 if g<0 { done=1 } else {
221 let ao: i64 = cs_find_from(buf, g, o, " alt=" as *u8)
222 if ao<0 { cnt[0]=cnt[0]+1; cs_detail(5,o+1,3) }
223 off=g+1
224 }
225 }
226 }
227 return 0
228}
229
230func cs_scan_mixed(buf: *u8, n: i64, cnt: *i64) -> i64 {
231 var off: i64=0
232 var done: i64=0
233 while done==0 {
234 let o: i64 = cs_find_from(buf, n, off, "src=\"http://" as *u8)
235 if o<0 { done=1 } else { cnt[0]=cnt[0]+1; cs_detail(6,o+5,7); off=o+12 }
236 }
237 var off2: i64=0
238 var d2: i64=0
239 while d2==0 {
240 let lo: i64 = cs_find_from(buf, n, off2, "<link" as *u8)
241 if lo<0 { d2=1 } else {
242 var j: i64=lo
243 var g: i64=0-1
244 var d3: i64=0
245 while d3==0 { if j>=n { d3=1 } else { let c: i64=buf[j] as i64; if c==62 { g=j; d3=1 } else { j=j+1 } } }
246 if g<0 { d2=1 } else {
247 let ho: i64 = cs_find_from(buf, g, lo, "href=\"http://" as *u8)
248 if ho>=0 { cnt[0]=cnt[0]+1; cs_detail(6,ho+6,7) }
249 off2=g+1
250 }
251 }
252 }
253 return 0
254}
255
256func cs_scan_empty(buf: *u8, n: i64, errc: *i64, warnc: *i64) -> i64 {
257 var off: i64=0
258 var done: i64=0
259 while done==0 {
260 let o: i64 = cs_find_from(buf, n, off, "src=\"\"" as *u8)
261 if o<0 { done=1 } else { errc[0]=errc[0]+1; cs_detail(7,o,3); off=o+6 }
262 }
263 var off2: i64=0
264 var d2: i64=0
265 while d2==0 {
266 let o2: i64 = cs_find_from(buf, n, off2, "href=\"\"" as *u8)
267 if o2<0 { d2=1 } else { warnc[0]=warnc[0]+1; cs_detail(7,o2,4); off2=o2+7 }
268 }
269 return 0
270}
271
272// count occurrences; nb=1 requires the char AFTER the pattern to be a non-name char (word boundary
273// for open tags); nb=0 counts verbatim (close tags end in '>').
274func cs_count_pat(buf: *u8, n: i64, pat: *u8, nb: i64) -> i64 {
275 var pl: i64=0
276 while pat[pl]!=(0 as u8) { pl=pl+1 }
277 var cv: i64=0
278 var off: i64=0
279 var done: i64=0
280 while done==0 {
281 let o: i64 = cs_find_from(buf, n, off, pat)
282 if o<0 { done=1 } else {
283 var good: i64=1
284 if nb==1 { let nxc: i64=o+pl; if nxc<n { let c: i64=buf[nxc] as i64; let isn: i64=cs_namec(c); if isn==1 { good=0 } } }
285 if good==1 { cv=cv+1 }
286 off=o+pl
287 }
288 }
289 return cv
290}
291
292// one container tag: returns 1 if open!=close; emit=1 prints a JSON row (comma-managed via first[0])
293func cs_tagpair(mk: *u8, n: i64, opat: *u8, cpat: *u8, name: *u8, emit: i64, first: *i64) -> i64 {
294 let oc: i64 = cs_count_pat(mk, n, opat, 1)
295 let cc: i64 = cs_count_pat(mk, n, cpat, 0)
296 if oc==cc { return 0 }
297 if emit==1 {
298 if first[0]==1 { first[0]=0 } else { uiq_w("," as *u8) }
299 uiq_w("{\"t\":\"" as *u8)
300 uiq_w(name)
301 uiq_w("\",\"open\":" as *u8)
302 uiq_pn(oc)
303 uiq_w(",\"close\":" as *u8)
304 uiq_pn(cc)
305 uiq_w("}" as *u8)
306 }
307 return 1
308}
309
310func cs_clsname(c: i64) -> i64 {
311 if c==1 { uiq_w("var_undef" as *u8); return 0 }
312 if c==2 { uiq_w("var_undef_fb" as *u8); return 0 }
313 if c==3 { uiq_w("dead_frag" as *u8); return 0 }
314 if c==4 { uiq_w("dup_id" as *u8); return 0 }
315 if c==5 { uiq_w("img_noalt" as *u8); return 0 }
316 if c==6 { uiq_w("mixed" as *u8); return 0 }
317 if c==7 { uiq_w("empty_ref" as *u8); return 0 }
318 uiq_w("tag" as *u8)
319 return 0
320}
321
322// the audit: returns ERROR count; fills g_cls[0..8] =
323// var_undef, var_undef_fb, dup_id, dead_frag, img_noalt, mixed, empty_src, empty_href, tag_imbalance
324func cs_audit_buf(buf: *u8, n: i64, emit: i64) -> i64 {
325 if (g_doff as i64)==0 { g_doff = sys_mmap(CS_CAP_DETAIL*8) as *i64 }
326 if (g_dlen as i64)==0 { g_dlen = sys_mmap(CS_CAP_DETAIL*8) as *i64 }
327 if (g_dcls as i64)==0 { g_dcls = sys_mmap(CS_CAP_DETAIL*8) as *i64 }
328 if (g_cls as i64)==0 { g_cls = sys_mmap(96) as *i64 }
329 g_dn=0
330 g_dcapped=0
331 let mk: *u8 = sys_mmap(n+16)
332 cs_mask_scripts(buf, n, mk)
333 let vc: *i64 = sys_mmap(32) as *i64
334 cs_scan_vars(buf, n, vc)
335 let ioff: *i64 = sys_mmap(CS_CAP_IDS*8) as *i64
336 let ilen: *i64 = sys_mmap(CS_CAP_IDS*8) as *i64
337 let dup: *i64 = sys_mmap(16) as *i64
338 let un: i64 = cs_scan_ids(mk, n, ioff, ilen, CS_CAP_IDS, dup)
339 let fragc: *i64 = sys_mmap(16) as *i64
340 cs_scan_frags(mk, n, ioff, ilen, un, fragc)
341 let imgc: *i64 = sys_mmap(16) as *i64
342 cs_scan_imgs(mk, n, imgc)
343 let mixc: *i64 = sys_mmap(16) as *i64
344 cs_scan_mixed(mk, n, mixc)
345 let eref: *i64 = sys_mmap(16) as *i64
346 let wref: *i64 = sys_mmap(16) as *i64
347 cs_scan_empty(mk, n, eref, wref)
348 let fdum: *i64 = sys_mmap(16) as *i64
349 fdum[0]=1
350 var tagbad: i64=0
351 tagbad = tagbad + cs_tagpair(mk,n,"<div" as *u8,"</div>" as *u8,"div" as *u8,0,fdum)
352 tagbad = tagbad + cs_tagpair(mk,n,"<section" as *u8,"</section>" as *u8,"section" as *u8,0,fdum)
353 tagbad = tagbad + cs_tagpair(mk,n,"<article" as *u8,"</article>" as *u8,"article" as *u8,0,fdum)
354 tagbad = tagbad + cs_tagpair(mk,n,"<main" as *u8,"</main>" as *u8,"main" as *u8,0,fdum)
355 tagbad = tagbad + cs_tagpair(mk,n,"<nav" as *u8,"</nav>" as *u8,"nav" as *u8,0,fdum)
356 tagbad = tagbad + cs_tagpair(mk,n,"<header" as *u8,"</header>" as *u8,"header" as *u8,0,fdum)
357 tagbad = tagbad + cs_tagpair(mk,n,"<footer" as *u8,"</footer>" as *u8,"footer" as *u8,0,fdum)
358 tagbad = tagbad + cs_tagpair(mk,n,"<table" as *u8,"</table>" as *u8,"table" as *u8,0,fdum)
359 tagbad = tagbad + cs_tagpair(mk,n,"<ul" as *u8,"</ul>" as *u8,"ul" as *u8,0,fdum)
360 tagbad = tagbad + cs_tagpair(mk,n,"<ol" as *u8,"</ol>" as *u8,"ol" as *u8,0,fdum)
361 tagbad = tagbad + cs_tagpair(mk,n,"<span" as *u8,"</span>" as *u8,"span" as *u8,0,fdum)
362 let gc: *i64 = g_cls
363 gc[0]=vc[0]
364 gc[1]=vc[1]
365 gc[2]=dup[0]
366 gc[3]=fragc[0]
367 gc[4]=imgc[0]
368 gc[5]=mixc[0]
369 gc[6]=eref[0]
370 gc[7]=wref[0]
371 gc[8]=tagbad
372 var errs: i64 = vc[0]+dup[0]+fragc[0]
373 errs = errs+mixc[0]+eref[0]+tagbad
374 var warns: i64 = vc[1]+imgc[0]+wref[0]
375 if emit==1 {
376 uiq_w("{\"organ\":\"nx_uiq_console\",\"classes\":{\"var_undef\":" as *u8)
377 uiq_pn(vc[0])
378 uiq_w(",\"var_undef_fb\":" as *u8)
379 uiq_pn(vc[1])
380 uiq_w(",\"dup_id\":" as *u8)
381 uiq_pn(dup[0])
382 uiq_w(",\"dead_frag\":" as *u8)
383 uiq_pn(fragc[0])
384 uiq_w(",\"img_noalt\":" as *u8)
385 uiq_pn(imgc[0])
386 uiq_w(",\"mixed\":" as *u8)
387 uiq_pn(mixc[0])
388 uiq_w(",\"empty_src\":" as *u8)
389 uiq_pn(eref[0])
390 uiq_w(",\"empty_href\":" as *u8)
391 uiq_pn(wref[0])
392 uiq_w(",\"tag_imbalance\":" as *u8)
393 uiq_pn(tagbad)
394 uiq_w("},\"tags\":[" as *u8)
395 let ftag: *i64 = sys_mmap(16) as *i64
396 ftag[0]=1
397 var du: i64=0
398 du = cs_tagpair(mk,n,"<div" as *u8,"</div>" as *u8,"div" as *u8,1,ftag)
399 du = cs_tagpair(mk,n,"<section" as *u8,"</section>" as *u8,"section" as *u8,1,ftag)
400 du = cs_tagpair(mk,n,"<article" as *u8,"</article>" as *u8,"article" as *u8,1,ftag)
401 du = cs_tagpair(mk,n,"<main" as *u8,"</main>" as *u8,"main" as *u8,1,ftag)
402 du = cs_tagpair(mk,n,"<nav" as *u8,"</nav>" as *u8,"nav" as *u8,1,ftag)
403 du = cs_tagpair(mk,n,"<header" as *u8,"</header>" as *u8,"header" as *u8,1,ftag)
404 du = cs_tagpair(mk,n,"<footer" as *u8,"</footer>" as *u8,"footer" as *u8,1,ftag)
405 du = cs_tagpair(mk,n,"<table" as *u8,"</table>" as *u8,"table" as *u8,1,ftag)
406 du = cs_tagpair(mk,n,"<ul" as *u8,"</ul>" as *u8,"ul" as *u8,1,ftag)
407 du = cs_tagpair(mk,n,"<ol" as *u8,"</ol>" as *u8,"ol" as *u8,1,ftag)
408 du = cs_tagpair(mk,n,"<span" as *u8,"</span>" as *u8,"span" as *u8,1,ftag)
409 uiq_w("],\"detail\":[" as *u8)
410 let dn2: i64 = g_dn
411 let po: *i64 = g_doff
412 let pl: *i64 = g_dlen
413 let pc: *i64 = g_dcls
414 var d: i64=0
415 while d<dn2 {
416 if d>0 { uiq_w("," as *u8) }
417 uiq_w("{\"c\":\"" as *u8)
418 let cid: i64 = pc[d]
419 cs_clsname(cid)
420 uiq_w("\",\"n\":\"" as *u8)
421 let doo: i64 = po[d]
422 let dll: i64 = pl[d]
423 uiq_wslice(buf, doo, dll)
424 uiq_w("\"}" as *u8)
425 d=d+1
426 }
427 uiq_w("],\"detail_capped\":" as *u8)
428 uiq_pn(g_dcapped)
429 uiq_w(",\"ids\":" as *u8)
430 uiq_pn(un)
431 uiq_w(",\"errors\":" as *u8)
432 uiq_pn(errs)
433 uiq_w(",\"warnings\":" as *u8)
434 uiq_pn(warns)
435 uiq_w(",\"verdict\":\"" as *u8)
436 if errs==0 { uiq_w("PASS" as *u8) } else { uiq_w("FAIL" as *u8) }
437 uiq_w("\",\"env\":\"static-source-scan;script-bodies-masked;lowercase-html;css-defined-tokens-only;empty-name-var-ignored;space-separated-attrs;detail-cap-48;families=console:mixed+empty_src|validator:tag_imbalance+dup_id|a11y:img_noalt+dead_frag+empty_href|computed-style:var_undef+var_undef_fb;chrome-console-calibrated-2026-07-23\"}" as *u8)
438 uiq_w("\n" as *u8)
439 }
440 return errs
441}
442
443func cs_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
444 let fd: i64 = sys_openat_rd(path)
445 if fd<0 { return 0 }
446 var total: i64=0
447 var nrd: i64=sys_read(fd, buf, cap)
448 while nrd>0 { total=total+nrd; if total>=cap { nrd=0 } else { nrd=sys_read(fd, ((buf as i64)+total) as *u8, cap-total) } }
449 sys_close(fd)
450 return total
451}
452
453// selftest: exact per-class counts on the FAIL fixture, clean PASS, liar-kill, mask tooth.
454// Returns failed-check count (0 = GREEN). Shared by nx_uiq_console --kat and the gate.
455func cs_selftest() -> i64 {
456 var f: i64=0
457 let ff: *u8 = CS_FIX_FAIL
458 let fl: i64 = cs_len(ff)
459 let er: i64 = cs_audit_buf(ff, fl, 0)
460 if er!=6 { f=f+1 }
461 let g: *i64 = g_cls
462 if g[0]!=1 { f=f+1 }
463 if g[1]!=1 { f=f+1 }
464 if g[2]!=1 { f=f+1 }
465 if g[3]!=1 { f=f+1 }
466 if g[4]!=1 { f=f+1 }
467 if g[5]!=1 { f=f+1 }
468 if g[6]!=1 { f=f+1 }
469 if g[7]!=1 { f=f+1 }
470 if g[8]!=1 { f=f+1 }
471 let fp: *u8 = CS_FIX_PASS
472 let pl2: i64 = cs_len(fp)
473 let ep: i64 = cs_audit_buf(fp, pl2, 0)
474 if ep!=0 { f=f+1 }
475 let gw: *i64 = g_cls
476 var wsum: i64 = gw[1]+gw[4]+gw[7]
477 if wsum!=0 { f=f+1 }
478 let lr: *u8 = CS_FIX_LIAR
479 let ll: i64 = cs_len(lr)
480 let el: i64 = cs_audit_buf(lr, ll, 0)
481 if el!=1 { f=f+1 }
482 let gl: *i64 = g_cls
483 if gl[0]!=1 { f=f+1 }
484 let mk2: *u8 = CS_FIX_MASK
485 let ml: i64 = cs_len(mk2)
486 let em: i64 = cs_audit_buf(mk2, ml, 0)
487 if em!=0 { f=f+1 }
488 return f
489}