code wiki / _hdl_build / nx_site_compose.nx
nx_site_compose.nx source
↩ module page · 177 lines · 7188 B
1// nx_site_compose.nx -- UNIFIED file-driven multi-type builder. One organ reads a .site DATA file and, from a
2// `type|<legal|game|video>` selector line, dispatches to the right page-type builder:
3// legal (default) -> the marketing block-walk (sgp_parse + sg_build_page)
4// game -> the last-mile game template (sgg_build)
5// video -> the video-gallery (vid_build)
6// Default type = legal, so every existing legal .site file keeps building untouched (additive). This makes the
7// "autonomously built from data, no AI" core (R4a) cover ALL three page types through ONE entry point, not just
8// legal. Each field is escaped by the underlying builder this routes to (block-walk sg_esc / crd_render slots /
9// vid_esc) -- this organ only parses + dispatches, it never emits HTML itself. license_tier: ORIGINAL
10import "nx_sitegen_parse.nx"
11import "nx_sitegen.nx"
12import "nx_sitegen_game.nx"
13import "nx_sitegen_video.nx"
14import "nx_syscalls.nx"
15const K_MAGIC_1024: i64 = 1024
16const K_MAGIC_131072: i64 = 131072
17const K_MAGIC_2048: i64 = 2048
18const K_MAGIC_2047: i64 = 2047
19
20func cmp_klen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
21
22func cmp_streq(a: *u8, b: *u8) -> i64 {
23 var i: i64 = 0
24 var go: i64 = 1
25 while go == 1 {
26 let ca: i64 = a[i] as i64
27 let cb: i64 = b[i] as i64
28 if ca != cb { return 0 }
29 if ca == 0 { return 1 }
30 i = i + 1
31 }
32 return 1
33}
34
35// does text[ls..le) start with key followed by '|'? return the value-start index, or -1.
36func cmp_line_match(text: *u8, ls: i64, le: i64, key: *u8, klen: i64) -> i64 {
37 if ls + klen + 1 > le { return 0 - 1 }
38 var i: i64 = 0
39 while i < klen {
40 if (text[ls+i] as i64) != (key[i] as i64) { return 0 - 1 }
41 i = i + 1
42 }
43 if (text[ls+klen] as i64) != 124 { return 0 - 1 } // '|'
44 return ls + klen + 1
45}
46
47// copy text[start..end) into arena at ap (trim a trailing CR), null-terminate, return new ap.
48func cmp_copy(arena: *u8, ap: i64, text: *u8, start: i64, end: i64) -> i64 {
49 var o: i64 = ap
50 var j: i64 = start
51 while j < end { arena[o] = text[j]; o = o + 1; j = j + 1 }
52 if o > ap { if (arena[o-1] as i64) == 13 { o = o - 1 } }
53 arena[o] = 0 as u8; o = o + 1
54 return o
55}
56
57// get the value of the first "key|value" line into out (null-terminated, trailing CR trimmed); return len or -1.
58func cmp_get(text: *u8, tn: i64, key: *u8, out: *u8, cap: i64) -> i64 {
59 let klen: i64 = cmp_klen(key)
60 var ls: i64 = 0
61 var i: i64 = 0
62 while i <= tn {
63 var eol: i64 = 0
64 if i == tn { eol = 1 }
65 if i < tn { if (text[i] as i64) == 10 { eol = 1 } }
66 if eol == 1 {
67 let vs: i64 = cmp_line_match(text, ls, i, key, klen)
68 if vs >= 0 {
69 var o: i64 = 0
70 var j: i64 = vs
71 while j < i {
72 if o < cap - 1 { out[o] = text[j]; o = o + 1 }
73 j = j + 1
74 }
75 if o > 0 { if (out[o-1] as i64) == 13 { o = o - 1 } }
76 out[o] = 0 as u8
77 return o
78 }
79 ls = i + 1
80 }
81 i = i + 1
82 }
83 return 0 - 1
84}
85
86// parse every "video|title|thumb|url" line into the parallel arrays (fields copied into arena). return count.
87func cmp_videos(text: *u8, tn: i64, titles: *i64, thumbs: *i64, urls: *i64, arena: *u8, max: i64) -> i64 {
88 var ap: i64 = 0
89 var cnt: i64 = 0
90 var ls: i64 = 0
91 var i: i64 = 0
92 while i <= tn {
93 var eol: i64 = 0
94 if i == tn { eol = 1 }
95 if i < tn { if (text[i] as i64) == 10 { eol = 1 } }
96 if eol == 1 {
97 let vs: i64 = cmp_line_match(text, ls, i, "video" as *u8, 5)
98 if vs >= 0 {
99 if cnt < max {
100 var p1: i64 = vs
101 while p1 < i { if (text[p1] as i64) == 124 { break } p1 = p1 + 1 }
102 var p2: i64 = p1 + 1
103 while p2 < i { if (text[p2] as i64) == 124 { break } p2 = p2 + 1 }
104 titles[cnt] = (arena + ap) as i64
105 ap = cmp_copy(arena, ap, text, vs, p1)
106 thumbs[cnt] = (arena + ap) as i64
107 ap = cmp_copy(arena, ap, text, p1 + 1, p2)
108 urls[cnt] = (arena + ap) as i64
109 ap = cmp_copy(arena, ap, text, p2 + 1, i)
110 cnt = cnt + 1
111 }
112 }
113 ls = i + 1
114 }
115 i = i + 1
116 }
117 return cnt
118}
119
120// build a page from an in-memory .site (text/tn) to fd, dispatching on the `type|` line. game_tpl = the game
121// template path (used only for type|game). returns the underlying builder's result (>=0 built, <0 refused).
122func compose_build(text: *u8, tn: i64, fd: i64, game_tpl: *u8) -> i64 {
123 let typ: *u8 = sys_mmap(64)
124 let tl: i64 = cmp_get(text, tn, "type" as *u8, typ, 63)
125 var is_video: i64 = 0
126 var is_game: i64 = 0
127 if tl > 0 {
128 if cmp_streq(typ, "video" as *u8) == 1 { is_video = 1 }
129 if cmp_streq(typ, "game" as *u8) == 1 { is_game = 1 }
130 }
131
132 if is_video == 1 {
133 let vt: *u8 = sys_mmap(K_MAGIC_1024)
134 cmp_get(text, tn, "vtitle" as *u8, vt, 1023)
135 let vh: *u8 = sys_mmap(K_MAGIC_1024)
136 cmp_get(text, tn, "vheading" as *u8, vh, 1023)
137 let titles: *i64 = sys_mmap(8*64) as *i64
138 let thumbs: *i64 = sys_mmap(8*64) as *i64
139 let urls: *i64 = sys_mmap(8*64) as *i64
140 let varena: *u8 = sys_mmap(K_MAGIC_131072)
141 let n: i64 = cmp_videos(text, tn, titles, thumbs, urls, varena, 64)
142 return vid_build(fd, vt, vh, titles, thumbs, urls, n)
143 }
144
145 if is_game == 1 {
146 let gt: *u8 = sys_mmap(K_MAGIC_1024)
147 cmp_get(text, tn, "gtitle" as *u8, gt, 1023)
148 let wasm: *u8 = sys_mmap(K_MAGIC_1024)
149 cmp_get(text, tn, "wasm" as *u8, wasm, 1023)
150 let fbw: *u8 = sys_mmap(64)
151 cmp_get(text, tn, "fbw" as *u8, fbw, 63)
152 let fbh: *u8 = sys_mmap(64)
153 cmp_get(text, tn, "fbh" as *u8, fbh, 63)
154 let dpw: *u8 = sys_mmap(64)
155 cmp_get(text, tn, "dispw" as *u8, dpw, 63)
156 let dph: *u8 = sys_mmap(64)
157 cmp_get(text, tn, "disph" as *u8, dph, 63)
158 let room: *u8 = sys_mmap(64)
159 cmp_get(text, tn, "room" as *u8, room, 63)
160 let ctl: *u8 = sys_mmap(K_MAGIC_2048)
161 cmp_get(text, tn, "controls" as *u8, ctl, K_MAGIC_2047)
162 return sgg_build(fd, game_tpl, gt, wasm, fbw, fbh, dpw, dph, room, ctl)
163 }
164
165 // legal (default) -- the marketing block-walk
166 let kind: *i64 = sys_mmap(8*64) as *i64
167 let a: *i64 = sys_mmap(8*64) as *i64
168 let b: *i64 = sys_mmap(8*64) as *i64
169 let cc: *i64 = sys_mmap(8*64) as *i64
170 let d: *i64 = sys_mmap(8*64) as *i64
171 let list: *i64 = sys_mmap(8*64) as *i64
172 let lcount: *i64 = sys_mmap(8*64) as *i64
173 let arena2: *u8 = sys_mmap(K_MAGIC_131072)
174 let title2: *u8 = sys_mmap(512)
175 let nblk: i64 = sgp_parse(text, tn, kind, a, b, cc, d, list, lcount, 64, arena2, title2, 511)
176 return sg_build_page(fd, title2, kind, a, b, cc, d, list, lcount, nblk)
177}