@@ -34,85 +34,96 @@ fn insertNulTerminator(slice: []const u8) [:0]const u8 {
3434 return mut_ptr [0.. slice .len :0 ];
3535}
3636
37- pub fn Parser (comptime Reader : type ) type {
38- return struct {
39- const Self = @This ();
40-
41- allocator : std.mem.Allocator ,
42- line_buffer : std .array_list .Managed (u8 ),
43- reader : Reader ,
44- comment_characters : []const u8 ,
45-
46- pub fn deinit (self : * Self ) void {
47- self .line_buffer .deinit ();
48- self .* = undefined ;
49- }
50-
51- pub fn next (self : * Self ) ! ? Record {
52- while (true ) {
53- self .reader .readUntilDelimiterArrayList (& self .line_buffer , '\n ' , 4096 ) catch | err | switch (err ) {
37+ pub const Parser = struct {
38+ const Self = @This ();
39+
40+ allocator : std.mem.Allocator ,
41+ line_buffer : std .array_list .Managed (u8 ),
42+ reader : * std.io.Reader ,
43+ comment_characters : []const u8 ,
44+
45+ pub fn deinit (self : * Self ) void {
46+ self .line_buffer .deinit ();
47+ self .* = undefined ;
48+ }
49+
50+ pub fn next (self : * Self ) ! ? Record {
51+ var write_buffer : [1024 ]u8 = undefined ;
52+ var old_writer_adapter = self .line_buffer .writer ().adaptToNewApi (& write_buffer );
53+ var writer = & old_writer_adapter .new_interface ;
54+ self .line_buffer .clearRetainingCapacity ();
55+ while (true ) {
56+ _ = try self .reader .streamDelimiterLimit (writer , '\n ' , .limited (4096 ));
57+ try writer .flush ();
58+ const discarded = self .reader .discard (.limited (1 )) catch | e | blk : {
59+ switch (e ) {
5460 error .EndOfStream = > {
5561 if (self .line_buffer .items .len == 0 )
5662 return null ;
63+ break :blk 0 ;
5764 },
58- else = > | e | return e ,
59- };
60- try self .line_buffer .append (0 ); // append guaranteed space for sentinel
61-
62- var line : []const u8 = self .line_buffer .items ;
63- var last_index : usize = 0 ;
64-
65- // handle comments and escaping
66- while (last_index < line .len ) {
67- if (std .mem .indexOfAnyPos (u8 , line , last_index , self .comment_characters )) | index | {
68- // escape character if needed, then skip it (it's not a comment)
69- if (index > 0 ) {
70- const previous_index = index - 1 ;
71- const previous_char = line [previous_index ];
72-
73- if (previous_char == '\\ ' ) {
74- _ = self .line_buffer .orderedRemove (previous_index );
75- line = self .line_buffer .items ;
76-
77- last_index = index + 1 ;
78- continue ;
79- }
65+ else = > return e ,
66+ }
67+ };
68+ if (self .line_buffer .items .len == 0 and discarded == 0 )
69+ return null ;
70+ try self .line_buffer .append (0 ); // append guaranteed space for sentinel
71+
72+ var line : []const u8 = self .line_buffer .items ;
73+ var last_index : usize = 0 ;
74+
75+ // handle comments and escaping
76+ while (last_index < line .len ) {
77+ if (std .mem .indexOfAnyPos (u8 , line , last_index , self .comment_characters )) | index | {
78+ // escape character if needed, then skip it (it's not a comment)
79+ if (index > 0 ) {
80+ const previous_index = index - 1 ;
81+ const previous_char = line [previous_index ];
82+
83+ if (previous_char == '\\ ' ) {
84+ _ = self .line_buffer .orderedRemove (previous_index );
85+ line = self .line_buffer .items ;
86+
87+ last_index = index + 1 ;
88+ continue ;
8089 }
81-
82- line = std .mem .trim (u8 , line [0.. index ], whitespace );
83- } else {
84- line = std .mem .trim (u8 , line , whitespace );
8590 }
8691
87- break ;
92+ line = std .mem .trim (u8 , line [0.. index ], whitespace );
93+ } else {
94+ line = std .mem .trim (u8 , line , whitespace );
8895 }
8996
90- if ( line . len == 0 )
91- continue ;
97+ break ;
98+ }
9299
93- if (std .mem .startsWith (u8 , line , "[" ) and std .mem .endsWith (u8 , line , "]" )) {
94- return Record { .section = insertNulTerminator (line [1 .. line .len - 1 ]) };
95- }
100+ if (line .len == 0 ) {
101+ self .line_buffer .clearRetainingCapacity ();
102+ continue ;
103+ }
96104
97- if (std .mem .indexOfScalar (u8 , line , '=' )) | index | {
98- return Record {
99- .property = KeyValue {
100- // note: the key *might* replace the '=' in the slice with 0!
101- .key = insertNulTerminator (std .mem .trim (u8 , line [0.. index ], whitespace )),
102- .value = insertNulTerminator (std .mem .trim (u8 , line [index + 1 .. ], whitespace )),
103- },
104- };
105- }
105+ if (std .mem .startsWith (u8 , line , "[" ) and std .mem .endsWith (u8 , line , "]" )) {
106+ return Record { .section = insertNulTerminator (line [1 .. line .len - 1 ]) };
107+ }
106108
107- return Record { .enumeration = insertNulTerminator (line ) };
109+ if (std .mem .indexOfScalar (u8 , line , '=' )) | index | {
110+ return Record {
111+ .property = KeyValue {
112+ // note: the key *might* replace the '=' in the slice with 0!
113+ .key = insertNulTerminator (std .mem .trim (u8 , line [0.. index ], whitespace )),
114+ .value = insertNulTerminator (std .mem .trim (u8 , line [index + 1 .. ], whitespace )),
115+ },
116+ };
108117 }
118+
119+ return Record { .enumeration = insertNulTerminator (line ) };
109120 }
110- };
111- }
121+ }
122+ };
112123
113124/// Returns a new parser that can read the ini structure
114- pub fn parse (allocator : std.mem.Allocator , reader : anytype , comment_characters : []const u8 ) Parser ( @TypeOf ( reader )) {
115- return Parser ( @TypeOf ( reader )) {
125+ pub fn parse (allocator : std.mem.Allocator , reader : * std.io.Reader , comment_characters : []const u8 ) Parser {
126+ return Parser {
116127 .allocator = allocator ,
117128 .line_buffer = std .array_list .Managed (u8 ).init (allocator ),
118129 .reader = reader ,
0 commit comments