From e313e334873580d56cae9d097a43a50103c4e7a5 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Thu, 18 Sep 2025 14:42:22 -0700 Subject: [PATCH] patched utilities.c / zig build test works with parser --- build.zig | 54 +++++++++++++++++++++++++++++++++++++------ build.zig.zon | 40 +++----------------------------- sed-lite/src/main.zig | 13 +++++++---- src/root.zig | 3 --- 4 files changed, 59 insertions(+), 51 deletions(-) diff --git a/build.zig b/build.zig index d170dee..f2ddc3b 100644 --- a/build.zig +++ b/build.zig @@ -26,6 +26,50 @@ pub fn build(b: *std.Build) void { const upstream = download_link_step.dependency(b, .{}); + // mod tests fail because the library has unconditional output to stdout, + // which messes with the test runner. So...we need to patch utilities.c with search: + // printf(" Opening + // + // replace: + // if ( verbosity > 0 ) printf(" Opening + // + + const Substitutions = struct { orig: []const u8, new: []const u8 }; + const patterns: [4]Substitutions = .{ + .{ + .orig = "\tprintf(\" Opening %s\\n\", filename); ", + .new = "\tif ( verbosity > 0 ) printf(\" Opening %s\\n\", filename); ", + }, + .{ + .orig = "\tprintf(\" Opening %s\\n\", filename);", + .new = "\tif ( verbosity > 0 ) printf(\" Opening %s\\n\", filename);", + }, + .{ + .orig = "\t printf(\" Opening %s\\n\", completename); ", + .new = "\t if ( verbosity > 0 ) printf(\" Opening %s\\n\", completename); ", + }, + .{ + .orig = " printf(\" Opening %s\\n\", completename); ", + .new = " if ( verbosity > 0 ) printf(\" Opening %s\\n\", completename); ", + }, + }; + + // pat5 is same as pat3 + //const pat5 = \t printf(" Opening %s\n", completename); "; + + // Create sed-lite run step to patch utilities.c + const sed_lite = b.dependency("sed_lite", .{}); + const sed_lite_exe = sed_lite.artifact("sed-lite"); + + const patch_cmd = b.addRunArtifact(sed_lite_exe); + patch_cmd.addArg("-sL"); + for (patterns) |s| { + patch_cmd.addArg(s.orig); + patch_cmd.addArg(s.new); + } + patch_cmd.addFileArg(upstream.path("src/utilities.c")); + patch_cmd.step.dependOn(&download_link_step.step); + const lib = b.addLibrary(.{ .name = "link", .linkage = .static, @@ -36,7 +80,7 @@ pub fn build(b: *std.Build) void { }), }); - lib.step.dependOn(&download_link_step.step); + lib.step.dependOn(&patch_cmd.step); lib.addIncludePath(upstream.path("include")); lib.addCSourceFiles(.{ @@ -78,6 +122,7 @@ pub fn build(b: *std.Build) void { "-fwrapv", }, }); + // This creates a module, which represents a collection of source files alongside // some compilation options, such as optimization mode and linked system libraries. // Zig modules are the preferred way of making Zig code available to consumers. @@ -211,12 +256,7 @@ pub fn build(b: *std.Build) void { // make the two of them run in parallel. const test_step = b.step("test", "Run tests"); - // mod tests fail because we need to patch utilities.c with search: - // printf(" Opening - // - // replace: - // if ( verbosity > 0 ) printf(" Opening - //test_step.dependOn(&run_mod_tests.step); + test_step.dependOn(&run_mod_tests.step); test_step.dependOn(&run_exe_tests.step); // Just like flags, top level steps are also listed in the `--help` menu. diff --git a/build.zig.zon b/build.zig.zon index 29fa25a..9c4175e 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -32,44 +32,10 @@ // Once all dependencies are fetched, `zig build` no longer requires // internet connectivity. .dependencies = .{ - // See `zig fetch --save ` for a command-line interface for adding dependencies. - //.example = .{ - // // When updating this field to a new URL, be sure to delete the corresponding - // // `hash`, otherwise you are communicating that you expect to find the old hash at - // // the new URL. If the contents of a URL change this will result in a hash mismatch - // // which will prevent zig from using it. - // .url = "https://example.com/foo.tar.gz", - // - // // This is computed from the file contents of the directory of files that is - // // obtained after fetching `url` and applying the inclusion rules given by - // // `paths`. - // // - // // This field is the source of truth; packages do not come from a `url`; they - // // come from a `hash`. `url` is just one of many possible mirrors for how to - // // obtain a package matching this `hash`. - // // - // // Uses the [multihash](https://multiformats.io/multihash/) format. - // .hash = "...", - // - // // When this is provided, the package is found in a directory relative to the - // // build root. In this case the package's hash is irrelevant and therefore not - // // computed. This field and `url` are mutually exclusive. - // .path = "foo", - // - // // When this is set to `true`, a package is declared to be lazily - // // fetched. This makes the dependency only get fetched if it is - // // actually used. - // .lazy = false, - //}, + .sed_lite = .{ + .path = "sed-lite", + }, }, - // Specifies the set of files and directories that are included in this package. - // Only files and directories listed here are included in the `hash` that - // is computed for this package. Only files listed here will remain on disk - // when using the zig package manager. As a rule of thumb, one should list - // files required for compilation plus any license(s). - // Paths are relative to the build root. Use the empty string (`""`) to refer to - // the build root itself. - // A directory listed here means that all files within, recursively, are included. .paths = .{ "build.zig", "build.zig.zon", diff --git a/sed-lite/src/main.zig b/sed-lite/src/main.zig index f5639ff..33cfd6b 100644 --- a/sed-lite/src/main.zig +++ b/sed-lite/src/main.zig @@ -37,6 +37,8 @@ pub fn main() !u8 { .original = args[2 + i * 2], .replacement = args[3 + i * 2], }; + // const s = substitutions[i]; + // try stdout.print("Replacing {s} -> {s}\n", .{ s.original, s.replacement }); } const file = std.fs.cwd().openFile(file_path, .{ .mode = .read_only }) catch |err| { @@ -61,12 +63,14 @@ pub fn main() !u8 { var writer_buffer: [4096]u8 = undefined; var fwriter = temp_file.writer(&writer_buffer); const writer = &fwriter.interface; - try substituteLines( + const subs = try substituteLines( reader, writer, substitutions, ); try writer.flush(); + _ = subs; + // try stdout.print("Made {d} substitutions in file {s}\n", .{ subs, file_path }); std.fs.cwd().rename(temp_path, file_path) catch |err| { try stderr.print("Error moving temp file: {}\n", .{err}); return 1; @@ -83,13 +87,15 @@ const Substitution = struct { replacement: []const u8, }; -fn substituteLines(reader: *std.Io.Reader, writer: *std.Io.Writer, substitutions: []const Substitution) !void { +fn substituteLines(reader: *std.Io.Reader, writer: *std.Io.Writer, substitutions: []const Substitution) !usize { + var subs: usize = 0; while (reader.takeDelimiterExclusive('\n')) |line| { var substituted = false; for (substitutions) |sub| { if (std.mem.eql(u8, line, sub.original)) { try writer.writeAll(sub.replacement); substituted = true; + subs += 1; break; } } @@ -99,8 +105,7 @@ fn substituteLines(reader: *std.Io.Reader, writer: *std.Io.Writer, substitutions if (reader.peekByte() != error.EndOfStream) try writer.writeByte('\n'); } else |err| if (err != error.EndOfStream) return err; - // write the final newline - // try writer.writeByte('\n'); + return subs; } test "substitute lines exact match" { diff --git a/src/root.zig b/src/root.zig index 9b00160..a0afd05 100644 --- a/src/root.zig +++ b/src/root.zig @@ -38,7 +38,6 @@ pub const Parser = struct { allocator: std.mem.Allocator, pub fn init(allocator: std.mem.Allocator) !Parser { - std.debug.print("1", .{}); const dict = c.dictionary_create( @ptrCast(@constCast("data/4.0.dict")), @ptrCast(@constCast("data/4.0.knowledge")), @@ -47,10 +46,8 @@ pub const Parser = struct { ); if (dict == null) return error.DictionaryCreationFailed; - std.debug.print("2", .{}); const opts = c.parse_options_create(); if (opts == null) return error.ParseOptionsCreationFailed; - std.debug.print("3", .{}); c.parse_options_set_verbosity(opts, 0); c.parse_options_set_linkage_limit(opts, 100);