Type Function ArgIteratorGeneral [src]

A general Iterator to parse a string into a set of arguments

Prototype

pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type

Parameters

options: ArgIteratorGeneralOptions

Source

pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type { return struct { allocator: Allocator, index: usize = 0, cmd_line: []const u8, /// Should the cmd_line field be free'd (using the allocator) on deinit()? free_cmd_line_on_deinit: bool, /// buffer MUST be long enough to hold the cmd_line plus a null terminator. /// buffer will we free'd (using the allocator) on deinit() buffer: []u8, start: usize = 0, end: usize = 0, pub const Self = @This(); pub const InitError = error{OutOfMemory}; /// cmd_line_utf8 MUST remain valid and constant while using this instance pub fn init(allocator: Allocator, cmd_line_utf8: []const u8) InitError!Self { const buffer = try allocator.alloc(u8, cmd_line_utf8.len + 1); errdefer allocator.free(buffer); return Self{ .allocator = allocator, .cmd_line = cmd_line_utf8, .free_cmd_line_on_deinit = false, .buffer = buffer, }; } /// cmd_line_utf8 will be free'd (with the allocator) on deinit() pub fn initTakeOwnership(allocator: Allocator, cmd_line_utf8: []const u8) InitError!Self { const buffer = try allocator.alloc(u8, cmd_line_utf8.len + 1); errdefer allocator.free(buffer); return Self{ .allocator = allocator, .cmd_line = cmd_line_utf8, .free_cmd_line_on_deinit = true, .buffer = buffer, }; } // Skips over whitespace in the cmd_line. // Returns false if the terminating sentinel is reached, true otherwise. // Also skips over comments (if supported). fn skipWhitespace(self: *Self) bool { while (true) : (self.index += 1) { const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0; switch (character) { 0 => return false, ' ', '\t', '\r', '\n' => continue, '#' => { if (options.comments) { while (true) : (self.index += 1) { switch (self.cmd_line[self.index]) { '\n' => break, 0 => return false, else => continue, } } continue; } else { break; } }, else => break, } } return true; } pub fn skip(self: *Self) bool { if (!self.skipWhitespace()) { return false; } var backslash_count: usize = 0; var in_quote = false; while (true) : (self.index += 1) { const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0; switch (character) { 0 => return true, '"', '\'' => { if (!options.single_quotes and character == '\'') { backslash_count = 0; continue; } const quote_is_real = backslash_count % 2 == 0; if (quote_is_real) { in_quote = !in_quote; } }, '\\' => { backslash_count += 1; }, ' ', '\t', '\r', '\n' => { if (!in_quote) { return true; } backslash_count = 0; }, else => { backslash_count = 0; continue; }, } } } /// Returns a slice of the internal buffer that contains the next argument. /// Returns null when it reaches the end. pub fn next(self: *Self) ?[:0]const u8 { if (!self.skipWhitespace()) { return null; } var backslash_count: usize = 0; var in_quote = false; while (true) : (self.index += 1) { const character = if (self.index != self.cmd_line.len) self.cmd_line[self.index] else 0; switch (character) { 0 => { self.emitBackslashes(backslash_count); self.buffer[self.end] = 0; const token = self.buffer[self.start..self.end :0]; self.end += 1; self.start = self.end; return token; }, '"', '\'' => { if (!options.single_quotes and character == '\'') { self.emitBackslashes(backslash_count); backslash_count = 0; self.emitCharacter(character); continue; } const quote_is_real = backslash_count % 2 == 0; self.emitBackslashes(backslash_count / 2); backslash_count = 0; if (quote_is_real) { in_quote = !in_quote; } else { self.emitCharacter('"'); } }, '\\' => { backslash_count += 1; }, ' ', '\t', '\r', '\n' => { self.emitBackslashes(backslash_count); backslash_count = 0; if (in_quote) { self.emitCharacter(character); } else { self.buffer[self.end] = 0; const token = self.buffer[self.start..self.end :0]; self.end += 1; self.start = self.end; return token; } }, else => { self.emitBackslashes(backslash_count); backslash_count = 0; self.emitCharacter(character); }, } } } fn emitBackslashes(self: *Self, emit_count: usize) void { var i: usize = 0; while (i < emit_count) : (i += 1) { self.emitCharacter('\\'); } } fn emitCharacter(self: *Self, char: u8) void { self.buffer[self.end] = char; self.end += 1; } /// Call to free the internal buffer of the iterator. pub fn deinit(self: *Self) void { self.allocator.free(self.buffer); if (self.free_cmd_line_on_deinit) { self.allocator.free(self.cmd_line); } } }; }