code wiki / _hdl_build / nx_meet_lib.nx

nx_meet_lib.nx source

↩ module page · 150 lines · 7221 B

1// nx_meet_lib.nx -- shared helpers for the NISHI MEET PLATFORM organs (LIBRARY, no main; rule 15 DRY, so R2..R8 2// don't each re-implement them). String/io utils + .meet config lookup (meet|key|value) + |-delimited field 3// extraction + HTML-escape (escape DATA values, never the organ's own markup) + slug sanitation. 100% sovereign 4// (nx_cc->nxasm, no gcc/JS). license_tier: ORIGINAL 5import "nx_syscalls.nx" 6const K_MAGIC_1024: i64 = 1024 7 8func mlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 9func mputs(s: *u8) -> i64 { sys_write(1, s, mlen(s)); return 0 } 10func mnum(v0: i64) -> i64 { var v: i64=v0; if v<0{sys_write(1,"-" as *u8,1);v=0-v} let b: *u8=sys_mmap(28); var k: i64=0; if v==0{b[0]=48 as u8;k=1} while v>0{b[k]=(48+(v%10)) as u8;v=v/10;k=k+1} let o: *u8=sys_mmap(28); var j: i64=0; while j<k{o[j]=b[k-1-j];j=j+1} sys_write(1,o,k); return 0 } 11 12// append nul-terminated s into dst at off; return new off (caller sizes dst generously). 13func mcat(dst: *u8, off: i64, s: *u8) -> i64 { 14 var o: i64 = off; var i: i64 = 0 15 while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } 16 dst[o] = 0 as u8 17 return o 18} 19 20// append s into dst at off, HTML-escaping & < > " (apply to DATA values, never the organ's own markup). new off. 21func mesc(dst: *u8, off: i64, s: *u8) -> i64 { 22 var o: i64 = off; var i: i64 = 0 23 while s[i] != (0 as u8) { 24 let c: i64 = s[i] as i64 25 var done: i64 = 0 26 if c == 38 { o = mcat(dst, o, "&amp;" as *u8); done = 1 } 27 if done == 0 { if c == 60 { o = mcat(dst, o, "&lt;" as *u8); done = 1 } } 28 if done == 0 { if c == 62 { o = mcat(dst, o, "&gt;" as *u8); done = 1 } } 29 if done == 0 { if c == 34 { o = mcat(dst, o, "&quot;" as *u8); done = 1 } } 30 if done == 0 { dst[o] = s[i]; o = o + 1; dst[o] = 0 as u8 } 31 i = i + 1 32 } 33 dst[o] = 0 as u8 34 return o 35} 36 37// text[s..e) byte-equal to lit[0..litlen)? 38func meet_seq(text: *u8, s: i64, e: i64, lit: *u8, litlen: i64) -> i64 { 39 if (e - s) != litlen { return 0 } 40 var i: i64 = 0 41 while i < litlen { if text[s+i] != lit[i] { return 0 } i = i + 1 } 42 return 1 43} 44 45// find a `meet|<key>|<value>` line; copy value into out (nul-term, cap-bounded). returns len, or -1 if absent. 46func meet_get(data: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64 { 47 let klen: i64 = mlen(key) 48 var i: i64 = 0 49 while i < n { 50 var le: i64 = i 51 while le < n { if data[le] == (10 as u8) { break } le = le + 1 } 52 var p0: i64 = 0 - 1; var p1: i64 = 0 - 1 53 var k: i64 = i 54 while k < le { 55 if data[k] == (124 as u8) { 56 if p0 < 0 { p0 = k } else { if p1 < 0 { p1 = k } } 57 } 58 k = k + 1 59 } 60 if p0 >= 0 { if p1 >= 0 { 61 if meet_seq(data, i, p0, "meet" as *u8, 4) == 1 { 62 if meet_seq(data, p0 + 1, p1, key, klen) == 1 { 63 var w: i64 = 0; var c: i64 = p1 + 1 64 while c < le { if w < cap - 1 { out[w] = data[c]; w = w + 1 } c = c + 1 } 65 out[w] = 0 as u8 66 return w 67 } 68 } 69 } } 70 i = le + 1 71 } 72 return 0 - 1 73} 74 75// meet_get with a default fallback copied when the key is absent (so output is always complete). 76func meet_get_or(data: *u8, n: i64, key: *u8, out: *u8, cap: i64, deflt: *u8) -> i64 { 77 let r: i64 = meet_get(data, n, key, out, cap) 78 if r >= 0 { return r } 79 var w: i64 = 0 80 while deflt[w] != (0 as u8) { if w >= cap - 1 { break } out[w] = deflt[w]; w = w + 1 } 81 out[w] = 0 as u8 82 return w 83} 84 85// extract the idx-th '|'-delimited field within data[ls,le) into out (nul-term, cap-bounded). returns len. 86func mfield(data: *u8, ls: i64, le: i64, idx: i64, out: *u8, cap: i64) -> i64 { 87 var f: i64 = 0; var i: i64 = ls 88 while f < idx { if i < le { if data[i] == (124 as u8) { f = f + 1 } i = i + 1 } else { i = le; f = idx } } 89 var o: i64 = 0 90 while i < le { if data[i] == (124 as u8) { break } if o < cap - 1 { out[o] = data[i]; o = o + 1 } i = i + 1 } 91 out[o] = 0 as u8 92 return o 93} 94 95// copy only [A-Za-z0-9_-] from src into out (cap-bounded); fall back to "demo" if empty. (boundary defense) 96func meet_slug_safe(src: *u8, out: *u8, cap: i64) -> i64 { 97 var w: i64 = 0; var i: i64 = 0 98 while src[i] != (0 as u8) { 99 let c: i64 = src[i] as i64 100 var ok: i64 = 0 101 if c >= 97 { if c <= 122 { ok = 1 } } 102 if c >= 65 { if c <= 90 { ok = 1 } } 103 if c >= 48 { if c <= 57 { ok = 1 } } 104 if c == 95 { ok = 1 } 105 if c == 45 { ok = 1 } 106 if ok == 1 { if w < cap - 1 { out[w] = src[i]; w = w + 1 } } 107 i = i + 1 108 } 109 if w == 0 { out[0]=100 as u8; out[1]=101 as u8; out[2]=109 as u8; out[3]=111 as u8; w=4 } 110 out[w] = 0 as u8 111 return w 112} 113 114// --- R8 P1: per-site directory + clean-URL header nav (shared by every page emitter that imports this lib) --- 115func meet_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd, s, n); return 0 } 116func meet_mkdir(path: *u8) -> i64 { __syscall(83, path as i64, 493, 0, 0, 0, 0); return 0 } // mkdir 0755, ignore EEXIST 117 118// token-driven nav CSS (white-on-primary header). emit ONCE, right after wb_doc_open_branded. 119func meet_nav_css(fd: i64) -> i64 { 120 meet_w(fd, "<style>.nav{display:flex;gap:14px;flex-wrap:wrap;align-items:center}.nav a{color:#fff;text-decoration:none;opacity:.82;font-weight:600;min-height:44px;display:inline-flex;align-items:center}.nav a.on,.nav a:hover,.nav a:focus-visible{opacity:1;text-decoration:underline}</style>\n" as *u8) 121 return 0 122} 123func meet_nav_link(fd: i64, href: *u8, label: *u8, active: i64, idx: i64) -> i64 { 124 meet_w(fd, "<a href=\"" as *u8); meet_w(fd, href); meet_w(fd, "\"" as *u8) 125 if active == idx { meet_w(fd, " class=\"on\" aria-current=\"page\"" as *u8) } 126 meet_w(fd, ">" as *u8); meet_w(fd, label); meet_w(fd, "</a>" as *u8) 127 return 0 128} 129// site header: brand + the 5-link primary nav (clean URLs). active: 0=Home 1=Jobs 2=Apply 3=Hire 4=About. 130func meet_header_nav(fd: i64, brand: *u8, active: i64) -> i64 { 131 let eb: *u8 = sys_mmap(K_MAGIC_1024); mesc(eb, 0, brand) 132 meet_w(fd, "<header><div class=\"wrap\"><span class=\"brand\">" as *u8); meet_w(fd, eb) 133 meet_w(fd, "</span><nav class=\"nav\" aria-label=\"Primary\">" as *u8) 134 meet_nav_link(fd, "index.html" as *u8, "Home" as *u8, active, 0) 135 meet_nav_link(fd, "jobs.html" as *u8, "Jobs" as *u8, active, 1) 136 meet_nav_link(fd, "apply.html" as *u8, "Apply" as *u8, active, 2) 137 meet_nav_link(fd, "hire.html" as *u8, "Hire" as *u8, active, 3) 138 meet_nav_link(fd, "about.html" as *u8, "About" as *u8, active, 4) 139 meet_w(fd, "</nav></div></header>\n" as *u8) 140 return 0 141} 142 143// strip ALL control chars (<32) from s into dst at off -> CRLF/header-injection safe for email + record fields 144// (the bk_san pattern). new off (nul-terminated). Apply to UNTRUSTED submission values. 145func meet_san(dst: *u8, off: i64, s: *u8) -> i64 { 146 var o: i64 = off; var i: i64 = 0 147 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 32 { dst[o] = s[i]; o = o + 1 } i = i + 1 } 148 dst[o] = 0 as u8 149 return o 150}