code wiki / (root) / nx_varcensus_lib.nx

nx_varcensus_lib.nx source

↩ module page · 594 lines · 24713 B

1// nx_varcensus_lib.nx -- the VaM corpus census's DATA-DRIVEN pieces, importable by the CLI (nx_varcensus) and its gate. 2// 3// (1) a growable byte ARENA -- tables store OFFSETS into it, so growth (a bigger mapping plus a copy) never leaves a 4// dangling pointer; an i64 vector rides the same arena in 8-byte cells. 5// (2) a growable string COUNTER -- FNV-1a, open addressing, the slot table doubled at half load; entries are kept in 6// FIRST-SEEN ORDER so a report reads in the order the corpus was walked (and the walk itself is sorted). 7// (3) the RULES conf (the classifier is DATA, never code). Rows, TAB separated, '#' comments: 8// role|format <TAB> <class> <TAB> <kind> <TAB> <pattern> [<TAB> <kind> <TAB> <pattern>] both conditions must hold 9// screen <TAB> <reason letter A-Z> <TAB> class <TAB> <role class> a member of that class sets the reason 10// screen <TAB> <reason letter A-Z> <TAB> namecontains <TAB> <token> the package id contains the token 11// deptag <TAB> <tag> <TAB> prefix <TAB> <dependency id prefix> a direct dependency with that prefix 12// kinds: dirent (name ends with a slash) | exact | prefix | suffix | contains. Matching is on LOWERCASED names and 13// lowercased patterns. Within one axis the FIRST matching rule wins, and a member no rule matches lands in the implicit 14// class `other` of that axis -- so each axis is a PARTITION of the members by construction, and the census asserts the 15// sum. A row this parser does not understand is an ERROR counted with its line number: a malformed rules file cannot 16// produce a census (the CLI refuses), because a silently skipped rule moves members into `other` with no trace. 17// license_tier: ORIGINAL No hw writes (Rule 26). 18import "nx_syscalls.nx" 19 20const VCL_PAD: i64 = 16 21const VCL_ARENA_INIT: i64 = 65536 22const VCL_CELL: i64 = 8 23const VCL_A_PTR: i64 = 0 24const VCL_A_USED: i64 = 1 25const VCL_A_CAP: i64 = 2 26const VCL_A_N: i64 = 3 27 28const VCL_TAB: i64 = 9 29const VCL_LF: i64 = 10 30const VCL_CR: i64 = 13 31const VCL_SPACE: i64 = 32 32const VCL_HASHMARK: i64 = 35 33const VCL_SLASH: i64 = 47 34const VCL_DOT: i64 = 46 35const VCL_UPPER_A: i64 = 65 36const VCL_UPPER_Z: i64 = 90 37const VCL_CASE_OFF: i64 = 32 38const VCL_ASCII_0: i64 = 48 39const VCL_DEC: i64 = 10 40 41// counter 42const VCL_FNV_BASIS: i64 = 2166136261 43const VCL_FNV_PRIME: i64 = 16777619 44const VCL_U32_MASK: i64 = 0xffffffff 45const VCL_SLOTS_INIT: i64 = 256 46const VCL_E_W: i64 = 4 47const VCL_E_HASH: i64 = 0 48const VCL_E_KOFF: i64 = 1 49const VCL_E_KLEN: i64 = 2 50const VCL_E_COUNT: i64 = 3 51const VCL_C_SLOTS: i64 = 0 52const VCL_C_CAP: i64 = 1 53const VCL_C_NENT: i64 = 2 54const VCL_C_ENTS: i64 = 3 55const VCL_C_KEYS: i64 = 4 56const VCL_C_N: i64 = 5 57 58// rules 59const VCL_K_NONE: i64 = 0 60const VCL_K_DIRENT: i64 = 1 61const VCL_K_EXACT: i64 = 2 62const VCL_K_PREFIX: i64 = 3 63const VCL_K_SUFFIX: i64 = 4 64const VCL_K_CONTAINS: i64 = 5 65const VCL_AX_ROLE: i64 = 0 66const VCL_AX_FORMAT: i64 = 1 67const VCL_AX_N: i64 = 2 68const VCL_R_W: i64 = 8 69const VCL_R_AXIS: i64 = 0 70const VCL_R_CLASS: i64 = 1 71const VCL_R_K1: i64 = 2 72const VCL_R_P1: i64 = 3 73const VCL_R_L1: i64 = 4 74const VCL_R_K2: i64 = 5 75const VCL_R_P2: i64 = 6 76const VCL_R_L2: i64 = 7 77const VCL_S_W: i64 = 4 78const VCL_S_BIT: i64 = 0 79const VCL_S_KIND: i64 = 1 80const VCL_S_ARG: i64 = 2 81const VCL_S_LEN: i64 = 3 82const VCL_SK_CLASS: i64 = 1 83const VCL_SK_NAME: i64 = 2 84const VCL_T_W: i64 = 3 85const VCL_T_TAG: i64 = 0 86const VCL_T_P: i64 = 1 87const VCL_T_L: i64 = 2 88const VCL_REASONS: i64 = 26 89const VCL_MAX_FIELDS: i64 = 8 90// rules box 91const VCL_RS_RULES: i64 = 0 92const VCL_RS_NRULES: i64 = 1 93const VCL_RS_STR: i64 = 2 94const VCL_RS_CLASS_ROLE: i64 = 3 95const VCL_RS_CLASS_FORMAT: i64 = 4 96const VCL_RS_OTHER_ROLE: i64 = 5 97const VCL_RS_OTHER_FORMAT: i64 = 6 98const VCL_RS_SCREEN: i64 = 7 99const VCL_RS_NSCREEN: i64 = 8 100const VCL_RS_DEPTAG: i64 = 9 101const VCL_RS_NDEPTAG: i64 = 10 102const VCL_RS_TAGS: i64 = 11 103const VCL_RS_ERRORS: i64 = 12 104const VCL_RS_FIRST_ERR_LINE: i64 = 13 105const VCL_RS_N: i64 = 16 106const VCL_OTHER: *u8 = "other" 107 108func vcl_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 109func vcl_lc(c: i64) -> i64 { if c >= VCL_UPPER_A { if c <= VCL_UPPER_Z { return c + VCL_CASE_OFF } } return c } 110func vcl_lower(src: *u8, n: i64, out: *u8) -> i64 { 111 var i: i64 = 0 112 while i < n { out[i] = vcl_lc(src[i] as i64 & 0xff) as u8; i = i + 1 } 113 out[n] = 0 as u8 114 return n 115} 116func vcl_eq(a: *u8, ao: i64, b: *u8, bo: i64, n: i64) -> i64 { 117 var i: i64 = 0 118 while i < n { if (a[ao+i] as i64 & 0xff) != (b[bo+i] as i64 & 0xff) { return 0 } i = i + 1 } 119 return 1 120} 121 122// ---- (1) ARENA ---- 123func vcl_arena_new(init: i64) -> *i64 { 124 let a: *i64 = sys_mmap(VCL_A_N * VCL_CELL) as *i64 125 var cap: i64 = init 126 if cap < VCL_ARENA_INIT { cap = VCL_ARENA_INIT } 127 a[VCL_A_PTR] = sys_mmap(cap + VCL_PAD) as i64 128 a[VCL_A_USED] = 0 129 a[VCL_A_CAP] = cap 130 return a 131} 132func vcl_arena_reserve(a: *i64, extra: i64) -> i64 { 133 let need: i64 = a[VCL_A_USED] + extra 134 if need <= a[VCL_A_CAP] { return 1 } 135 var ncap: i64 = a[VCL_A_CAP] * 2 136 while ncap < need { ncap = ncap * 2 } 137 let nb: *u8 = sys_mmap(ncap + VCL_PAD) 138 if (nb as i64) <= 0 { return 0 } 139 let ob: *u8 = a[VCL_A_PTR] as *u8 140 let used: i64 = a[VCL_A_USED] 141 var i: i64 = 0 142 while i < used { nb[i] = ob[i]; i = i + 1 } 143 sys_munmap(ob, a[VCL_A_CAP] + VCL_PAD) 144 a[VCL_A_PTR] = nb as i64 145 a[VCL_A_CAP] = ncap 146 return 1 147} 148func vcl_at(a: *i64, off: i64) -> *u8 { return (a[VCL_A_PTR] + off) as *u8 } 149func vcl_used(a: *i64) -> i64 { return a[VCL_A_USED] } 150// store n bytes plus a NUL; returns the offset or -1 151func vcl_put(a: *i64, src: *u8, so: i64, n: i64) -> i64 { 152 if vcl_arena_reserve(a, n + 1) == 0 { return 0 - 1 } 153 let b: *u8 = a[VCL_A_PTR] as *u8 154 let off: i64 = a[VCL_A_USED] 155 var i: i64 = 0 156 while i < n { b[off+i] = src[so+i]; i = i + 1 } 157 b[off+n] = 0 as u8 158 a[VCL_A_USED] = off + n + 1 159 return off 160} 161// text appenders (no terminator): bytes, a NUL-terminated string, one byte, a decimal, TSV-clean bytes 162func vcl_app(a: *i64, src: *u8, so: i64, n: i64) -> i64 { 163 if vcl_arena_reserve(a, n) == 0 { return 0 } 164 let b: *u8 = a[VCL_A_PTR] as *u8 165 let off: i64 = a[VCL_A_USED] 166 var i: i64 = 0 167 while i < n { b[off+i] = src[so+i]; i = i + 1 } 168 a[VCL_A_USED] = off + n 169 return 1 170} 171func vcl_apps(a: *i64, s: *u8) -> i64 { return vcl_app(a, s, 0, vcl_slen(s)) } 172func vcl_appc(a: *i64, c: i64) -> i64 { 173 if vcl_arena_reserve(a, 1) == 0 { return 0 } 174 let b: *u8 = a[VCL_A_PTR] as *u8 175 b[a[VCL_A_USED]] = c as u8 176 a[VCL_A_USED] = a[VCL_A_USED] + 1 177 return 1 178} 179func vcl_appn(a: *i64, v: i64) -> i64 { 180 if vcl_arena_reserve(a, 24) == 0 { return 0 } 181 let b: *u8 = a[VCL_A_PTR] as *u8 182 var p: i64 = a[VCL_A_USED] 183 var m: i64 = v 184 if m < 0 { b[p] = 45 as u8; p = p + 1; m = 0 - m } 185 if m == 0 { b[p] = VCL_ASCII_0 as u8; a[VCL_A_USED] = p + 1; return 1 } 186 let s: i64 = p 187 while m > 0 { b[p] = (VCL_ASCII_0 + (m % VCL_DEC)) as u8; m = m / VCL_DEC; p = p + 1 } 188 var i: i64 = s 189 var j: i64 = p - 1 190 while i < j { let t: u8 = b[i]; b[i] = b[j]; b[j] = t; i = i + 1; j = j - 1 } 191 a[VCL_A_USED] = p 192 return 1 193} 194// TSV-clean: TAB, CR, LF and every control byte become a space, so a value can never open a column or a row 195func vcl_appclean(a: *i64, src: *u8, so: i64, n: i64) -> i64 { 196 if vcl_arena_reserve(a, n) == 0 { return 0 } 197 let b: *u8 = a[VCL_A_PTR] as *u8 198 let off: i64 = a[VCL_A_USED] 199 var i: i64 = 0 200 while i < n { 201 let c: i64 = src[so+i] as i64 & 0xff 202 if c < VCL_SPACE { b[off+i] = VCL_SPACE as u8 } else { b[off+i] = c as u8 } 203 i = i + 1 204 } 205 a[VCL_A_USED] = off + n 206 return 1 207} 208func vcl_push(a: *i64, v: i64) -> i64 { 209 if vcl_arena_reserve(a, VCL_CELL) == 0 { return 0 } 210 let cell: *i64 = (a[VCL_A_PTR] + a[VCL_A_USED]) as *i64 211 cell[0] = v 212 a[VCL_A_USED] = a[VCL_A_USED] + VCL_CELL 213 return 1 214} 215func vcl_vec_n(a: *i64) -> i64 { return a[VCL_A_USED] / VCL_CELL } 216func vcl_vec_at(a: *i64, i: i64) -> i64 { let cell: *i64 = (a[VCL_A_PTR] + i * VCL_CELL) as *i64; return cell[0] } 217 218// ---- (2) COUNTER ---- 219func vcl_hash(s: *u8, so: i64, n: i64) -> i64 { 220 var h: i64 = VCL_FNV_BASIS 221 var i: i64 = 0 222 while i < n { 223 h = h ^ (s[so+i] as i64 & 0xff) 224 h = (h * VCL_FNV_PRIME) & VCL_U32_MASK 225 i = i + 1 226 } 227 return h 228} 229func vcl_counter_new() -> *i64 { 230 let c: *i64 = sys_mmap(VCL_C_N * VCL_CELL) as *i64 231 c[VCL_C_SLOTS] = sys_mmap(VCL_SLOTS_INIT * VCL_CELL) as i64 232 c[VCL_C_CAP] = VCL_SLOTS_INIT 233 c[VCL_C_NENT] = 0 234 c[VCL_C_ENTS] = vcl_arena_new(VCL_ARENA_INIT) as i64 235 c[VCL_C_KEYS] = vcl_arena_new(VCL_ARENA_INIT) as i64 236 return c 237} 238func vcl_ent(c: *i64, idx: i64) -> *i64 { 239 let ents: *i64 = c[VCL_C_ENTS] as *i64 240 return (ents[VCL_A_PTR] + idx * VCL_E_W * VCL_CELL) as *i64 241} 242func vcl_counter_n(c: *i64) -> i64 { return c[VCL_C_NENT] } 243func vcl_counter_count(c: *i64, idx: i64) -> i64 { let e: *i64 = vcl_ent(c, idx); return e[VCL_E_COUNT] } 244func vcl_counter_key(c: *i64, idx: i64) -> *u8 { let e: *i64 = vcl_ent(c, idx); return vcl_at(c[VCL_C_KEYS] as *i64, e[VCL_E_KOFF]) } 245func vcl_counter_klen(c: *i64, idx: i64) -> i64 { let e: *i64 = vcl_ent(c, idx); return e[VCL_E_KLEN] } 246func vcl_counter_rehash(c: *i64, ncap: i64) -> i64 { 247 let ns: *i64 = sys_mmap(ncap * VCL_CELL) as *i64 248 if (ns as i64) <= 0 { return 0 } 249 let mask: i64 = ncap - 1 250 var k: i64 = 0 251 while k < c[VCL_C_NENT] { 252 let e: *i64 = vcl_ent(c, k) 253 var i: i64 = e[VCL_E_HASH] & mask 254 var run: i64 = 1 255 while run == 1 { if ns[i] == 0 { ns[i] = k + 1; run = 0 } else { i = (i + 1) & mask } } 256 k = k + 1 257 } 258 sys_munmap(c[VCL_C_SLOTS] as *u8, c[VCL_C_CAP] * VCL_CELL) 259 c[VCL_C_SLOTS] = ns as i64 260 c[VCL_C_CAP] = ncap 261 return 1 262} 263// add inc to key src[so..so+n); returns the entry index (first-seen order) or -1 264func vcl_counter_add(c: *i64, src: *u8, so: i64, n: i64, inc: i64) -> i64 { 265 let h: i64 = vcl_hash(src, so, n) 266 let slots: *i64 = c[VCL_C_SLOTS] as *i64 267 let mask: i64 = c[VCL_C_CAP] - 1 268 let keys: *i64 = c[VCL_C_KEYS] as *i64 269 var i: i64 = h & mask 270 var run: i64 = 1 271 while run == 1 { 272 let s: i64 = slots[i] 273 if s == 0 { run = 0 } else { 274 let e: *i64 = vcl_ent(c, s - 1) 275 if e[VCL_E_HASH] == h { if e[VCL_E_KLEN] == n { if vcl_eq(vcl_at(keys, e[VCL_E_KOFF]), 0, src, so, n) == 1 { 276 e[VCL_E_COUNT] = e[VCL_E_COUNT] + inc 277 return s - 1 278 } } } 279 i = (i + 1) & mask 280 } 281 } 282 let koff: i64 = vcl_put(keys, src, so, n) 283 if koff < 0 { return 0 - 1 } 284 let ents: *i64 = c[VCL_C_ENTS] as *i64 285 if vcl_push(ents, h) == 0 { return 0 - 1 } 286 vcl_push(ents, koff) 287 vcl_push(ents, n) 288 vcl_push(ents, inc) 289 let idx: i64 = c[VCL_C_NENT] 290 slots[i] = idx + 1 291 c[VCL_C_NENT] = idx + 1 292 if (idx + 1) * 2 > c[VCL_C_CAP] { vcl_counter_rehash(c, c[VCL_C_CAP] * 2) } 293 return idx 294} 295// index of key without adding, or -1 296func vcl_counter_find(c: *i64, src: *u8, so: i64, n: i64) -> i64 { 297 let h: i64 = vcl_hash(src, so, n) 298 let slots: *i64 = c[VCL_C_SLOTS] as *i64 299 let mask: i64 = c[VCL_C_CAP] - 1 300 let keys: *i64 = c[VCL_C_KEYS] as *i64 301 var i: i64 = h & mask 302 var run: i64 = 1 303 while run == 1 { 304 let s: i64 = slots[i] 305 if s == 0 { run = 0 } else { 306 let e: *i64 = vcl_ent(c, s - 1) 307 if e[VCL_E_HASH] == h { if e[VCL_E_KLEN] == n { if vcl_eq(vcl_at(keys, e[VCL_E_KOFF]), 0, src, so, n) == 1 { return s - 1 } } } 308 i = (i + 1) & mask 309 } 310 } 311 return 0 - 1 312} 313 314// ---- (3) RULES ---- 315func vcl_kind(src: *u8, so: i64, n: i64) -> i64 { 316 let lit: *u8 = sys_mmap(n + 1) 317 vcl_lower(((src as i64) + so) as *u8, n, lit) 318 if n == 6 { if vcl_eq(lit, 0, "dirent" as *u8, 0, 6) == 1 { return VCL_K_DIRENT } } 319 if n == 5 { if vcl_eq(lit, 0, "exact" as *u8, 0, 5) == 1 { return VCL_K_EXACT } } 320 if n == 6 { if vcl_eq(lit, 0, "prefix" as *u8, 0, 6) == 1 { return VCL_K_PREFIX } } 321 if n == 6 { if vcl_eq(lit, 0, "suffix" as *u8, 0, 6) == 1 { return VCL_K_SUFFIX } } 322 if n == 8 { if vcl_eq(lit, 0, "contains" as *u8, 0, 8) == 1 { return VCL_K_CONTAINS } } 323 return VCL_K_NONE 324} 325func vcl_field_is(src: *u8, so: i64, n: i64, lit: *u8) -> i64 { 326 if vcl_slen(lit) != n { return 0 } 327 return vcl_eq(src, so, lit, 0, n) 328} 329// store a lowercased copy of src[so..so+n) in the strings arena; returns its offset 330func vcl_put_lower(str: *i64, src: *u8, so: i64, n: i64) -> i64 { 331 let tmp: *u8 = sys_mmap(n + 1) 332 vcl_lower(((src as i64) + so) as *u8, n, tmp) 333 return vcl_put(str, tmp, 0, n) 334} 335func vcl_rules_err(rs: *i64, line: i64) -> i64 { 336 if rs[VCL_RS_ERRORS] == 0 { rs[VCL_RS_FIRST_ERR_LINE] = line } 337 rs[VCL_RS_ERRORS] = rs[VCL_RS_ERRORS] + 1 338 return 0 339} 340 341// parse the rules text; returns the rules box (check VCL_RS_ERRORS before use) 342func vcl_rules_parse(text: *u8, n: i64) -> *i64 { 343 let rs: *i64 = sys_mmap(VCL_RS_N * VCL_CELL) as *i64 344 rs[VCL_RS_RULES] = vcl_arena_new(VCL_ARENA_INIT) as i64 345 rs[VCL_RS_NRULES] = 0 346 rs[VCL_RS_STR] = vcl_arena_new(VCL_ARENA_INIT) as i64 347 rs[VCL_RS_CLASS_ROLE] = vcl_counter_new() as i64 348 rs[VCL_RS_CLASS_FORMAT] = vcl_counter_new() as i64 349 rs[VCL_RS_SCREEN] = vcl_arena_new(VCL_ARENA_INIT) as i64 350 rs[VCL_RS_NSCREEN] = 0 351 rs[VCL_RS_DEPTAG] = vcl_arena_new(VCL_ARENA_INIT) as i64 352 rs[VCL_RS_NDEPTAG] = 0 353 rs[VCL_RS_TAGS] = vcl_counter_new() as i64 354 rs[VCL_RS_ERRORS] = 0 355 rs[VCL_RS_FIRST_ERR_LINE] = 0 356 let rules: *i64 = rs[VCL_RS_RULES] as *i64 357 let str: *i64 = rs[VCL_RS_STR] as *i64 358 let fs: *i64 = sys_mmap(VCL_MAX_FIELDS * VCL_CELL) as *i64 359 let fl: *i64 = sys_mmap(VCL_MAX_FIELDS * VCL_CELL) as *i64 360 // screen rows naming a class are resolved AFTER every class row is read, so row order in the file cannot matter 361 let pend: *i64 = vcl_arena_new(VCL_ARENA_INIT) 362 var line: i64 = 0 363 var p: i64 = 0 364 while p < n { 365 var q: i64 = p 366 var qrun: i64 = 1 367 while qrun == 1 { if q >= n { qrun = 0 } else { if (text[q] as i64 & 0xff) == VCL_LF { qrun = 0 } else { q = q + 1 } } } 368 var e: i64 = q 369 if e > n { e = n } 370 var ee: i64 = e 371 if ee > p { if (text[ee-1] as i64 & 0xff) == VCL_CR { ee = ee - 1 } } 372 line = line + 1 373 var skip: i64 = 0 374 if ee <= p { skip = 1 } else { if (text[p] as i64 & 0xff) == VCL_HASHMARK { skip = 1 } } 375 if skip == 0 { 376 var nf: i64 = 0 377 var s: i64 = p 378 var k: i64 = p 379 while k <= ee { 380 var at_end: i64 = 0 381 if k == ee { at_end = 1 } else { if (text[k] as i64 & 0xff) == VCL_TAB { at_end = 1 } } 382 if at_end == 1 { 383 if nf < VCL_MAX_FIELDS { fs[nf] = s; fl[nf] = k - s } 384 nf = nf + 1 385 s = k + 1 386 } 387 k = k + 1 388 } 389 var axis: i64 = 0 - 1 390 if vcl_field_is(text, fs[0], fl[0], "role" as *u8) == 1 { axis = VCL_AX_ROLE } 391 if vcl_field_is(text, fs[0], fl[0], "format" as *u8) == 1 { axis = VCL_AX_FORMAT } 392 if axis >= 0 { 393 var ok: i64 = 1 394 if nf != 4 { if nf != 6 { ok = 0 } } 395 if nf > VCL_MAX_FIELDS { ok = 0 } 396 if ok == 1 { 397 let k1: i64 = vcl_kind(text, fs[2], fl[2]) 398 var k2: i64 = VCL_K_NONE 399 if nf == 6 { k2 = vcl_kind(text, fs[4], fl[4]); if k2 == VCL_K_NONE { ok = 0 } } 400 if k1 == VCL_K_NONE { ok = 0 } 401 if fl[1] <= 0 { ok = 0 } 402 if ok == 1 { 403 var cc: *i64 = rs[VCL_RS_CLASS_ROLE] as *i64 404 if axis == VCL_AX_FORMAT { cc = rs[VCL_RS_CLASS_FORMAT] as *i64 } 405 let cls: i64 = vcl_counter_add(cc, text, fs[1], fl[1], 0) 406 vcl_push(rules, axis) 407 vcl_push(rules, cls) 408 vcl_push(rules, k1) 409 vcl_push(rules, vcl_put_lower(str, text, fs[3], fl[3])) 410 vcl_push(rules, fl[3]) 411 vcl_push(rules, k2) 412 if nf == 6 { 413 vcl_push(rules, vcl_put_lower(str, text, fs[5], fl[5])) 414 vcl_push(rules, fl[5]) 415 } else { vcl_push(rules, 0 - 1); vcl_push(rules, 0) } 416 rs[VCL_RS_NRULES] = rs[VCL_RS_NRULES] + 1 417 } 418 } 419 if ok == 0 { vcl_rules_err(rs, line) } 420 } else { 421 if vcl_field_is(text, fs[0], fl[0], "screen" as *u8) == 1 { 422 var ok2: i64 = 1 423 if nf != 4 { ok2 = 0 } 424 var bit: i64 = 0 - 1 425 if ok2 == 1 { 426 if fl[1] != 1 { ok2 = 0 } else { 427 let letter: i64 = text[fs[1]] as i64 & 0xff 428 if letter >= VCL_UPPER_A { if letter <= VCL_UPPER_Z { bit = letter - VCL_UPPER_A } } 429 if bit < 0 { ok2 = 0 } 430 } 431 } 432 if ok2 == 1 { 433 if vcl_field_is(text, fs[2], fl[2], "class" as *u8) == 1 { 434 vcl_push(pend, bit) 435 vcl_push(pend, fs[3]) 436 vcl_push(pend, fl[3]) 437 vcl_push(pend, line) 438 } else { 439 if vcl_field_is(text, fs[2], fl[2], "namecontains" as *u8) == 1 { 440 let sc: *i64 = rs[VCL_RS_SCREEN] as *i64 441 vcl_push(sc, bit) 442 vcl_push(sc, VCL_SK_NAME) 443 vcl_push(sc, vcl_put_lower(str, text, fs[3], fl[3])) 444 vcl_push(sc, fl[3]) 445 rs[VCL_RS_NSCREEN] = rs[VCL_RS_NSCREEN] + 1 446 } else { ok2 = 0 } 447 } 448 } 449 if ok2 == 0 { vcl_rules_err(rs, line) } 450 } else { 451 if vcl_field_is(text, fs[0], fl[0], "deptag" as *u8) == 1 { 452 var ok3: i64 = 1 453 if nf != 4 { ok3 = 0 } 454 if ok3 == 1 { if vcl_field_is(text, fs[2], fl[2], "prefix" as *u8) == 0 { ok3 = 0 } } 455 if ok3 == 1 { 456 let tg: *i64 = rs[VCL_RS_DEPTAG] as *i64 457 let tag: i64 = vcl_counter_add(rs[VCL_RS_TAGS] as *i64, text, fs[1], fl[1], 0) 458 vcl_push(tg, tag) 459 vcl_push(tg, vcl_put_lower(str, text, fs[3], fl[3])) 460 vcl_push(tg, fl[3]) 461 rs[VCL_RS_NDEPTAG] = rs[VCL_RS_NDEPTAG] + 1 462 } 463 if ok3 == 0 { vcl_rules_err(rs, line) } 464 } else { vcl_rules_err(rs, line) } 465 } 466 } 467 } 468 p = e + 1 469 } 470 // the implicit `other` class of each axis 471 rs[VCL_RS_OTHER_ROLE] = vcl_counter_add(rs[VCL_RS_CLASS_ROLE] as *i64, VCL_OTHER, 0, vcl_slen(VCL_OTHER), 0) 472 rs[VCL_RS_OTHER_FORMAT] = vcl_counter_add(rs[VCL_RS_CLASS_FORMAT] as *i64, VCL_OTHER, 0, vcl_slen(VCL_OTHER), 0) 473 // resolve screen rows that name a role class 474 let npend: i64 = vcl_vec_n(pend) / VCL_S_W 475 var pi: i64 = 0 476 while pi < npend { 477 let pb: i64 = vcl_vec_at(pend, pi * VCL_S_W) 478 let po: i64 = vcl_vec_at(pend, pi * VCL_S_W + 1) 479 let pl: i64 = vcl_vec_at(pend, pi * VCL_S_W + 2) 480 let pln: i64 = vcl_vec_at(pend, pi * VCL_S_W + 3) 481 let ci: i64 = vcl_counter_find(rs[VCL_RS_CLASS_ROLE] as *i64, text, po, pl) 482 if ci < 0 { vcl_rules_err(rs, pln) } else { 483 let sc2: *i64 = rs[VCL_RS_SCREEN] as *i64 484 vcl_push(sc2, pb) 485 vcl_push(sc2, VCL_SK_CLASS) 486 vcl_push(sc2, ci) 487 vcl_push(sc2, 0) 488 rs[VCL_RS_NSCREEN] = rs[VCL_RS_NSCREEN] + 1 489 } 490 pi = pi + 1 491 } 492 return rs 493} 494 495func vcl_nclasses(rs: *i64, axis: i64) -> i64 { 496 if axis == VCL_AX_ROLE { return vcl_counter_n(rs[VCL_RS_CLASS_ROLE] as *i64) } 497 return vcl_counter_n(rs[VCL_RS_CLASS_FORMAT] as *i64) 498} 499func vcl_class_name(rs: *i64, axis: i64, idx: i64) -> *u8 { 500 if axis == VCL_AX_ROLE { return vcl_counter_key(rs[VCL_RS_CLASS_ROLE] as *i64, idx) } 501 return vcl_counter_key(rs[VCL_RS_CLASS_FORMAT] as *i64, idx) 502} 503 504// does lowercased name[0..nl) satisfy (kind, pattern)? 505func vcl_match(kind: i64, name: *u8, nl: i64, pat: *u8, pl: i64) -> i64 { 506 if kind == VCL_K_DIRENT { if nl > 0 { if (name[nl-1] as i64 & 0xff) == VCL_SLASH { return 1 } } return 0 } 507 if kind == VCL_K_EXACT { if nl != pl { return 0 } return vcl_eq(name, 0, pat, 0, pl) } 508 if kind == VCL_K_PREFIX { if nl < pl { return 0 } return vcl_eq(name, 0, pat, 0, pl) } 509 if kind == VCL_K_SUFFIX { if nl < pl { return 0 } return vcl_eq(name, nl - pl, pat, 0, pl) } 510 if kind == VCL_K_CONTAINS { 511 if pl == 0 { return 1 } 512 var i: i64 = 0 513 while i + pl <= nl { if vcl_eq(name, i, pat, 0, pl) == 1 { return 1 } i = i + 1 } 514 return 0 515 } 516 return 0 517} 518 519// the class of a lowercased member name on one axis: the first matching rule of that axis, else `other` 520func vcl_classify(rs: *i64, axis: i64, name: *u8, nl: i64) -> i64 { 521 let rules: *i64 = rs[VCL_RS_RULES] as *i64 522 let str: *i64 = rs[VCL_RS_STR] as *i64 523 let nr: i64 = rs[VCL_RS_NRULES] 524 var r: i64 = 0 525 while r < nr { 526 let base: i64 = r * VCL_R_W 527 if vcl_vec_at(rules, base + VCL_R_AXIS) == axis { 528 let k1: i64 = vcl_vec_at(rules, base + VCL_R_K1) 529 if vcl_match(k1, name, nl, vcl_at(str, vcl_vec_at(rules, base + VCL_R_P1)), vcl_vec_at(rules, base + VCL_R_L1)) == 1 { 530 let k2: i64 = vcl_vec_at(rules, base + VCL_R_K2) 531 var both: i64 = 1 532 if k2 != VCL_K_NONE { 533 both = vcl_match(k2, name, nl, vcl_at(str, vcl_vec_at(rules, base + VCL_R_P2)), vcl_vec_at(rules, base + VCL_R_L2)) 534 } 535 if both == 1 { return vcl_vec_at(rules, base + VCL_R_CLASS) } 536 } 537 } 538 r = r + 1 539 } 540 if axis == VCL_AX_ROLE { return rs[VCL_RS_OTHER_ROLE] } 541 return rs[VCL_RS_OTHER_FORMAT] 542} 543 544// the real-person-screen reason bitmask of one package: role class counts (index = role class) plus the lowercased id 545func vcl_screen(rs: *i64, role_counts: *i64, id_lc: *u8, idl: i64) -> i64 { 546 let sc: *i64 = rs[VCL_RS_SCREEN] as *i64 547 let str: *i64 = rs[VCL_RS_STR] as *i64 548 var mask: i64 = 0 549 var i: i64 = 0 550 while i < rs[VCL_RS_NSCREEN] { 551 let base: i64 = i * VCL_S_W 552 let bit: i64 = vcl_vec_at(sc, base + VCL_S_BIT) 553 let kind: i64 = vcl_vec_at(sc, base + VCL_S_KIND) 554 var hit: i64 = 0 555 if kind == VCL_SK_CLASS { if role_counts[vcl_vec_at(sc, base + VCL_S_ARG)] > 0 { hit = 1 } } 556 if kind == VCL_SK_NAME { hit = vcl_match(VCL_K_CONTAINS, id_lc, idl, vcl_at(str, vcl_vec_at(sc, base + VCL_S_ARG)), vcl_vec_at(sc, base + VCL_S_LEN)) } 557 if hit == 1 { 558 var b: i64 = 1 559 var s: i64 = 0 560 while s < bit { b = b * 2; s = s + 1 } 561 if (mask / b) % 2 == 0 { mask = mask + b } 562 } 563 i = i + 1 564 } 565 return mask 566} 567 568// the deptag of one lowercased dependency id (first matching deptag row), or -1 569func vcl_deptag(rs: *i64, dep_lc: *u8, dl: i64) -> i64 { 570 let tg: *i64 = rs[VCL_RS_DEPTAG] as *i64 571 let str: *i64 = rs[VCL_RS_STR] as *i64 572 var i: i64 = 0 573 while i < rs[VCL_RS_NDEPTAG] { 574 let base: i64 = i * VCL_T_W 575 if vcl_match(VCL_K_PREFIX, dep_lc, dl, vcl_at(str, vcl_vec_at(tg, base + VCL_T_P)), vcl_vec_at(tg, base + VCL_T_L)) == 1 { 576 return vcl_vec_at(tg, base + VCL_T_TAG) 577 } 578 i = i + 1 579 } 580 return 0 - 1 581} 582 583// write the letters of a reason mask (A..Z) into a; "-" when empty 584func vcl_app_reasons(a: *i64, mask: i64) -> i64 { 585 if mask == 0 { return vcl_appc(a, 45) } 586 var m: i64 = mask 587 var bit: i64 = 0 588 while bit < VCL_REASONS { 589 if m % 2 == 1 { vcl_appc(a, VCL_UPPER_A + bit) } 590 m = m / 2 591 bit = bit + 1 592 } 593 return 1 594}