feature. See also
. The project being documented here (as the example) is the Zig library itself.
cli.Options
pub const Options = struct
File
Code
pub const Options = struct {
allocator: Allocator,
input_source: IoSource = .{ .filename = &[_]u8{} },
output_source: IoSource = .{ .filename = &[_]u8{} },
extra_include_paths: std.ArrayList([]const u8) = .empty,
ignore_include_env_var: bool = false,
preprocess: Preprocess = .yes,
default_language_id: ?u16 = null,
default_code_page: ?SupportedCodePage = null,
verbose: bool = false,
symbols: std.array_hash_map.String(SymbolValue) = .empty,
null_terminate_string_table_strings: bool = false,
max_string_literal_codepoints: u15 = lex.default_max_string_literal_codepoints,
silent_duplicate_control_ids: bool = false,
warn_instead_of_error_on_invalid_code_page: bool = false,
debug: bool = false,
print_help_and_exit: bool = false,
auto_includes: AutoIncludes = .any,
depfile_path: ?[]const u8 = null,
depfile_fmt: DepfileFormat = .json,
input_format: InputFormat = .rc,
output_format: OutputFormat = .res,
coff_options: cvtres.CoffOptions = .{},
pub const IoSource = union(enum) {
stdio: Io.File,
filename: []const u8,
};
pub const AutoIncludes = enum { any, msvc, gnu, none };
pub const DepfileFormat = enum { json };
pub const InputFormat = enum { rc, res, rcpp };
pub const OutputFormat = enum {
res,
coff,
rcpp,
pub fn extension(format: OutputFormat) []const u8 {
return switch (format) {
.rcpp => ".rcpp",
.coff => ".obj",
.res => ".res",
};
}
};
pub const Preprocess = enum { no, yes, only };
pub const SymbolAction = enum { define, undefine };
pub const SymbolValue = union(SymbolAction) {
define: []const u8,
undefine: void,
pub fn deinit(self: SymbolValue, allocator: Allocator) void {
switch (self) {
.define => |value| allocator.free(value),
.undefine => {},
}
}
};
pub fn define(self: *Options, identifier: []const u8, value: []const u8) !void {
if (self.symbols.getPtr(identifier)) |val_ptr| {
// we shouldn't change anything.
if (val_ptr.* == .undefine) return;
const duped_value = try self.allocator.dupe(u8, value);
errdefer self.allocator.free(duped_value);
val_ptr.deinit(self.allocator);
val_ptr.* = .{ .define = duped_value };
return;
}
const duped_key = try self.allocator.dupe(u8, identifier);
errdefer self.allocator.free(duped_key);
const duped_value = try self.allocator.dupe(u8, value);
errdefer self.allocator.free(duped_value);
try self.symbols.put(self.allocator, duped_key, .{ .define = duped_value });
}
pub fn undefine(self: *Options, identifier: []const u8) !void {
if (self.symbols.getPtr(identifier)) |action| {
action.deinit(self.allocator);
action.* = .{ .undefine = {} };
return;
}
const duped_key = try self.allocator.dupe(u8, identifier);
errdefer self.allocator.free(duped_key);
try self.symbols.put(self.allocator, duped_key, .{ .undefine = {} });
}
pub fn maybeAppendRC(options: *Options, io: Io, cwd: Io.Dir) !void {
switch (options.input_source) {
.stdio => return,
.filename => {},
}
if (options.input_format == .rc and std.fs.path.extension(options.input_source.filename).len == 0) {
cwd.access(io, options.input_source.filename, .{}) catch |err| switch (err) {
error.FileNotFound => {
var filename_bytes = try options.allocator.alloc(u8, options.input_source.filename.len + 3);
@memcpy(filename_bytes[0..options.input_source.filename.len], options.input_source.filename);
@memcpy(filename_bytes[filename_bytes.len - 3 ..], ".rc");
options.allocator.free(options.input_source.filename);
options.input_source = .{ .filename = filename_bytes };
},
else => {},
};
}
}
pub fn deinit(self: *Options) void {
for (self.extra_include_paths.items) |extra_include_path| {
self.allocator.free(extra_include_path);
}
self.extra_include_paths.deinit(self.allocator);
switch (self.input_source) {
.stdio => {},
.filename => |filename| self.allocator.free(filename),
}
switch (self.output_source) {
.stdio => {},
.filename => |filename| self.allocator.free(filename),
}
var symbol_it = self.symbols.iterator();
while (symbol_it.next()) |entry| {
self.allocator.free(entry.key_ptr.*);
entry.value_ptr.deinit(self.allocator);
}
self.symbols.deinit(self.allocator);
if (self.depfile_path) |depfile_path| {
self.allocator.free(depfile_path);
}
if (self.coff_options.define_external_symbol) |symbol_name| {
self.allocator.free(symbol_name);
}
}
pub fn dumpVerbose(self: *const Options, writer: *std.Io.Writer) !void {
const input_source_name = switch (self.input_source) {
.stdio => "<stdin>",
.filename => |filename| filename,
};
const output_source_name = switch (self.output_source) {
.stdio => "<stdout>",
.filename => |filename| filename,
};
try writer.print("Input filename: {s} (format={s})\n", .{ input_source_name, @tagName(self.input_format) });
try writer.print("Output filename: {s} (format={s})\n", .{ output_source_name, @tagName(self.output_format) });
if (self.output_format == .coff) {
try writer.print(" Target machine type for COFF: {s}\n", .{@tagName(self.coff_options.target)});
}
if (self.extra_include_paths.items.len > 0) {
try writer.writeAll(" Extra include paths:\n");
for (self.extra_include_paths.items) |extra_include_path| {
try writer.print(" \"{s}\"\n", .{extra_include_path});
}
}
if (self.ignore_include_env_var) {
try writer.writeAll(" The INCLUDE environment variable will be ignored\n");
}
if (self.preprocess == .no) {
try writer.writeAll(" The preprocessor will not be invoked\n");
} else if (self.preprocess == .only) {
try writer.writeAll(" Only the preprocessor will be invoked\n");
}
if (self.symbols.count() > 0) {
try writer.writeAll(" Symbols:\n");
var it = self.symbols.iterator();
while (it.next()) |symbol| {
try writer.print(" {s} {s}", .{ switch (symbol.value_ptr.*) {
.define => "#define",
.undefine => "#undef",
}, symbol.key_ptr.* });
if (symbol.value_ptr.* == .define) {
try writer.print(" {s}", .{symbol.value_ptr.define});
}
try writer.writeAll("\n");
}
}
if (self.null_terminate_string_table_strings) {
try writer.writeAll(" Strings in string tables will be null-terminated\n");
}
if (self.max_string_literal_codepoints != lex.default_max_string_literal_codepoints) {
try writer.print(" Max string literal length: {}\n", .{self.max_string_literal_codepoints});
}
if (self.silent_duplicate_control_ids) {
try writer.writeAll(" Duplicate control IDs will not emit warnings\n");
}
if (self.silent_duplicate_control_ids) {
try writer.writeAll(" Invalid code page in .rc will produce a warning (instead of an error)\n");
}
const language_id = self.default_language_id orelse res.Language.default;
const language_name = language_name: {
if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| {
break :language_name @tagName(lang_enum_val);
}
if (language_id == lang.LOCALE_CUSTOM_UNSPECIFIED) {
break :language_name "LOCALE_CUSTOM_UNSPECIFIED";
}
break :language_name "<UNKNOWN>";
};
try writer.print("Default language: {s} (id=0x{x})\n", .{ language_name, language_id });
const code_page = self.default_code_page orelse .windows1252;
try writer.print("Default codepage: {s} (id={})\n", .{ @tagName(code_page), @backingInt(code_page) });
}
}