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}