nx_compare_scope_lib.nx source
↩ module page · 86 lines · 3275 B
1// Allocation-free validation for an explicitly selected Compare domain.
2// No I/O or mutation. Byte lengths describe accessible caller-owned buffers.
3const CSCOPE_INVALID: i64 = 0 - 1
4const CSCOPE_LF: i64 = 10
5const CSCOPE_CR: i64 = 13
6const CSCOPE_COMMENT: i64 = 35
7const CSCOPE_DASH: i64 = 45
8const CSCOPE_UNDERSCORE: i64 = 95
9const CSCOPE_ZERO: i64 = 48
10const CSCOPE_NINE: i64 = 57
11const CSCOPE_LOWER_A: i64 = 97
12const CSCOPE_LOWER_Z: i64 = 122
13
14func cscope_name_char(c: i64) -> i64 {
15 if c >= CSCOPE_ZERO { if c <= CSCOPE_NINE { return 1 } }
16 if c >= CSCOPE_LOWER_A { if c <= CSCOPE_LOWER_Z { return 1 } }
17 if c == CSCOPE_DASH { return 1 }
18 if c == CSCOPE_UNDERSCORE { return 1 }
19 return 0
20}
21
22// name is a NUL-terminated argv string, or has at least max_len+1 accessible
23// bytes. The extra byte distinguishes an exact-bound name from a long prefix.
24// max_len is a caller-owned path-capacity bound, not a policy hidden here.
25func cscope_validate_name(name: *u8, max_len: i64) -> i64 {
26 if (name as i64) == 0 { return CSCOPE_INVALID }
27 if max_len <= 0 { return CSCOPE_INVALID }
28 var i: i64 = 0
29 while i < max_len {
30 if name[i] == (0 as u8) {
31 if i == 0 { return CSCOPE_INVALID }
32 return i
33 }
34 if cscope_name_char(name[i] as i64) == 0 { return CSCOPE_INVALID }
35 i = i + 1
36 }
37 if name[i] != (0 as u8) { return CSCOPE_INVALID }
38 return i
39}
40
41// Counts exact selected entries: 0 means unknown, 1 admits membership,
42// >1 means ambiguous duplicate selection, -1 means malformed input.
43// Blank lines and column-zero # comments are ignored. LF, CRLF and an
44// unterminated final domain line are supported. Other whitespace cannot match.
45// Unrelated lines are never executed and do not block the selected domain.
46// Embedded NUL anywhere makes the file ambiguous to downstream C-string
47// consumers, so reject it even in comments. Duplicate unrelated lines are safe.
48func cscope_roster_count(roster: *u8, n: i64, name: *u8, name_len: i64) -> i64 {
49 if (roster as i64) == 0 { return CSCOPE_INVALID }
50 if n < 0 { return CSCOPE_INVALID }
51 if (name as i64) == 0 { return CSCOPE_INVALID }
52 if name_len <= 0 { return CSCOPE_INVALID }
53 var ni: i64 = 0
54 while ni < name_len {
55 if cscope_name_char(name[ni] as i64) == 0 { return CSCOPE_INVALID }
56 ni = ni + 1
57 }
58 var bi: i64 = 0
59 while bi < n {
60 if roster[bi] == (0 as u8) { return CSCOPE_INVALID }
61 bi = bi + 1
62 }
63 var count: i64 = 0
64 var p: i64 = 0
65 while p < n {
66 var e: i64 = p
67 while e < n { if roster[e] == (CSCOPE_LF as u8) { break } e = e + 1 }
68 var end: i64 = e
69 if e < n { if end > p { if roster[end-1] == (CSCOPE_CR as u8) { end = end - 1 } } }
70 if end > p {
71 if roster[p] != (CSCOPE_COMMENT as u8) {
72 var i: i64 = p
73 var equal: i64 = 1
74 if end-p != name_len { equal = 0 }
75 while i < end {
76 if equal == 1 { if roster[i] != name[i-p] { equal = 0 } }
77 i = i + 1
78 }
79 if equal == 1 { count = count + 1 }
80 }
81 }
82 if e == n { p = n } else { p = e + 1 }
83 }
84 return count
85}
86