code wiki / _hdl_build / nx_ad_emitter_registry.nx
nx_ad_emitter_registry.nx source
↩ module page · 130 lines · 6496 B
1// nx_ad_emitter_registry.nx -- LIB: the BUILDER'S LEARNED CATALOG. Every emitter we build (an accent, an
2// animation, a theme, a size) is TAUGHT to the builder by registering it here as DATA; the builder reads the
3// catalog to offer those emitters, and a GROW loop (nx_ad_emitter_grow) generates new ones and registers them
4// -- so the builder keeps growing its own emitters (the emitter-of-emitters loop, in the ad domain).
5//
6// Data-driven (rule 11), append-only + idempotent (rule 10/13). One row per emitter:
7// kind<TAB>id<TAB>label<TAB>template kind in {size, theme, accent, animation}.
8// `template` = the DATA to emit that block (SVG for an accent, a CSS @keyframes+rule for an animation,
9// pipe-joined colors for a theme, WxH for a size). SAFETY (enforced by the gate): a registered template may
10// NEVER contain a <script or src= -> the growing library stays sovereign (0 third-party JS / 0 external fetch)
11// BY CONSTRUCTION. Functions take a `path` so they are hermetically testable; ER_PATH is the live catalog.
12// (TSV registry for inspectability now; seg-store migration = the doctrine follow-on.) license_tier: ORIGINAL
13import "nx_syscalls.nx"
14
15const ER_PATH: *u8 = "knowledge/registry/ad_emitters.tsv"
16const ER_MAXTPL: i64 = 2048
17
18func er_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 }
19
20// copy the idx-th TAB-field of line[0..linelen) into out (NUL-terminated). returns 1.
21func er_field(line: *u8, linelen: i64, idx: i64, out: *u8) -> i64 {
22 var f: i64 = 0; var i: i64 = 0
23 while f < idx { if i < linelen { if line[i] == (9 as u8) { f = f + 1 } i = i + 1 } else { f = idx; i = linelen } }
24 var o: i64 = 0; var stop: i64 = 0
25 while i < linelen { if stop == 0 { if line[i] == (9 as u8) { stop = 1 } } if stop == 0 { out[o] = line[i]; o = o + 1 } i = i + 1 }
26 out[o] = 0 as u8; return 1
27}
28
29// 1 if a row in `path` has field0==kind AND field1==id.
30func er_present(path: *u8, kind: *u8, id: *u8) -> i64 {
31 let lp: *i64 = sys_mmap(16) as *i64; lp[0] = 0
32 let data: *u8 = sys_read_file(path, lp)
33 if (data as i64) == 0 { return 0 }
34 let n: i64 = lp[0]
35 let f0: *u8 = sys_mmap(64); let f1: *u8 = sys_mmap(128)
36 var i: i64 = 0; var ls: i64 = 0; var found: i64 = 0
37 while i < n {
38 if data[i] == (10 as u8) {
39 let line: *u8 = ((data as i64) + ls) as *u8
40 er_field(line, i - ls, 0, f0); er_field(line, i - ls, 1, f1)
41 if er_streq(f0, kind) == 1 { if er_streq(f1, id) == 1 { found = 1 } }
42 ls = i + 1
43 }
44 i = i + 1
45 }
46 return found
47}
48
49// TEACH one emitter into `path`: register kind/id/label/template if absent. 1 newly-taught, 0 already-known.
50func er_register(path: *u8, kind: *u8, id: *u8, label: *u8, template: *u8) -> i64 {
51 if er_present(path, kind, id) == 1 { return 0 }
52 let line: *u8 = sys_mmap(ER_MAXTPL + 512); var o: i64 = 0
53 var i: i64 = 0; while kind[i] != (0 as u8) { line[o] = kind[i]; o = o + 1; i = i + 1 } line[o] = 9 as u8; o = o + 1
54 i = 0; while id[i] != (0 as u8) { line[o] = id[i]; o = o + 1; i = i + 1 } line[o] = 9 as u8; o = o + 1
55 i = 0; while label[i] != (0 as u8) { line[o] = label[i]; o = o + 1; i = i + 1 } line[o] = 9 as u8; o = o + 1
56 i = 0; while template[i] != (0 as u8) { line[o] = template[i]; o = o + 1; i = i + 1 } line[o] = 10 as u8; o = o + 1
57 let fd: i64 = sys_openat_append(path, 420)
58 if fd < 0 { return 0 - 1 }
59 sys_write(fd, line, o); sys_close(fd)
60 return 1
61}
62
63// count emitters of a kind in `path`.
64func er_count(path: *u8, kind: *u8) -> i64 {
65 let lp: *i64 = sys_mmap(16) as *i64; lp[0] = 0
66 let data: *u8 = sys_read_file(path, lp)
67 if (data as i64) == 0 { return 0 }
68 let n: i64 = lp[0]
69 let f0: *u8 = sys_mmap(64)
70 var i: i64 = 0; var ls: i64 = 0; var c: i64 = 0
71 while i < n {
72 if data[i] == (10 as u8) { er_field(((data as i64) + ls) as *u8, i - ls, 0, f0); if er_streq(f0, kind) == 1 { c = c + 1 } ls = i + 1 }
73 i = i + 1
74 }
75 return c
76}
77
78// fetch the idx-th emitter of a kind in `path` -> out_id/out_label/out_template. 1 if found, 0 if not.
79func er_get(path: *u8, kind: *u8, idx: i64, out_id: *u8, out_label: *u8, out_template: *u8) -> i64 {
80 let lp: *i64 = sys_mmap(16) as *i64; lp[0] = 0
81 let data: *u8 = sys_read_file(path, lp)
82 if (data as i64) == 0 { return 0 }
83 let n: i64 = lp[0]
84 let f0: *u8 = sys_mmap(64)
85 var i: i64 = 0; var ls: i64 = 0; var c: i64 = 0; var got: i64 = 0
86 while i < n {
87 if data[i] == (10 as u8) {
88 let line: *u8 = ((data as i64) + ls) as *u8; let ll: i64 = i - ls
89 er_field(line, ll, 0, f0)
90 if er_streq(f0, kind) == 1 {
91 if c == idx { if got == 0 { er_field(line, ll, 1, out_id); er_field(line, ll, 2, out_label); er_field(line, ll, 3, out_template); got = 1 } }
92 c = c + 1
93 }
94 ls = i + 1
95 }
96 i = i + 1
97 }
98 return got
99}
100
101// find the row with field0==kind AND field1==id -> copy field3 (template) into out_template. 1 found, 0 not.
102func er_lookup(path: *u8, kind: *u8, id: *u8, out_template: *u8) -> i64 {
103 let lp: *i64 = sys_mmap(16) as *i64; lp[0] = 0
104 let data: *u8 = sys_read_file(path, lp)
105 if (data as i64) == 0 { return 0 }
106 let n: i64 = lp[0]
107 let f0: *u8 = sys_mmap(64); let f1: *u8 = sys_mmap(128)
108 var i: i64 = 0; var ls: i64 = 0; var got: i64 = 0
109 while i < n {
110 if data[i] == (10 as u8) {
111 let line: *u8 = ((data as i64) + ls) as *u8; let ll: i64 = i - ls
112 er_field(line, ll, 0, f0); er_field(line, ll, 1, f1)
113 if er_streq(f0, kind) == 1 { if er_streq(f1, id) == 1 { if got == 0 { er_field(line, ll, 3, out_template); got = 1 } } }
114 ls = i + 1
115 }
116 i = i + 1
117 }
118 return got
119}
120
121// SAFETY: 1 if a template is sovereign-safe (no <script and no src= -> 0 third-party JS / 0 external fetch).
122func er_template_safe(template: *u8) -> i64 {
123 var i: i64 = 0
124 while template[i] != (0 as u8) {
125 if template[i] == (60 as u8) { if template[i+1] == (115 as u8) { if template[i+2] == (99 as u8) { if template[i+3] == (114 as u8) { return 0 } } } } // "<scr"
126 if template[i] == (115 as u8) { if template[i+1] == (114 as u8) { if template[i+2] == (99 as u8) { if template[i+3] == (61 as u8) { return 0 } } } } // "src="
127 i = i + 1
128 }
129 return 1
130}