code wiki / (root) / nx_ini_writer.nx

nx_ini_writer.nx source

↩ module page · 110 lines · 3499 B

1// ini_writer.nx -- serialise INI-style config. 2// 3// Companion to ini.nx (reader). Stream builder emits files 4// that ini.nx round-trips exactly: 5// [section] 6// key = value 7// ; comment 8// 9// We always use \" = \" (space-equals-space) separator and LF line 10// endings. This matches typical Unix convention; Windows tools 11// tolerate LF. 12// 13// Invariants: 14// IW1 Keys and values emitted verbatim -- no escaping. INI 15// has no standard escape form; values with newlines are 16// inherently unsafe in INI, caller pre-sanitises. 17// IW2 ini_writer_section groups the next keys under that name 18// until another section is opened. 19// IW3 Round-trip: ini.nx parsing our output yields the 20// original (section, key, value) tuples. 21 22// nx_safety_envelope: 23// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 24// sil_target: SIL1 25// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 26// verdict: NOT_YET_EVALUATED 27 28import "nx_syscalls.nx" 29 30const IW_ERR_SHORT: i64 = -1 31 32func iw_put(out: *u8, cap: i64, off: i64, src: *u8, n: i64) -> i64 { 33 if off + n > cap { return IW_ERR_SHORT } 34 var i: i64 = 0 35 while i < n { 36 out[off + i] = src[i] 37 i = i + 1 38 } 39 return off + n 40} 41 42// Write \"[name]\\n\". 43func ini_writer_section(out: *u8, cap: i64, off: i64, 44 name: *u8, name_len: i64) -> i64 { 45 var cur: i64 = off 46 cur = iw_put(out, cap, cur, "[", 1) 47 if cur < 0 { return cur } 48 cur = iw_put(out, cap, cur, name, name_len) 49 if cur < 0 { return cur } 50 cur = iw_put(out, cap, cur, "]\n", 2) 51 return cur 52} 53 54// Write \"key = value\\n\". 55func ini_writer_kv(out: *u8, cap: i64, off: i64, 56 key: *u8, key_len: i64, 57 val: *u8, val_len: i64) -> i64 { 58 var cur: i64 = off 59 cur = iw_put(out, cap, cur, key, key_len) 60 if cur < 0 { return cur } 61 cur = iw_put(out, cap, cur, " = ", 3) 62 if cur < 0 { return cur } 63 cur = iw_put(out, cap, cur, val, val_len) 64 if cur < 0 { return cur } 65 cur = iw_put(out, cap, cur, "\n", 1) 66 return cur 67} 68 69// Write \"; comment\\n\". 70func ini_writer_comment(out: *u8, cap: i64, off: i64, 71 text: *u8, text_len: i64) -> i64 { 72 var cur: i64 = off 73 cur = iw_put(out, cap, cur, "; ", 2) 74 if cur < 0 { return cur } 75 cur = iw_put(out, cap, cur, text, text_len) 76 if cur < 0 { return cur } 77 cur = iw_put(out, cap, cur, "\n", 1) 78 return cur 79} 80 81// Blank line separator. 82func ini_writer_blank(out: *u8, cap: i64, off: i64) -> i64 { 83 return iw_put(out, cap, off, "\n", 1) 84} 85 86// Compile-only smoke. 87func main() -> i64 { 88 let out: *u8 = sys_mmap(256) 89 var off: i64 = 0 90 91 off = ini_writer_comment(out, 256, off, "Nishi config", 12) 92 if off < 0 { return 1 } 93 off = ini_writer_section(out, 256, off, "db", 2) 94 if off < 0 { return 2 } 95 off = ini_writer_kv(out, 256, off, "host", 4, "127.0.0.1", 9) 96 if off < 0 { return 3 } 97 off = ini_writer_kv(out, 256, off, "port", 4, "5432", 4) 98 if off < 0 { return 4 } 99 off = ini_writer_blank(out, 256, off) 100 if off < 0 { return 5 } 101 off = ini_writer_section(out, 256, off, "log", 3) 102 if off < 0 { return 6 } 103 off = ini_writer_kv(out, 256, off, "level", 5, "info", 4) 104 if off < 0 { return 7 } 105 106 // First two bytes: \"; \" 107 if out[0] != 0x3B { return 8 } // ';' 108 if out[1] != 0x20 { return 9 } // ' ' 109 return 0 110}