some cleanup

This commit is contained in:
Emil Lerch 2025-09-18 11:02:58 -07:00
parent 7858c0f51c
commit 899d5fdfc5
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 92 additions and 28 deletions

View file

@ -1,31 +1,47 @@
const std = @import("std");
const print = std.debug.print;
pub fn main() !void {
pub fn main() !u8 {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var stdout_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
var stderr_writer = std.fs.File.stdout().writer(&.{});
const stdout = &stdout_writer.interface;
defer stdout.flush() catch {};
const stderr = &stderr_writer.interface;
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len < 2) {
print("Usage: {s} <operation> <operation args...> <file>\n", .{args[0]});
std.process.exit(1);
try stdout.print("Usage: {s} <operation> <operation args...> <file>\n", .{args[0]});
return 1;
}
const operation = args[1];
const file_path = args[args.len - 1];
if (std.mem.eql(u8, operation, "-sL")) {
if (args.len != 5) {
print("Usage: {s} -sL \"original string\" \"replacement string\" <file>\n", .{args[0]});
std.process.exit(1);
if (args.len < 5 or args.len % 2 != 1) {
try stderr.print("Usage: {s} -sL <\"original string\" \"replacement string\">... <file>\n", .{args[0]});
return 2;
}
const file = std.fs.cwd().openFile(file_path, .{}) catch |err| {
print("Error opening file '{s}': {}\n", .{ file_path, err });
std.process.exit(1);
const num_substitutions = (args.len - 3) / 2;
const substitutions = try allocator.alloc(Substitution, num_substitutions);
defer allocator.free(substitutions);
for (0..num_substitutions) |i| {
substitutions[i] = Substitution{
.original = args[2 + i * 2],
.replacement = args[3 + i * 2],
};
}
const file = std.fs.cwd().openFile(file_path, .{ .mode = .read_only }) catch |err| {
try stderr.print("Error opening file '{s}': {}\n", .{ file_path, err });
return 1;
};
defer file.close();
@ -35,8 +51,8 @@ pub fn main() !void {
defer allocator.free(temp_path);
const temp_file = std.fs.cwd().createFile(temp_path, .{}) catch |err| {
print("Error creating temp file: {}\n", .{err});
std.process.exit(1);
try stderr.print("Error creating temp file: {}\n", .{err});
return 1;
};
defer temp_file.close();
@ -46,29 +62,40 @@ pub fn main() !void {
try substituteLines(
&reader,
&writer,
args[2],
args[3],
substitutions,
);
try writer.flush();
std.fs.cwd().rename(temp_path, file_path) catch |err| {
print("Error moving temp file: {}\n", .{err});
std.process.exit(1);
try stderr.print("Error moving temp file: {}\n", .{err});
return 1;
};
} else {
print("Error: Unknown operation '{s}'\n", .{operation});
std.process.exit(1);
try stderr.print("Error: Unknown operation '{s}'\n", .{operation});
return 1;
}
return 0;
}
fn substituteLines(reader: *std.Io.Reader, writer: *std.Io.Writer, original: []const u8, replacement: []const u8) !void {
const Substitution = struct {
original: []const u8,
replacement: []const u8,
};
fn substituteLines(reader: *std.Io.Reader, writer: *std.Io.Writer, substitutions: []const Substitution) !void {
var line_buf: [1024]u8 = undefined;
var line = std.Io.Writer.fixed(&line_buf);
while ((try reader.streamDelimiterEnding(&line, '\n')) > 0) : (_ = line.consumeAll()) {
const line_content = line.buffered();
if (std.mem.eql(u8, line_content, original))
try writer.writeAll(replacement)
else
var substituted = false;
for (substitutions) |sub| {
if (std.mem.eql(u8, line_content, sub.original)) {
try writer.writeAll(sub.replacement);
substituted = true;
break;
}
}
if (!substituted)
try writer.writeAll(line_content);
// Write our \n
@ -86,11 +113,14 @@ test "substitute lines exact match" {
var output_buf: [1024]u8 = undefined;
var output_stream = std.Io.Writer.fixed(&output_buf);
const substitutions = [_]Substitution{
.{ .original = "replace_me", .replacement = "new_line" },
};
try substituteLines(
&input_stream,
&output_stream,
"replace_me",
"new_line",
&substitutions,
);
const result = output_stream.buffered();
@ -104,11 +134,14 @@ test "no match found" {
var output_buf: [1024]u8 = undefined;
var output_stream = std.Io.Writer.fixed(&output_buf);
const substitutions = [_]Substitution{
.{ .original = "nonexistent", .replacement = "replacement" },
};
try substituteLines(
&input_stream,
&output_stream,
"nonexistent",
"replacement",
&substitutions,
);
const result = output_stream.buffer[0..output_stream.end];
@ -123,11 +156,37 @@ test "partial match not replaced" {
var output_buf: [1024]u8 = undefined;
var output_stream = std.Io.Writer.fixed(&output_buf);
const substitutions = [_]Substitution{
.{ .original = "match", .replacement = "replaced" },
};
try substituteLines(
&input_stream,
&output_stream,
"match",
"replaced",
&substitutions,
);
const result = output_stream.buffered();
try std.testing.expectEqualStrings(expected, result);
}
test "multiple substitutions" {
const test_content = "line1\nreplace_me\nline3\nreplace_also\nline5";
const expected = "line1\nnew_line\nline3\nalso_new\nline5";
var input_stream = std.Io.Reader.fixed(test_content);
var output_buf: [1024]u8 = undefined;
var output_stream = std.Io.Writer.fixed(&output_buf);
const substitutions = [_]Substitution{
.{ .original = "replace_me", .replacement = "new_line" },
.{ .original = "replace_also", .replacement = "also_new" },
};
try substituteLines(
&input_stream,
&output_stream,
&substitutions,
);
const result = output_stream.buffered();

5
sed-lite/test.txt Normal file
View file

@ -0,0 +1,5 @@
line1
old_text
line3
another_old
line5