code wiki / _hdl_build / nx_site_wholesale.nx
nx_site_wholesale.nx source
↩ module page · 237 lines · 10236 B
1// nx_site_wholesale.nx -- R-SITESHAPE of the SITE FACTORY: EMIT a complete multi-page site from a `site:`
2// graph record ("lego up a site / pass it along wholesale" -- the OUTPUT half of R-WHOLESITE). Reads the
3// content-addressed site graph (pages + per-page archetype + section-seq + nav edges) from the corpus and
4// re-emits the WHOLE site: same relative page paths (subdirs preserved), each page composed SEQ-FAITHFULLY
5// by the R5 composer, a shared nav built from the graph's own index edges (not the factory default), plus
6// self-emitted sitemap.xml + robots.txt. Content = archetype defaults or an optional .req brief.
7// usage: nx_site_wholesale <corpus-prefix> <site-key> <docroot> <domain> [reqfile]
8// license_tier: ORIGINAL
9import "nx_site_archetype.nx"
10const SW_MAGIC_1024: i64 = 1024
11const SW_MAGIC_262144: i64 = 262144
12
13const SW_MAXPG: i64 = 64
14const SW_NAMEW: i64 = 96
15const SW_SEQW: i64 = 200
16const SW_MAXNAV: i64 = 8
17
18// archname -> code (reverse of ti_arch_name); 0 unknown
19func sw_arch_code(nm: *u8, nl: i64) -> i64 {
20 let buf: *u8 = sys_mmap(32)
21 var c: i64 = 1
22 while c <= 10 {
23 let bl: i64 = ti_arch_name(c, buf)
24 if bl == nl {
25 var i: i64 = 0
26 var eq: i64 = 1
27 while i < nl { if (buf[i] as i64) != (nm[i] as i64) { eq = 0; i = nl } else { i = i + 1 } }
28 if eq == 1 { return c }
29 }
30 c = c + 1
31 }
32 return 0
33}
34// copy src[a..b) into dst, NUL-terminate; returns len
35func sw_cp(src: *u8, a: i64, b: i64, dst: *u8, cap: i64) -> i64 {
36 var o: i64 = 0
37 var i: i64 = a
38 while i < b { if o < cap - 1 { dst[o] = src[i]; o = o + 1 } i = i + 1 }
39 dst[o] = 0 as u8
40 return o
41}
42// next '|' at-or-after p, else e
43func sw_bar(s: *u8, p: i64, e: i64) -> i64 {
44 var i: i64 = p
45 while i < e { if (s[i] as i64) == 124 { return i } i = i + 1 }
46 return e
47}
48func sw_starts(s: *u8, p: i64, e: i64, lit: *u8) -> i64 {
49 var i: i64 = 0
50 while lit[i] != (0 as u8) {
51 if p + i >= e { return 0 }
52 if (s[p + i] as i64) != (lit[i] as i64) { return 0 }
53 i = i + 1
54 }
55 return 1
56}
57func sw_eqz(a: *u8, b: *u8) -> i64 { var i: i64=0; while 1==1 { if (a[i] as i64)!=(b[i] as i64) { return 0 } if a[i]==(0 as u8) { return 1 } i=i+1 } return 1 }
58
59func main(argc: i64, argv: *i64) -> i64 {
60 if argc < 5 { sa_w("usage: nx_site_wholesale <corpus-prefix> <site-key> <docroot> <domain> [reqfile]\n" as *u8); return 2 }
61 let prefix: *u8 = argv[1] as *u8
62 let key: *u8 = argv[2] as *u8
63 let docroot: *u8 = argv[3] as *u8
64 let domain: *u8 = argv[4] as *u8
65 // optional [urlbase] (starts with '/') so nav + sitemap work when served under a subpath
66 // (e.g. /wholesale/remix1); optional [reqfile] fills content. Order-flexible for back-compat.
67 let ub: *u8 = sys_mmap(160)
68 ub[0] = 0 as u8
69 if argc >= 6 {
70 let a5: *u8 = argv[5] as *u8
71 if a5[0] == (47 as u8) {
72 var u0: i64 = 0
73 while a5[u0] != (0 as u8) { if u0 < 156 { ub[u0] = a5[u0] } u0 = u0 + 1 }
74 if u0 > 156 { u0 = 156 }
75 ub[u0] = 0 as u8
76 } else { sa_req_load(a5) }
77 }
78 if argc >= 7 { sa_req_load(argv[6] as *u8) }
79 // fetch the site-graph record
80 let pbox: *i64 = sys_mmap(16) as *i64
81 let lbox: *i64 = sys_mmap(16) as *i64
82 if ss_get(prefix, key, pbox, lbox) != 1 { sa_w("site-wholesale: key not in corpus: " as *u8); sa_w(key); sa_w("\n" as *u8); return 3 }
83 let rec: *u8 = pbox[0] as *u8
84 let rn: i64 = lbox[0]
85 // parse pages + index-nav targets
86 let names: *u8 = sys_mmap(SW_MAXPG * SW_NAMEW)
87 let seqs: *u8 = sys_mmap(SW_MAXPG * SW_SEQW)
88 let archs: *i64 = sys_mmap(SW_MAXPG * 8) as *i64
89 var npg: i64 = 0
90 let navt: *u8 = sys_mmap(SW_MAXNAV * SW_NAMEW)
91 var nnav: i64 = 0
92 let anb: *u8 = sys_mmap(32)
93 var ls: i64 = 0
94 while ls < rn {
95 var le: i64 = ls
96 var sc: i64 = 1
97 while sc == 1 { if le >= rn { sc = 0 } else { if (rec[le] as i64) == 10 { sc = 0 } else { le = le + 1 } } }
98 if sw_starts(rec, ls, le, "page|" as *u8) == 1 { if npg < SW_MAXPG {
99 let f1: i64 = ls + 5
100 let b1: i64 = sw_bar(rec, f1, le)
101 let b2: i64 = sw_bar(rec, b1 + 1, le)
102 sw_cp(rec, f1, b1, (names as i64 + npg * SW_NAMEW) as *u8, SW_NAMEW)
103 let al: i64 = sw_cp(rec, b1 + 1, b2, anb, 32)
104 archs[npg] = sw_arch_code(anb, al)
105 if archs[npg] == 0 { archs[npg] = 7 }
106 sw_cp(rec, b2 + 1, le, (seqs as i64 + npg * SW_SEQW) as *u8, SW_SEQW)
107 npg = npg + 1
108 } }
109 if sw_starts(rec, ls, le, "nav|index.html|" as *u8) == 1 { if nnav < SW_MAXNAV {
110 let t1: i64 = ls + 15
111 let td: *u8 = (navt as i64 + nnav * SW_NAMEW) as *u8
112 sw_cp(rec, t1, le, td, SW_NAMEW)
113 // dedup
114 var dup: i64 = 0
115 var d: i64 = 0
116 while d < nnav { if sw_eqz(td, (navt as i64 + d * SW_NAMEW) as *u8) == 1 { dup = 1; d = nnav } else { d = d + 1 } }
117 if dup == 0 { nnav = nnav + 1 }
118 } }
119 ls = le + 1
120 }
121 if npg == 0 { sa_w("site-wholesale: record has no pages\n" as *u8); return 4 }
122 // shared nav from the graph: Home + index's targets (label = basename sans .html; href = /<name>)
123 let nlbl: *i64 = sys_mmap((SW_MAXNAV + 2) * 8) as *i64
124 let nhrf: *i64 = sys_mmap((SW_MAXNAV + 2) * 8) as *i64
125 let lblarena: *u8 = sys_mmap((SW_MAXNAV + 2) * 64)
126 let hrfarena: *u8 = sys_mmap((SW_MAXNAV + 2) * 112)
127 var nn: i64 = 0
128 nlbl[nn] = ("Home" as *u8) as i64
129 let homehref: *u8 = (hrfarena as i64) as *u8
130 var hh0: i64 = sa_cat(homehref, 0, ub)
131 homehref[hh0] = 47 as u8
132 homehref[hh0 + 1] = 0 as u8
133 nhrf[nn] = homehref as i64
134 nn = nn + 1
135 var v: i64 = 0
136 while v < nnav {
137 let t: *u8 = (navt as i64 + v * SW_NAMEW) as *u8
138 if sw_eqz(t, "index.html" as *u8) == 0 {
139 // label = basename without .html
140 var b0: i64 = 0
141 var i2: i64 = 0
142 while t[i2] != (0 as u8) { if (t[i2] as i64) == 47 { b0 = i2 + 1 } i2 = i2 + 1 }
143 let ld: *u8 = (lblarena as i64 + nn * 64) as *u8
144 var lo: i64 = 0
145 var j2: i64 = b0
146 while t[j2] != (0 as u8) { if (t[j2] as i64) == 46 { j2 = i2 } else { if lo < 60 { ld[lo] = t[j2]; lo = lo + 1 } j2 = j2 + 1 } }
147 ld[lo] = 0 as u8
148 let hd: *u8 = (hrfarena as i64 + nn * 112) as *u8
149 var ho: i64 = sa_cat(hd, 0, ub)
150 hd[ho] = 47 as u8; ho = ho + 1
151 var k2: i64 = 0
152 while t[k2] != (0 as u8) { if ho < 108 { hd[ho] = t[k2]; ho = ho + 1 } k2 = k2 + 1 }
153 hd[ho] = 0 as u8
154 nlbl[nn] = ld as i64
155 nhrf[nn] = hd as i64
156 nn = nn + 1
157 }
158 v = v + 1
159 }
160 SA_WNAV = nlbl as i64
161 SA_WHREF = nhrf as i64
162 SA_WNAVN = nn
163 // R-BRICKS: open the corpus for part: queries so grid richness follows the consumed bricks
164 let bh: *i64 = ss_open(prefix)
165 if (bh as i64) != 0 { SA_STOREH = bh as i64 }
166 // mkdir docroot + one-level subdirs from page names
167 sys_mkdir(docroot, 0x1ed)
168 let pathb: *u8 = sys_mmap(SW_MAGIC_1024)
169 var p: i64 = 0
170 while p < npg {
171 let nm: *u8 = (names as i64 + p * SW_NAMEW) as *u8
172 var sl: i64 = 0 - 1
173 var i3: i64 = 0
174 while nm[i3] != (0 as u8) { if (nm[i3] as i64) == 47 { sl = i3 } i3 = i3 + 1 }
175 if sl > 0 {
176 var po: i64 = sa_cat(pathb, 0, docroot)
177 po = sa_cat(pathb, po, "/" as *u8)
178 var c3: i64 = 0
179 while c3 < sl { pathb[po] = nm[c3]; po = po + 1; c3 = c3 + 1 }
180 pathb[po] = 0 as u8
181 sys_mkdir(pathb, 0x1ed)
182 }
183 p = p + 1
184 }
185 // emit every page seq-faithfully with the site's own nav
186 let buf: *u8 = sys_mmap(SW_MAGIC_262144)
187 let titleb: *u8 = sys_mmap(192)
188 var emitted: i64 = 0
189 p = 0
190 while p < npg {
191 let nm2: *u8 = (names as i64 + p * SW_NAMEW) as *u8
192 var t4: i64 = sa_cat(titleb, 0, sa_disp(archs[p]))
193 t4 = sa_cat(titleb, t4, " -- " as *u8)
194 t4 = sa_cat(titleb, t4, domain)
195 titleb[t4] = 0 as u8
196 let o: i64 = sa_recipe_seq(archs[p], (seqs as i64 + p * SW_SEQW) as *u8, p % 2, domain, titleb, buf)
197 var pp: i64 = sa_cat(pathb, 0, docroot)
198 pp = sa_cat(pathb, pp, "/" as *u8)
199 pp = sa_cat(pathb, pp, nm2)
200 pathb[pp] = 0 as u8
201 let fd: i64 = sys_openat_wr(pathb, 0x1a4)
202 if fd >= 0 { sys_write(fd, buf, o); sys_close(fd); emitted = emitted + 1 }
203 p = p + 1
204 }
205 // sitemap + robots over the emitted page set
206 var so: i64 = sa_cat(buf, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" as *u8)
207 p = 0
208 while p < npg {
209 let nm3: *u8 = (names as i64 + p * SW_NAMEW) as *u8
210 so = sa_cat(buf, so, "<url><loc>https://" as *u8)
211 so = sa_cat(buf, so, domain)
212 so = sa_cat(buf, so, ub)
213 so = sa_cat(buf, so, "/" as *u8)
214 if sw_eqz(nm3, "index.html" as *u8) == 0 { so = sa_cat(buf, so, nm3) }
215 so = sa_cat(buf, so, "</loc></url>\n" as *u8)
216 p = p + 1
217 }
218 so = sa_cat(buf, so, "</urlset>\n" as *u8)
219 var mp: i64 = sa_cat(pathb, 0, docroot); mp = sa_cat(pathb, mp, "/sitemap.xml" as *u8); pathb[mp] = 0 as u8
220 let mfd: i64 = sys_openat_wr(pathb, 0x1a4)
221 if mfd >= 0 { sys_write(mfd, buf, so); sys_close(mfd) }
222 var ro2: i64 = sa_cat(buf, 0, "User-agent: *\nAllow: /\nSitemap: https://" as *u8)
223 ro2 = sa_cat(buf, ro2, domain)
224 ro2 = sa_cat(buf, ro2, "/sitemap.xml\n" as *u8)
225 var rp2: i64 = sa_cat(pathb, 0, docroot); rp2 = sa_cat(pathb, rp2, "/robots.txt" as *u8); pathb[rp2] = 0 as u8
226 let rfd: i64 = sys_openat_wr(pathb, 0x1a4)
227 if rfd >= 0 { sys_write(rfd, buf, ro2); sys_close(rfd) }
228 sa_w("SITE-WHOLESALE OK: " as *u8)
229 let nb2: *u8 = sys_mmap(28)
230 let ne2: i64 = sa_catn(nb2, 0, emitted)
231 sys_write(1, nb2, ne2)
232 sa_w(" pages (structure + nav from the site graph) -> " as *u8)
233 sa_w(docroot)
234 sa_w("\n" as *u8)
235 if emitted == npg { return 0 }
236 return 1
237}