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}