| ... | @@ -7,7 +7,7 @@ pub const Style = union(enum) { | ... | @@ -7,7 +7,7 @@ pub const Style = union(enum) { |
| 7 | /// The configure format supported by autotools. It uses `#undef foo` to | 7 | /// The configure format supported by autotools. It uses `#undef foo` to |
| 8 | /// mark lines that can be substituted with different values. | 8 | /// mark lines that can be substituted with different values. |
| 9 | autoconf: std.Build.LazyPath, | 9 | autoconf: std.Build.LazyPath, |
| 10 | /// The configure format supported by CMake. It uses `@@FOO@@` and | 10 | /// The configure format supported by CMake. It uses `@FOO@`, `${}` and |
| 11 | /// `#cmakedefine` for template substitution. | 11 | /// `#cmakedefine` for template substitution. |
| 12 | cmake: std.Build.LazyPath, | 12 | cmake: std.Build.LazyPath, |
| 13 | /// Instead of starting with an input file, start with nothing. | 13 | /// Instead of starting with an input file, start with nothing. |
| ... | @@ -32,28 +32,6 @@ pub const Value = union(enum) { | ... | @@ -32,28 +32,6 @@ pub const Value = union(enum) { |
| 32 | string: []const u8, | 32 | string: []const u8, |
| 33 | }; | 33 | }; |
| 34 | | 34 | |
| 35 | fn formatValueCMake(data: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | | |
| 36 | _ = fmt; | | |
| 37 | _ = options; | | |
| 38 | | | |
| 39 | switch (data) { | | |
| 40 | .undef, .defined => {}, | | |
| 41 | .boolean => |b| { | | |
| 42 | try writer.print("{d}", .{@intFromBool(b)}); | | |
| 43 | }, | | |
| 44 | .int => |i| { | | |
| 45 | try writer.print("{d}", .{i}); | | |
| 46 | }, | | |
| 47 | .ident, .string => |s| { | | |
| 48 | try writer.writeAll(s); | | |
| 49 | }, | | |
| 50 | } | | |
| 51 | } | | |
| 52 | | | |
| 53 | fn fmtValueCMake(value: Value) std.fmt.Formatter(formatValueCMake) { | | |
| 54 | return .{ .data = value }; | | |
| 55 | } | | |
| 56 | | | |
| 57 | step: Step, | 35 | step: Step, |
| 58 | values: std.StringArrayHashMap(Value), | 36 | values: std.StringArrayHashMap(Value), |
| 59 | output_file: std.Build.GeneratedFile, | 37 | output_file: std.Build.GeneratedFile, |
| ... | @@ -344,7 +322,11 @@ fn render_cmake( | ... | @@ -344,7 +322,11 @@ fn render_cmake( |
| 344 | continue; | 322 | continue; |
| 345 | }, | 323 | }, |
| 346 | else => { | 324 | else => { |
| 347 | @panic("Failed to substitute"); | 325 | try step.addError("{s}:{d}: unable to substitute variable: error: {s}", .{ |
| | 326 | src_path, line_index + 1, @errorName(err), |
| | 327 | }); |
| | 328 | any_errors = true; |
| | 329 | continue; |
| 348 | }, | 330 | }, |
| 349 | }; | 331 | }; |
| 350 | defer allocator.free(line); | 332 | defer allocator.free(line); |
| ... | @@ -549,8 +531,8 @@ fn expand_variables_cmake( | ... | @@ -549,8 +531,8 @@ fn expand_variables_cmake( |
| 549 | contents: []const u8, | 531 | contents: []const u8, |
| 550 | values: std.StringArrayHashMap(Value), | 532 | values: std.StringArrayHashMap(Value), |
| 551 | ) ![]const u8 { | 533 | ) ![]const u8 { |
| 552 | var result = allocator.alloc(u8, 0) catch @panic("OOM"); | 534 | var result = std.ArrayList(u8).init(allocator); |
| 553 | errdefer allocator.free(result); | 535 | errdefer result.deinit(); |
| 554 | | 536 | |
| 555 | const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_.+-"; | 537 | const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_.+-"; |
| 556 | const open_var = "${"; | 538 | const open_var = "${"; |
| ... | @@ -571,8 +553,8 @@ fn expand_variables_cmake( | ... | @@ -571,8 +553,8 @@ fn expand_variables_cmake( |
| 571 | // closed immediately, preserve as a literal | 553 | // closed immediately, preserve as a literal |
| 572 | break :blk; | 554 | break :blk; |
| 573 | } | 555 | } |
| 574 | const valid_varname_end = std.mem.indexOfNonePos(u8, contents, curr + 1, valid_varname_chars); | 556 | const valid_varname_end = std.mem.indexOfNonePos(u8, contents, curr + 1, valid_varname_chars) orelse 0; |
| 575 | if (valid_varname_end == null or valid_varname_end != close_pos) { | 557 | if (valid_varname_end != close_pos) { |
| 576 | // contains invalid characters, preserve as a literal | 558 | // contains invalid characters, preserve as a literal |
| 577 | break :blk; | 559 | break :blk; |
| 578 | } | 560 | } |
| ... | @@ -580,9 +562,19 @@ fn expand_variables_cmake( | ... | @@ -580,9 +562,19 @@ fn expand_variables_cmake( |
| 580 | const key = contents[curr + 1 .. close_pos]; | 562 | const key = contents[curr + 1 .. close_pos]; |
| 581 | const value = values.get(key) orelse .undef; | 563 | const value = values.get(key) orelse .undef; |
| 582 | const missing = contents[source_offset..curr]; | 564 | const missing = contents[source_offset..curr]; |
| 583 | const buf = try std.fmt.allocPrint(allocator, "{s}{s}{}", .{ result, missing, fmtValueCMake(value) }); | 565 | try result.appendSlice(missing); |
| 584 | allocator.free(result); | 566 | switch (value) { |
| 585 | result = buf; | 567 | .undef, .defined => {}, |
| | 568 | .boolean => |b| { |
| | 569 | try result.append(if (b) '1' else '0'); |
| | 570 | }, |
| | 571 | .int => |i| { |
| | 572 | try result.writer().print("{d}", .{i}); |
| | 573 | }, |
| | 574 | .ident, .string => |s| { |
| | 575 | try result.appendSlice(s); |
| | 576 | }, |
| | 577 | } |
| 586 | | 578 | |
| 587 | curr = close_pos; | 579 | curr = close_pos; |
| 588 | source_offset = close_pos + 1; | 580 | source_offset = close_pos + 1; |
| ... | @@ -597,15 +589,14 @@ fn expand_variables_cmake( | ... | @@ -597,15 +589,14 @@ fn expand_variables_cmake( |
| 597 | break :blk; | 589 | break :blk; |
| 598 | } | 590 | } |
| 599 | const missing = contents[source_offset..curr]; | 591 | const missing = contents[source_offset..curr]; |
| 600 | const buf = try std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ result, missing, open_var }); | 592 | try result.appendSlice(missing); |
| 601 | allocator.free(result); | 593 | try result.appendSlice(open_var); |
| 602 | result = buf; | | |
| 603 | | 594 | |
| 604 | source_offset = curr + open_var.len; | 595 | source_offset = curr + open_var.len; |
| 605 | curr = next; | 596 | curr = next; |
| 606 | try var_stack.append(Position{ | 597 | try var_stack.append(Position{ |
| 607 | .source = curr, | 598 | .source = curr, |
| 608 | .target = result.len - open_var.len, | 599 | .target = result.items.len - open_var.len, |
| 609 | }); | 600 | }); |
| 610 | | 601 | |
| 611 | continue :loop; | 602 | continue :loop; |
| ... | @@ -620,14 +611,24 @@ fn expand_variables_cmake( | ... | @@ -620,14 +611,24 @@ fn expand_variables_cmake( |
| 620 | source_offset += open_var.len; | 611 | source_offset += open_var.len; |
| 621 | } | 612 | } |
| 622 | const missing = contents[source_offset..curr]; | 613 | const missing = contents[source_offset..curr]; |
| 623 | const key_start = open_pos.target + open_var.len; | 614 | try result.appendSlice(missing); |
| 624 | const key = try std.fmt.allocPrint(allocator, "{s}{s}", .{ result[key_start..], missing }); | | |
| 625 | defer allocator.free(key); | | |
| 626 | | 615 | |
| | 616 | const key_start = open_pos.target + open_var.len; |
| | 617 | const key = result.items[key_start..]; |
| 627 | const value = values.get(key) orelse .undef; | 618 | const value = values.get(key) orelse .undef; |
| 628 | const buf = try std.fmt.allocPrint(allocator, "{s}{}", .{ result[0..open_pos.target], fmtValueCMake(value) }); | 619 | result.shrinkRetainingCapacity(result.items.len - key.len - open_var.len); |
| 629 | allocator.free(result); | 620 | switch (value) { |
| 630 | result = buf; | 621 | .undef, .defined => {}, |
| | 622 | .boolean => |b| { |
| | 623 | try result.append(if (b) '1' else '0'); |
| | 624 | }, |
| | 625 | .int => |i| { |
| | 626 | try result.writer().print("{d}", .{i}); |
| | 627 | }, |
| | 628 | .ident, .string => |s| { |
| | 629 | try result.appendSlice(s); |
| | 630 | }, |
| | 631 | } |
| 631 | | 632 | |
| 632 | source_offset = curr + 1; | 633 | source_offset = curr + 1; |
| 633 | | 634 | |
| ... | @@ -646,12 +647,11 @@ fn expand_variables_cmake( | ... | @@ -646,12 +647,11 @@ fn expand_variables_cmake( |
| 646 | } | 647 | } |
| 647 | | 648 | |
| 648 | if (source_offset != contents.len) { | 649 | if (source_offset != contents.len) { |
| 649 | const buf = try std.fmt.allocPrint(allocator, "{s}{s}", .{ result, contents[source_offset..] }); | 650 | const missing = contents[source_offset..]; |
| 650 | allocator.free(result); | 651 | try result.appendSlice(missing); |
| 651 | result = buf; | | |
| 652 | } | 652 | } |
| 653 | | 653 | |
| 654 | return result; | 654 | return result.toOwnedSlice(); |
| 655 | } | 655 | } |
| 656 | | 656 | |
| 657 | fn testReplaceVariables( | 657 | fn testReplaceVariables( |