code wiki / (root) / nx_bills_entry.nx

nx_bills_entry.nx source

↩ module page · 50 lines · 2696 B

1// nx_bills_entry.nx -- the BILL-ENTRY data path: turns a person's submitted bill form (a urlencoded POST 2// body from the zero-JS "add a bill" form behind the opaque wall) into a stored bill (bs_add), so the 3// situation dashboard runs on the person's REAL recurring bills instead of representative ones. Reuses the 4// existing nx_http_form_get_field parser (DRY -- same one intake + the login route use), with the proven 5// NUL-terminate-at-length fix so a reused scratch buffer never bleeds digits between fields. Money fields are 6// entered in whole dollars and stored in cents (the engines are no-float cents). No hardware writes. 7// license_tier: ORIGINAL 8import "nx_syscalls.nx" 9import "nx_http_form.nx" 10import "nx_bills_store.nx" 11import "nx_bills.nx" 12 13func be_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 14 15// decimal parse of a NUL-terminated (or length-bounded) digit string. Ignores a leading '-' (bills are >=0). 16func be_atoi(s: *u8) -> i64 { 17 var v: i64 = 0 18 var i: i64 = 0 19 while s[i] != (0 as u8) { 20 let c: i64 = s[i] as i64 21 if c >= 0x30 { if c <= 0x39 { v = v * 10 + (c - 0x30) } } 22 i = i + 1 23 } 24 return v 25} 26 27// parse one integer field from the urlencoded body (0 if absent/empty). `scratch` is a caller buffer. 28func be_field(body: *u8, body_n: i64, name: *u8, scratch: *u8, scratch_cap: i64) -> i64 { 29 let vl: *i64 = sys_mmap(16) as *i64 30 vl[0] = 0 31 nx_http_form_get_field(body, body_n, name, be_len(name), scratch, scratch_cap, vl) 32 if vl[0] <= 0 { return 0 } 33 if vl[0] < scratch_cap { scratch[vl[0]] = 0 as u8 } // NUL-terminate at the parsed length (parser returns 34 // len, not a terminator) -- the bug the intake gate caught 35 return be_atoi(scratch) 36} 37 38// record one bill from a urlencoded form body. Money (bill_amount) is dollars -> cents. Sane defaults: 39// cadence<=0 -> monthly(1); due_day<=0 -> 1. returns bs_add's result (0 ok). Field names are data. 40func be_record(prefix: *u8, respondent: *u8, body: *u8, body_n: i64) -> i64 { 41 let sc: *u8 = sys_mmap(128) 42 let amount: i64 = be_field(body, body_n, "bill_amount\x00" as *u8, sc, 127) * 100 43 var cadence: i64 = be_field(body, body_n, "bill_cadence\x00" as *u8, sc, 127) 44 var due_day: i64 = be_field(body, body_n, "bill_due_day\x00" as *u8, sc, 127) 45 let cat: i64 = be_field(body, body_n, "bill_category\x00" as *u8, sc, 127) 46 let paid: i64 = be_field(body, body_n, "bill_paid\x00" as *u8, sc, 127) 47 if cadence <= 0 { cadence = 1 } 48 if due_day <= 0 { due_day = 1 } 49 return bs_add(prefix, respondent, amount, cadence, due_day, cat, paid) 50}