code wiki / (root) / nx_imgattr_lib.nx

nx_imgattr_lib.nx

buildroot/runtime/nx_imgattr_lib.nx

19397 B481 linesdepth 2pulls 2 transitivereach 60 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_imgattr_lib.nx -- THE ONE PLACE THAT DECIDES HOW AN <img> IS WRITTEN, AND THE ONE PLACE THAT READS ONE BACK. MEASURED 2026-08-26 ON OUR OWN HEADLINE SURFACE, served live at /compare/koikatsu: <img src='/compare/koikatsu/native_kk396262.png' alt='The card's own portrait -- the oracle we match against' loading='lazy'> The apostrophe came straight out of the .gallery caption DATA and was written raw into a single-quoted attribute. Every real HTML parser ends alt at the two words -The card-, reads the remainder as bogus attribute names, and the stray quote then swallows loading='lazy' as well. The accessible name of that image is -The card-, and the browser hint that keeps 14 large PNGs off the critical path is gone. AND THE PAGE STILL VALIDATED GREEN. nx_page_verify's a11y check counts the byte pattern - alt=- over the whole page and read 15 with-alt of 15 img. A SUBSTRING COUNTER CANNOT SEE ATTRIBUTE SCOPE, so the emitter's defect and the ruler's blindness are ONE defect met twice -- and the ruler's blindness is the half that let it ship and stay shipped. SO THE WRITER AND THE READER LIVE IN ONE LIB. The function that WRITES an img and the function that CHECKS an img share one definition of -an img with a usable alt-, and disagreement between them is impossible by construction rather than by discipline. THE INCUMBENT WAS EXTENDED, NOT DUPLICATED. nx_adnet_slot's aslot_cat_esc is the estate's existing attribute escaper and its lit-flag shape is kept here verbatim. It is changed in exactly one direction: it replaces an apostrophe with a SPACE, which is lossy -- -The card's- becomes -The card s- -- and rule 25 says rewrite it better rather than strip it, so this escaper emits the numeric character reference and KEEPS the byte. NO GUESSED CEILING LIVES HERE. Every buffer this lib fills is sized by the caller from the strings the caller already holds (ia_alt_cap_for / ia_img_cap_for), so there is no bound to tune in either direction and none can silently truncate. The guards remain and ANNOUNCE, for a caller that sizes its own buffer wrong. DECLARED IMPRECISION, so the next reader does not trust this as exact: ia_scan is a LEXICAL scan. It skips comments, script and style bodies, so markup quoted inside those cannot be miscounted, but it does not build a tree -- an img inside a CDATA section or produced by script at runtime is outside what it can see, and it reports on the bytes as served. license_tier: ORIGINAL

dependencies 1 imports · 12 importers

nx_syscalls.nx nx_imgattr_lib.nx nx_compare_shared_fit_lib_20260910 nx_imgattr_lib_gate.nx nx_models_page_emit.nx nx_page_verify.nx nx_swcompare_evidence_lib_t138.nx nx_swcompare_growth_candidate_2026 nx_swcompare_heading_lib_20260907. nx_swcompare_ladder_candidate.nx nx_swcompare_lib.nx nx_swcompare_preview_lib_t56.nx

diagram shows first 10 each side; +0 more imports, +2 more importers in the complete lists below.

imports: nx_syscalls.nx

imported by: nx_compare_shared_fit_lib_20260910.nxnx_imgattr_lib_gate.nxnx_models_page_emit.nxnx_page_verify.nxnx_swcompare_evidence_lib_t138.nxnx_swcompare_growth_candidate_20260910.nxnx_swcompare_heading_lib_20260907.nxnx_swcompare_ladder_candidate.nxnx_swcompare_lib.nxnx_swcompare_preview_lib_t56.nxnx_swcompare_production_lib_20260907.nxnx_swcompare_release_candidate.nx

structs

none

consts

42const IA_TAB: i64 = 9
43const IA_LF: i64 = 10
44const IA_CR: i64 = 13
45const IA_SP: i64 = 32
46const IA_DQ: i64 = 34
47const IA_HASH: i64 = 35
48const IA_AMP: i64 = 38
49const IA_SQ: i64 = 39
50const IA_HYPHEN: i64 = 45
51const IA_DOT: i64 = 46
52const IA_SLASH: i64 = 47
53const IA_DIGIT_3: i64 = 51
54const IA_DIGIT_9: i64 = 57
55const IA_SEMI: i64 = 59
56const IA_LT: i64 = 60
57const IA_EQ: i64 = 61
58const IA_GT: i64 = 62
59const IA_UPPER_A: i64 = 65
60const IA_UPPER_Z: i64 = 90
61const IA_USCORE: i64 = 95
62const IA_CASE_DELTA: i64 = 32
66const IA_MAX_EXPANSION: i64 = 6
68const IA_SEP_AND_NUL: i64 = 2
73const IA_TAG_OPEN: *u8 = "<img src='" as *u8
74const IA_TAG_MID: *u8 = "' alt='" as *u8
75const IA_TAG_ENDQ: *u8 = "'" as *u8
76const IA_TAG_CLOSE: *u8 = ">" as *u8
77const IA_IMG_OPEN: *u8 = "<img" as *u8
80const IA_S_IMGS: i64 = 0
81const IA_S_ALT_OK: i64 = 1
82const IA_S_SRC_OK: i64 = 2
83const IA_S_MALFORMED: i64 = 3
92const IA_S_QUOTEBREAK: i64 = 4
93const IA_SCAN_SLOTS: i64 = 5
94const IA_SLOT_BYTES: i64 = 8

functions

96func ia_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
98func ia_is_space(c: i64) -> i64
106func ia_lower(c: i64) -> i64
111func ia_put(dst: *u8, off: i64, c: i64) -> i64 { dst[off] = c as u8; return off + 1 }
113func ia_cat(dst: *u8, off: i64, s: *u8, cap: i64) -> i64
133func ia_esc_attr(dst: *u8, off: i64, s: *u8, cap: i64, trunc: *i64) -> i64
163func ia_esc_text(dst: *u8, off: i64, s: *u8, cap: i64, trunc: *i64) -> i64
183func ia_attr_hostile(s: *u8) -> i64
called by 1: main
197func ia_solid(p: *u8, a: i64, b: i64) -> i64
212func ia_alt_derive(caption: *u8, file: *u8, out: *u8, cap: i64) -> i64
257func ia_alt_cap_for(caption: *u8, file: *u8) -> i64
264func ia_img_cap_for(src: *u8, alt: *u8, extra: *u8) -> i64
277func ia_img_emit(dst: *u8, off: i64, cap: i64, src: *u8, alt: *u8, extra: *u8) -> i64
301func ia_starts_ci(p: *u8, at: i64, n: i64, lit: *u8) -> i64
312func ia_skip_past(p: *u8, from: i64, n: i64, lit: *u8) -> i64
called by 1: ia_scan calls 2: ia_slenia_starts_ci
324func ia_is_img_open(p: *u8, at: i64, n: i64) -> i64
335func ia_name_is(p: *u8, ns: i64, nlen: i64, lit: *u8) -> i64
called by 1: ia_img_tag calls 2: ia_slenia_lower
352func ia_img_tag(p: *u8, at: i64, n: i64, res: *i64) -> i64
447func ia_scan(page: *u8, n: i64, out: *i64) -> i64