feature. See also
. The project being documented here (as the example) is the Zig library itself.
ConfigHeader.expandVariablesCmake
fn expandVariablesCmake(
arena: Allocator,
contents: []const u8,
conf: *const Configuration,
value_pairs: []const Value.Pair,
value_map: *const ValueMap,
) ![]const u8
File
Code
fn expandVariablesCmake(
arena: Allocator,
contents: []const u8,
conf: *const Configuration,
value_pairs: []const Value.Pair,
value_map: *const ValueMap,
) ![]const u8 {
var result: std.ArrayList(u8) = .empty;
const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_.+-";
const open_var = "${";
var curr: usize = 0;
var source_offset: usize = 0;
const Position = struct {
source: usize,
target: usize,
};
var var_stack: std.ArrayList(Position) = .empty;
loop: while (curr < contents.len) : (curr += 1) {
switch (contents[curr]) {
'@' => blk: {
if (std.mem.findScalarPos(u8, contents, curr + 1, '@')) |close_pos| {
if (close_pos == curr + 1) {
break :blk;
}
const valid_varname_end = std.mem.findNonePos(u8, contents, curr + 1, valid_varname_chars) orelse 0;
if (valid_varname_end != close_pos) {
break :blk;
}
const key = contents[curr + 1 .. close_pos];
const index = value_map.getIndex(key) orelse return error.MissingValue;
value_map.values()[index] = true;
const value = value_pairs[index].index;
const missing = contents[source_offset..curr];
try result.appendSlice(arena, missing);
switch (value.unpack(conf)) {
.undef, .defined => {},
.bool => |b| try result.append(arena, if (b) '1' else '0'),
inline .i64, .u64 => |i| try result.print(arena, "{d}", .{i}),
.ident, .string => |s| try result.appendSlice(arena, s),
}
curr = close_pos;
source_offset = close_pos + 1;
continue :loop;
}
},
'$' => blk: {
const next = curr + 1;
if (next == contents.len or contents[next] != '{') {
break :blk;
}
const missing = contents[source_offset..curr];
try result.appendSlice(arena, missing);
try result.appendSlice(arena, open_var);
source_offset = curr + open_var.len;
curr = next;
try var_stack.append(arena, .{
.source = curr,
.target = result.items.len - open_var.len,
});
continue :loop;
},
'}' => blk: {
if (var_stack.items.len == 0) {
break :blk;
}
const open_pos = var_stack.pop().?;
if (source_offset == open_pos.source) {
source_offset += open_var.len;
}
const missing = contents[source_offset..curr];
try result.appendSlice(arena, missing);
const key_start = open_pos.target + open_var.len;
const key = result.items[key_start..];
if (key.len == 0) {
return error.MissingKey;
}
const index = value_map.getIndex(key) orelse return error.MissingValue;
value_map.values()[index] = true;
const value = value_pairs[index].index;
result.shrinkRetainingCapacity(result.items.len - key.len - open_var.len);
switch (value.unpack(conf)) {
.undef, .defined => {},
.bool => |b| try result.append(arena, if (b) '1' else '0'),
inline .i64, .u64 => |i| try result.print(arena, "{d}", .{i}),
.ident, .string => |s| try result.appendSlice(arena, s),
}
source_offset = curr + 1;
continue :loop;
},
'\\' => {
continue :loop;
},
else => {},
}
if (var_stack.items.len > 0 and std.mem.findScalar(u8, valid_varname_chars, contents[curr]) == null) {
return error.InvalidCharacter;
}
}
if (source_offset != contents.len) {
const missing = contents[source_offset..];
try result.appendSlice(arena, missing);
}
try result.shrinkToLen(arena);
return result.toOwnedSliceAssert();
}