some cleanup
This commit is contained in:
parent
7858c0f51c
commit
899d5fdfc5
2 changed files with 92 additions and 28 deletions
|
@ -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
5
sed-lite/test.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
line1
|
||||
old_text
|
||||
line3
|
||||
another_old
|
||||
line5
|
Loading…
Add table
Reference in a new issue