code wiki / (root) / ini_writer.nx

ini_writer.nx source

↩ module page · 104 lines · 3349 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 22import "syscalls.nx" 23 24const IW_ERR_SHORT: i64 = -1 25 26func iw_put(out: *u8, cap: i64, off: i64, src: *u8, n: i64) -> i64 { 27 if off + n > cap { return IW_ERR_SHORT } 28 var i: i64 = 0 29 while i < n { 30 out[off + i] = src[i] 31 i = i + 1 32 } 33 return off + n 34} 35 36// Write \"[name]\\n\". 37func ini_writer_section(out: *u8, cap: i64, off: i64, 38 name: *u8, name_len: i64) -> i64 { 39 var cur: i64 = off 40 cur = iw_put(out, cap, cur, "[", 1) 41 if cur < 0 { return cur } 42 cur = iw_put(out, cap, cur, name, name_len) 43 if cur < 0 { return cur } 44 cur = iw_put(out, cap, cur, "]\n", 2) 45 return cur 46} 47 48// Write \"key = value\\n\". 49func ini_writer_kv(out: *u8, cap: i64, off: i64, 50 key: *u8, key_len: i64, 51 val: *u8, val_len: i64) -> i64 { 52 var cur: i64 = off 53 cur = iw_put(out, cap, cur, key, key_len) 54 if cur < 0 { return cur } 55 cur = iw_put(out, cap, cur, " = ", 3) 56 if cur < 0 { return cur } 57 cur = iw_put(out, cap, cur, val, val_len) 58 if cur < 0 { return cur } 59 cur = iw_put(out, cap, cur, "\n", 1) 60 return cur 61} 62 63// Write \"; comment\\n\". 64func ini_writer_comment(out: *u8, cap: i64, off: i64, 65 text: *u8, text_len: i64) -> i64 { 66 var cur: i64 = off 67 cur = iw_put(out, cap, cur, "; ", 2) 68 if cur < 0 { return cur } 69 cur = iw_put(out, cap, cur, text, text_len) 70 if cur < 0 { return cur } 71 cur = iw_put(out, cap, cur, "\n", 1) 72 return cur 73} 74 75// Blank line separator. 76func ini_writer_blank(out: *u8, cap: i64, off: i64) -> i64 { 77 return iw_put(out, cap, off, "\n", 1) 78} 79 80// Compile-only smoke. 81func main() -> i64 { 82 let out: *u8 = sys_mmap(256) 83 var off: i64 = 0 84 85 off = ini_writer_comment(out, 256, off, "Nishi config", 12) 86 if off < 0 { return 1 } 87 off = ini_writer_section(out, 256, off, "db", 2) 88 if off < 0 { return 2 } 89 off = ini_writer_kv(out, 256, off, "host", 4, "127.0.0.1", 9) 90 if off < 0 { return 3 } 91 off = ini_writer_kv(out, 256, off, "port", 4, "5432", 4) 92 if off < 0 { return 4 } 93 off = ini_writer_blank(out, 256, off) 94 if off < 0 { return 5 } 95 off = ini_writer_section(out, 256, off, "log", 3) 96 if off < 0 { return 6 } 97 off = ini_writer_kv(out, 256, off, "level", 5, "info", 4) 98 if off < 0 { return 7 } 99 100 // First two bytes: \"; \" 101 if out[0] != 0x3B { return 8 } // ';' 102 if out[1] != 0x20 { return 9 } // ' ' 103 return 0 104}