nx_url_params.nx source
↩ module page · 147 lines · 4605 B
1// nx_url_params.nx -- bits-up URL query-string parser for the Nishi
2// test harness arc. Mirrors what nishi-host.js does today in JS:
3// extracting `?v=N` from a URL string for sovereign version pinning.
4//
5// Scope: only what the test driver needs. No URL-encoding, no
6// fragment handling, no multi-value params (those are queued via
7// the full nishi-browser arc).
8
9import "nx_syscalls.nx"
10
11struct NxUrlParam {
12 found: i64, // 1 if param present
13 val_off: i64, // offset of value within URL string
14 val_len: i64 // byte length of value
15}
16
17func _up_strlen(s: *u8) -> i64 {
18 var n: i64 = 0
19 while s[n] != 0 { n = n + 1 }
20 return n
21}
22
23func _up_byte_eq(a: *u8, ao: i64, b: *u8, bo: i64, n: i64) -> i64 {
24 var i: i64 = 0
25 while i < n {
26 if a[ao + i] != b[bo + i] { return 0 }
27 i = i + 1
28 }
29 return 1
30}
31
32// Scan a key-delimiter (one of '=' '&' '#') or end. Returns position
33// of the delimiter, or url_len if none.
34func _up_scan_key_end(url: *u8, url_len: i64, start: i64) -> i64 {
35 var p: i64 = start
36 while p < url_len {
37 let b: i64 = url[p] as i64
38 if b == 61 { return p }
39 if b == 38 { return p }
40 if b == 35 { return p }
41 p = p + 1
42 }
43 return p
44}
45
46// Scan a value-delimiter (one of '&' '#') or end.
47func _up_scan_val_end(url: *u8, url_len: i64, start: i64) -> i64 {
48 var p: i64 = start
49 while p < url_len {
50 let b: i64 = url[p] as i64
51 if b == 38 { return p }
52 if b == 35 { return p }
53 p = p + 1
54 }
55 return p
56}
57
58// Find the start of the query string ('?'). Returns offset just past
59// the '?' or -1 if none.
60func nx_url_query_start(url: *u8, url_len: i64) -> i64 {
61 var i: i64 = 0
62 while i < url_len {
63 if url[i] == 63 { return i + 1 } // '?'
64 if url[i] == 35 { return -1 } // '#' before '?' -> no query
65 i = i + 1
66 }
67 return -1
68}
69
70// Parse a single named param from the URL. Single-exit pattern --
71// accumulate into out_found / out_val_off / out_val_len cells, then
72// pack into the result struct at function-end. NishiLang's scope
73// tracker loses an outer-scope struct pointer when an early-return
74// appears inside a nested-then-closed `if` block, so we sidestep it.
75func nx_url_param_get(url: *u8, url_len: i64, name: *u8) -> *NxUrlParam {
76 let out_found: *i64 = sys_mmap(8) as *i64
77 let out_val_off: *i64 = sys_mmap(8) as *i64
78 let out_val_len: *i64 = sys_mmap(8) as *i64
79 out_found[0] = 0
80 out_val_off[0] = -1
81 out_val_len[0] = 0
82
83 let qs_start: i64 = nx_url_query_start(url, url_len)
84 let nlen: i64 = _up_strlen(name)
85 var done: i64 = 0
86 if qs_start < 0 { done = 1 }
87 if nlen == 0 { done = 1 }
88
89 var pos: i64 = qs_start
90 while done == 0 {
91 if pos >= url_len { done = 1 }
92 if done == 0 {
93 let kstart: i64 = pos
94 let kend: i64 = _up_scan_key_end(url, url_len, kstart)
95 let klen: i64 = kend - kstart
96 var matched: i64 = 0
97 if klen == nlen {
98 if _up_byte_eq(url, kstart, name, 0, nlen) == 1 { matched = 1 }
99 }
100 var vstart: i64 = kend
101 var vend: i64 = kend
102 if kend < url_len {
103 if url[kend] == 61 {
104 vstart = kend + 1
105 vend = _up_scan_val_end(url, url_len, vstart)
106 }
107 }
108 if matched == 1 {
109 out_found[0] = 1
110 out_val_off[0] = vstart
111 out_val_len[0] = vend - vstart
112 done = 1
113 }
114 if done == 0 {
115 if vend >= url_len { done = 1 }
116 if done == 0 {
117 if url[vend] == 35 { done = 1 }
118 if done == 0 { pos = vend + 1 }
119 }
120 }
121 }
122 }
123
124 let r: *NxUrlParam = sys_mmap(24) as *NxUrlParam
125 r.found = out_found[0]
126 r.val_off = out_val_off[0]
127 r.val_len = out_val_len[0]
128 return r
129}
130
131// Convenience: parse a decimal integer value (positive only). Returns
132// -1 if param missing or non-numeric.
133func nx_url_param_int(url: *u8, url_len: i64, name: *u8) -> i64 {
134 let p: *NxUrlParam = nx_url_param_get(url, url_len, name)
135 if p.found != 1 { return -1 }
136 if p.val_len <= 0 { return -1 }
137 var acc: i64 = 0
138 var i: i64 = 0
139 while i < p.val_len {
140 let b: i64 = url[p.val_off + i] as i64
141 if b < 48 { return -1 }
142 if b > 57 { return -1 }
143 acc = acc * 10 + (b - 48)
144 i = i + 1
145 }
146 return acc
147}