summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig16
-rw-r--r--src/cmd.zig4
-rw-r--r--src/cmd/dir.zig28
-rw-r--r--src/cmd/external.zig13
-rw-r--r--src/cmd/lib/flags.zig30
-rw-r--r--src/cmd/lib/types.zig63
-rw-r--r--src/cmd/redirect.zig8
-rw-r--r--src/cmd/sort.zig12
-rw-r--r--src/cmd/type.zig12
-rw-r--r--src/main.zig83
-rw-r--r--src/parser.zig110
-rw-r--r--src/paths.zig62
12 files changed, 234 insertions, 207 deletions
diff --git a/build.zig b/build.zig
index f5eb0e4..a7dea7c 100644
--- a/build.zig
+++ b/build.zig
@@ -6,9 +6,11 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "dose",
- .root_source_file = b.path("src/main.zig"),
- .target = target,
- .optimize = optimize,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/main.zig"),
+ .target = target,
+ .optimize = optimize,
+ }),
});
// Add cross-platform terminal support
@@ -33,9 +35,11 @@ pub fn build(b: *std.Build) void {
run_step.dependOn(&run_cmd.step);
const unit_tests = b.addTest(.{
- .root_source_file = b.path("src/main.zig"),
- .target = target,
- .optimize = optimize,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("src/main.zig"),
+ .target = target,
+ .optimize = optimize,
+ }),
});
const run_unit_tests = b.addRunArtifact(unit_tests);
diff --git a/src/cmd.zig b/src/cmd.zig
index 755e659..2766a8c 100644
--- a/src/cmd.zig
+++ b/src/cmd.zig
@@ -174,14 +174,14 @@ pub const Command = union(enum) {
else => {},
}
}
- redirect.redirects.deinit();
+ redirect.redirects.deinit(allocator);
},
.External => |*external| {
allocator.free(external.program);
for (external.args.items) |arg| {
allocator.free(arg);
}
- external.args.deinit();
+ external.args.deinit(allocator);
},
.Builtin => |builtin| {
switch (builtin) {
diff --git a/src/cmd/dir.zig b/src/cmd/dir.zig
index 04f74dc..96c6319 100644
--- a/src/cmd/dir.zig
+++ b/src/cmd/dir.zig
@@ -120,8 +120,8 @@ pub const Dir = struct {
subdirs: bool = false, // /s flag
pub fn eval(dir: Dir, ctx: CommandContext) !CommandStatus {
- var output_buffer = ArrayList(u8).init(ctx.allocator);
- defer output_buffer.deinit();
+ var output_buffer = ArrayList(u8){};
+ defer output_buffer.deinit(ctx.allocator);
// Format path in DOS style with backslashes and uppercase drive letter
const formatted_path = try formatDosPath(ctx.allocator, dir.path);
@@ -134,9 +134,9 @@ pub const Dir = struct {
formatted_path[0]
else
'C';
- try output_buffer.writer().print(" Volume in drive {c} has no label\n", .{drive_letter});
- try output_buffer.writer().print(" Volume Serial Number is 1234-5678\n", .{});
- try output_buffer.writer().print("\n Directory of {s}\n\n", .{formatted_path});
+ try output_buffer.writer(ctx.allocator).print(" Volume in drive {c} has no label\n", .{drive_letter});
+ try output_buffer.writer(ctx.allocator).print(" Volume Serial Number is 1234-5678\n", .{});
+ try output_buffer.writer(ctx.allocator).print("\n Directory of {s}\n\n", .{formatted_path});
}
var dir_iterator = std.fs.cwd().openDir(dir.path, .{ .iterate = true }) catch {
@@ -172,23 +172,23 @@ pub const Dir = struct {
switch (entry.kind) {
.directory => {
if (dir.bare_format) {
- try output_buffer.writer().print("{s}\n", .{entry.name});
+ try output_buffer.writer(ctx.allocator).print("{s}\n", .{entry.name});
} else if (dir.wide_format) {
- try output_buffer.writer().print("{s:<12} ", .{entry.name});
+ try output_buffer.writer(ctx.allocator).print("{s:<12} ", .{entry.name});
} else {
- try output_buffer.writer().print("{s:<8} {s:<3} <DIR> {s}\n", .{ name, ext, date_time });
+ try output_buffer.writer(ctx.allocator).print("{s:<8} {s:<3} <DIR> {s}\n", .{ name, ext, date_time });
}
dir_count += 1;
},
.file => {
if (dir.bare_format) {
- try output_buffer.writer().print("{s}\n", .{entry.name});
+ try output_buffer.writer(ctx.allocator).print("{s}\n", .{entry.name});
} else if (dir.wide_format) {
- try output_buffer.writer().print("{s:<12} ", .{entry.name});
+ try output_buffer.writer(ctx.allocator).print("{s:<12} ", .{entry.name});
} else {
const formatted_size = try formatWithCommas(ctx.allocator, stat.size);
defer ctx.allocator.free(formatted_size);
- try output_buffer.writer().print("{s:<8} {s:<3} {s:>14} {s}\n", .{ name, ext, formatted_size, date_time });
+ try output_buffer.writer(ctx.allocator).print("{s:<8} {s:<3} {s:>14} {s}\n", .{ name, ext, formatted_size, date_time });
}
file_count += 1;
total_file_bytes += stat.size;
@@ -199,7 +199,7 @@ pub const Dir = struct {
// Add newline after wide format listing
if (dir.wide_format and !dir.bare_format) {
- try output_buffer.writer().print("\n", .{});
+ try output_buffer.writer(ctx.allocator).print("\n", .{});
}
// Only show footer for non-bare format
@@ -218,8 +218,8 @@ pub const Dir = struct {
const formatted_free_bytes = try formatWithCommas(ctx.allocator, bytes_free);
defer ctx.allocator.free(formatted_free_bytes);
- try output_buffer.writer().print(" {d} File(s) {s:>14} bytes\n", .{ file_count, formatted_total_bytes });
- try output_buffer.writer().print(" {d} Dir(s) {s:>14} bytes free\n", .{ dir_count, formatted_free_bytes });
+ try output_buffer.writer(ctx.allocator).print(" {d} File(s) {s:>14} bytes\n", .{ file_count, formatted_total_bytes });
+ try output_buffer.writer(ctx.allocator).print(" {d} Dir(s) {s:>14} bytes free\n", .{ dir_count, formatted_free_bytes });
}
var writer = ctx.output_writer;
diff --git a/src/cmd/external.zig b/src/cmd/external.zig
index 3aaa7af..befd746 100644
--- a/src/cmd/external.zig
+++ b/src/cmd/external.zig
@@ -26,12 +26,12 @@ pub const External = struct {
.capture => true,
};
// Try to execute external command
- var child_args = ArrayList([]const u8).init(allocator);
- defer child_args.deinit();
+ var child_args = ArrayList([]const u8){};
+ defer child_args.deinit(allocator);
- try child_args.append(external.program);
+ try child_args.append(allocator, external.program);
for (external.args.items) |arg| {
- try child_args.append(arg);
+ try child_args.append(allocator, arg);
}
var child = std.process.Child.init(child_args.items, allocator);
@@ -72,7 +72,9 @@ pub const External = struct {
// Handle input redirection
if (input_source) |source| {
if (child.stdin) |stdin| {
- const writer = stdin.writer();
+ var writer_buffer: [1024]u8 = undefined;
+ var file_writer = stdin.writer(&writer_buffer);
+ const writer = &file_writer.interface;
// Reset source position for reading
var temp_source = source.*;
@@ -82,6 +84,7 @@ pub const External = struct {
defer allocator.free(line);
try writer.print("{s}\n", .{line});
}
+ try writer.flush();
child.stdin.?.close();
child.stdin = null;
}
diff --git a/src/cmd/lib/flags.zig b/src/cmd/lib/flags.zig
index 637ea83..266ddfe 100644
--- a/src/cmd/lib/flags.zig
+++ b/src/cmd/lib/flags.zig
@@ -155,34 +155,34 @@ pub const CommandFlags = struct {
}
pub fn getHelp(self: *const CommandFlags, command_name: []const u8, allocator: Allocator) ![]const u8 {
- var help = ArrayList(u8).init(allocator);
- defer help.deinit();
+ var help = ArrayList(u8){};
+ defer help.deinit(allocator);
- try help.appendSlice(command_name);
- try help.appendSlice(" - Available flags:\n\n");
+ try help.appendSlice(allocator, command_name);
+ try help.appendSlice(allocator, " - Available flags:\n\n");
for (self.flags) |flag_def| {
- try help.appendSlice(" /");
- try help.appendSlice(flag_def.name);
+ try help.appendSlice(allocator, " /");
+ try help.appendSlice(allocator, flag_def.name);
if (flag_def.aliases.len > 0) {
- try help.appendSlice(" (");
+ try help.appendSlice(allocator, " (");
for (flag_def.aliases, 0..) |alias, i| {
- if (i > 0) try help.appendSlice(", ");
- try help.appendSlice(alias);
+ if (i > 0) try help.appendSlice(allocator, ", ");
+ try help.appendSlice(allocator, alias);
}
- try help.appendSlice(")");
+ try help.appendSlice(allocator, ")");
}
switch (flag_def.flag_type) {
- .String => try help.appendSlice(":value"),
- .Number => try help.appendSlice(":number"),
+ .String => try help.appendSlice(allocator, ":value"),
+ .Number => try help.appendSlice(allocator, ":number"),
.Boolean => {},
}
- try help.appendSlice(" - ");
- try help.appendSlice(flag_def.description);
- try help.appendSlice("\n");
+ try help.appendSlice(allocator, " - ");
+ try help.appendSlice(allocator, flag_def.description);
+ try help.appendSlice(allocator, "\n");
}
return help.toOwnedSlice();
diff --git a/src/cmd/lib/types.zig b/src/cmd/lib/types.zig
index 57d370d..2dfb0fa 100644
--- a/src/cmd/lib/types.zig
+++ b/src/cmd/lib/types.zig
@@ -12,19 +12,21 @@ pub const CommandStatus = union(enum) {
pub const OutputCapture = struct {
buffer: ArrayList(u8),
+ allocator: Allocator,
pub fn init(allocator: Allocator) OutputCapture {
return OutputCapture{
- .buffer = ArrayList(u8).init(allocator),
+ .buffer = ArrayList(u8){},
+ .allocator = allocator,
};
}
pub fn deinit(self: *OutputCapture) void {
- self.buffer.deinit();
+ self.buffer.deinit(self.allocator);
}
pub fn write(self: *OutputCapture, data: []const u8) !void {
- try self.buffer.appendSlice(data);
+ try self.buffer.appendSlice(self.allocator, data);
}
pub fn getContents(self: *const OutputCapture) []const u8 {
@@ -35,7 +37,11 @@ pub const OutputCapture = struct {
pub const StdoutOutputCapture = struct {
pub fn write(self: *StdoutOutputCapture, data: []const u8) !void {
_ = self;
- try std.io.getStdOut().writeAll(data);
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
+ try stdout.writeAll(data);
+ try stdout.flush();
}
};
@@ -73,41 +79,32 @@ pub const InputSource = struct {
};
pub const StdinInputReader = struct {
- pub fn readLine(self: *StdinInputReader, allocator: Allocator) !?[]const u8 {
+ pub fn readLine(self: *StdinInputReader, buf: []u8) !?[]const u8 {
_ = self;
- const stdin = std.io.getStdIn().reader();
+ const stdin = std.fs.File.stdin();
// Read line from stdin with proper DOS handling
- const line = stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096) catch |err| switch (err) {
+ var reader = stdin.readerStreaming(buf);
+ const input = std.io.Reader.takeDelimiterExclusive(&reader.interface, '\n') catch |err| switch (err) {
+ error.EndOfStream => return null,
error.StreamTooLong => {
- // Line too long, skip to next line
- while (true) {
- const ch = stdin.readByte() catch return null;
- if (ch == '\n') break;
- }
- return try allocator.dupe(u8, "");
+ // Line too long - return empty string
+ return "";
},
else => return null,
};
- if (line) |input| {
- // Check for Ctrl+Z (EOF marker) - ASCII 26
- if (input.len == 1 and input[0] == 26) {
- allocator.free(input);
- return null; // EOF
- }
-
- // Remove trailing \r if present (DOS line endings)
- if (input.len > 0 and input[input.len - 1] == '\r') {
- const trimmed = try allocator.dupe(u8, input[0 .. input.len - 1]);
- allocator.free(input);
- return trimmed;
- } else {
- return input;
- }
- } else {
+ // Check for Ctrl+Z (EOF marker) - ASCII 26
+ if (input.len == 1 and input[0] == 26) {
return null; // EOF
}
+
+ // Remove trailing \r if present (DOS line endings)
+ if (input.len > 0 and input[input.len - 1] == '\r') {
+ return input[0 .. input.len - 1];
+ } else {
+ return input;
+ }
}
};
@@ -118,7 +115,13 @@ pub const InputReader = union(enum) {
pub fn readLine(self: *InputReader, allocator: Allocator) !?[]const u8 {
switch (self.*) {
.source => |source| return source.readLine(allocator),
- .stdin => |stdin| return stdin.readLine(allocator),
+ .stdin => |stdin| {
+ var buf: [4096]u8 = undefined;
+ if (try stdin.readLine(&buf)) |line| {
+ return try allocator.dupe(u8, line);
+ }
+ return null;
+ },
}
}
};
diff --git a/src/cmd/redirect.zig b/src/cmd/redirect.zig
index ef37c3e..3921ef0 100644
--- a/src/cmd/redirect.zig
+++ b/src/cmd/redirect.zig
@@ -21,8 +21,12 @@ pub const RedirectCommand = struct {
pub fn eval(redirect: RedirectCommand, ctx: CommandContext) !CommandStatus {
const allocator = ctx.allocator;
- const stdout = std.io.getStdOut();
- const stderr = std.io.getStdErr();
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
+ var stderr_buffer: [1024]u8 = undefined;
+ var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer);
+ const stderr = &stderr_writer.interface;
// Extract output_capture from the output_writer for redirection logic
const output_capture = switch (ctx.output_writer) {
.capture => |capture| capture,
diff --git a/src/cmd/sort.zig b/src/cmd/sort.zig
index 79616e9..5f75734 100644
--- a/src/cmd/sort.zig
+++ b/src/cmd/sort.zig
@@ -10,12 +10,12 @@ pub const Sort = struct {
pub fn eval(sort: Sort, ctx: CommandContext) !CommandStatus {
_ = sort;
- var lines = ArrayList([]const u8).init(ctx.allocator);
+ var lines = ArrayList([]const u8){};
defer {
for (lines.items) |line| {
ctx.allocator.free(line);
}
- lines.deinit();
+ lines.deinit(ctx.allocator);
}
// Read input lines from unified input reader
@@ -33,7 +33,7 @@ pub const Sort = struct {
.source => {
// Read from input redirection
while (try reader.readLine(ctx.allocator)) |line| {
- try lines.append(line);
+ try lines.append(ctx.allocator, line);
}
},
}
@@ -46,11 +46,11 @@ pub const Sort = struct {
}.lessThan);
// Output sorted lines
- var output_buffer = ArrayList(u8).init(ctx.allocator);
- defer output_buffer.deinit();
+ var output_buffer = ArrayList(u8){};
+ defer output_buffer.deinit(ctx.allocator);
for (lines.items) |line| {
- try output_buffer.writer().print("{s}\n", .{line});
+ try output_buffer.writer(ctx.allocator).print("{s}\n", .{line});
}
var writer = ctx.output_writer;
diff --git a/src/cmd/type.zig b/src/cmd/type.zig
index 147c2a9..5909f4a 100644
--- a/src/cmd/type.zig
+++ b/src/cmd/type.zig
@@ -58,23 +58,23 @@ pub const Type = struct {
if (bytes_read == 0) break;
// Process buffer contents for output
- var processed_output = ArrayList(u8).init(ctx.allocator);
- defer processed_output.deinit();
+ var processed_output = ArrayList(u8){};
+ defer processed_output.deinit(ctx.allocator);
for (buffer[0..bytes_read]) |byte| {
// Convert to printable characters, similar to DOS TYPE behavior
if (byte >= 32 and byte <= 126) {
- try processed_output.append(byte);
+ try processed_output.append(ctx.allocator, byte);
} else if (byte == '\n') {
- try processed_output.append('\n');
+ try processed_output.append(ctx.allocator, '\n');
} else if (byte == '\r') {
// Skip carriage return in DOS-style line endings
continue;
} else if (byte == '\t') {
- try processed_output.append('\t');
+ try processed_output.append(ctx.allocator, '\t');
} else {
// Replace non-printable characters with '?'
- try processed_output.append('?');
+ try processed_output.append(ctx.allocator, '?');
}
}
diff --git a/src/main.zig b/src/main.zig
index 7c2ffd7..f8bd7b5 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -18,14 +18,14 @@ const STDERR_BUFFER_SIZE: usize = 1024;
fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 {
// Normalize separators and case first
- var normalized = ArrayList(u8).init(allocator);
- defer normalized.deinit();
+ var normalized = ArrayList(u8){};
+ defer normalized.deinit(allocator);
for (path) |ch| {
if (ch == '/') {
- try normalized.append('\\');
+ try normalized.append(allocator, '\\');
} else {
- try normalized.append(std.ascii.toUpper(ch));
+ try normalized.append(allocator, std.ascii.toUpper(ch));
}
}
@@ -48,12 +48,12 @@ fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 {
}
// Build result with components converted to 8.3
- var result = ArrayList(u8).init(allocator);
- defer result.deinit();
+ var result = ArrayList(u8){};
+ defer result.deinit(allocator);
// If absolute, start with a backslash (after potential drive prefix)
if (starts_with_backslash) {
- try result.append('\\');
+ try result.append(allocator, '\\');
}
var it = std.mem.splitScalar(u8, normalized.items[idx..], '\\');
@@ -62,38 +62,38 @@ fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 {
if (component.len == 0) continue;
if (!first_component and result.items.len > 0 and result.items[result.items.len - 1] != '\\') {
- try result.append('\\');
+ try result.append(allocator, '\\');
}
first_component = false;
const short_name = try convertTo83(allocator, component);
defer allocator.free(short_name.name);
defer allocator.free(short_name.ext);
- try result.appendSlice(short_name.name);
+ try result.appendSlice(allocator, short_name.name);
if (short_name.ext.len > 0) {
- try result.append('.');
- try result.appendSlice(short_name.ext);
+ try result.append(allocator, '.');
+ try result.appendSlice(allocator, short_name.ext);
}
}
// Prepend drive if present or add default C:
- var final_buf = ArrayList(u8).init(allocator);
- defer final_buf.deinit();
+ var final_buf = ArrayList(u8){};
+ defer final_buf.deinit(allocator);
if (has_drive) {
- try final_buf.append(drive_letter);
- try final_buf.append(':');
+ try final_buf.append(allocator, drive_letter);
+ try final_buf.append(allocator, ':');
if (result.items.len > 0 and result.items[0] != '\\') {
- try final_buf.append('\\');
+ try final_buf.append(allocator, '\\');
}
- try final_buf.appendSlice(result.items);
+ try final_buf.appendSlice(allocator, result.items);
} else {
// No drive: default to C:
- try final_buf.appendSlice("C:");
+ try final_buf.appendSlice(allocator, "C:");
if (result.items.len > 0 and result.items[0] != '\\') {
- try final_buf.append('\\');
+ try final_buf.append(allocator, '\\');
}
- try final_buf.appendSlice(result.items);
+ try final_buf.appendSlice(allocator, result.items);
}
return allocator.dupe(u8, final_buf.items);
@@ -113,19 +113,25 @@ fn parseAndExecute(input: []const u8, allocator: Allocator) !CommandStatus {
return try eval.executeCommand(command, allocator);
}
-fn readLine(allocator: Allocator, prompt_text: []const u8) !?[]const u8 {
- const stdin = std.io.getStdIn().reader();
- const stdout = std.io.getStdOut();
+fn readLine(buf: []u8, prompt_text: []const u8) !?[]const u8 {
+ const stdin = std.fs.File.stdin();
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
try stdout.writeAll(prompt_text);
+ try stdout.flush();
- if (try stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096)) |input| {
- // Remove trailing \r on Windows
- if (input.len > 0 and input[input.len - 1] == '\r') {
- return input[0 .. input.len - 1];
+ var reader = stdin.readerStreaming(buf);
+ const input = std.io.Reader.takeDelimiterExclusive(&reader.interface, '\n') catch |err| {
+ switch (err) {
+ error.EndOfStream => return null,
+ else => return err,
}
- return input;
+ };
+ if (input.len > 0 and input[input.len - 1] == '\r') {
+ return input[0 .. input.len - 1];
}
- return null;
+ return input;
}
pub fn main() !void {
@@ -153,14 +159,16 @@ pub fn main() !void {
const final_prompt = try std.mem.replaceOwned(u8, allocator, interpolated_prompt, "$g", ">");
defer allocator.free(final_prompt);
- if (try readLine(allocator, final_prompt)) |line| {
- defer allocator.free(line);
-
+ var buf: [4096]u8 = undefined;
+ if (try readLine(&buf, final_prompt)) |line| {
const command_result = parseAndExecute(line, allocator) catch |err| {
switch (err) {
error.ExpectedWord, error.UnexpectedToken => {
- const stdout = std.io.getStdOut();
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
try stdout.writeAll("Bad command or file name\n");
+ try stdout.flush();
continue;
},
else => return err,
@@ -178,8 +186,12 @@ pub fn main() !void {
}
fn printWelcomeMessage() !void {
- const stdout = std.io.getStdOut();
- if (!stdout.isTty()) return;
+ const stdout_file = std.fs.File.stdout();
+ if (!stdout_file.isTty()) return;
+
+ var stdout_buffer: [1024]u8 = undefined;
+ var stdout_writer = stdout_file.writer(&stdout_buffer);
+ const stdout = &stdout_writer.interface;
try stdout.writeAll(
\\Starting MB-DOS...
@@ -193,4 +205,5 @@ fn printWelcomeMessage() !void {
\\
\\
);
+ try stdout.flush();
}
diff --git a/src/parser.zig b/src/parser.zig
index 7bbfdab..af465f8 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -46,8 +46,8 @@ const Lexer = struct {
}
fn readWord(self: *Lexer, allocator: Allocator) ![]const u8 {
- var word = ArrayList(u8).init(allocator);
- defer word.deinit();
+ var word = ArrayList(u8){};
+ defer word.deinit(allocator);
var in_quotes = false;
var quote_char: u8 = '"';
@@ -63,18 +63,18 @@ const Lexer = struct {
in_quotes = false;
self.advance();
} else {
- try word.append(ch);
+ try word.append(allocator, ch);
self.advance();
}
},
'|', '>', '<', '\n' => {
if (!in_quotes) break;
- try word.append(ch);
+ try word.append(allocator, ch);
self.advance();
},
else => {
if (!in_quotes and std.ascii.isWhitespace(ch)) break;
- try word.append(ch);
+ try word.append(allocator, ch);
self.advance();
},
}
@@ -127,7 +127,7 @@ const Lexer = struct {
}
pub fn tokenize(self: *Lexer, allocator: Allocator) !ArrayList(Token) {
- var tokens = ArrayList(Token).init(allocator);
+ var tokens = ArrayList(Token){};
while (true) {
const token = try self.nextToken(allocator);
@@ -135,7 +135,7 @@ const Lexer = struct {
.Eof => true,
else => false,
};
- try tokens.append(token);
+ try tokens.append(allocator, token);
if (is_eof) break;
}
@@ -206,7 +206,7 @@ const Parser = struct {
fn parseRedirectedCommand(self: *Parser) !Command {
const command = try self.parseSimpleCommand();
- var redirects = ArrayList(Redirect).init(self.allocator);
+ var redirects = ArrayList(Redirect){};
while (true) {
const redirect_type = switch (self.currentToken()) {
@@ -221,14 +221,14 @@ const Parser = struct {
const target_str = try self.expectWord();
const target = try parseFilespec(self.allocator, target_str);
- try redirects.append(Redirect{
+ try redirects.append(self.allocator, Redirect{
.redirect_type = redirect_type,
.target = target,
});
}
if (redirects.items.len == 0) {
- redirects.deinit();
+ redirects.deinit(self.allocator);
return command;
} else {
const command_ptr = try self.allocator.create(Command);
@@ -242,23 +242,23 @@ const Parser = struct {
.Eof, .Newline => return Command.Empty,
.Word => |command_name| {
self.advance();
- var args = ArrayList([]const u8).init(self.allocator);
+ var args = ArrayList([]const u8){};
// Collect arguments
while (true) {
switch (self.currentToken()) {
.Word => |arg| {
- try args.append(arg);
+ try args.append(self.allocator, arg);
self.advance();
},
else => break,
}
}
- const result = try self.parseBuiltinCommand(command_name, args);
+ const result = try self.parseBuiltinCommand(command_name, &args);
// For builtin commands, free the args ArrayList (the strings inside belong to tokens and will be freed later)
if (result == .Builtin) {
- args.deinit();
+ args.deinit(self.allocator);
}
return result;
},
@@ -266,35 +266,35 @@ const Parser = struct {
}
}
- fn parseBuiltinCommand(self: *Parser, command_name: []const u8, args: ArrayList([]const u8)) !Command {
+ fn parseBuiltinCommand(self: *Parser, command_name: []const u8, args: *ArrayList([]const u8)) !Command {
const cmd_upper = try std.ascii.allocUpperString(self.allocator, command_name);
defer self.allocator.free(cmd_upper);
// Check for /? help flag first
- if (hasHelpFlag(args.items)) {
+ if (hasHelpFlag(args.*.items)) {
const cmd_copy = try self.allocator.dupe(u8, cmd_upper);
return Command{ .Builtin = BuiltinCommand{ .Help = .{ .command = cmd_copy } } };
}
if (std.mem.eql(u8, cmd_upper, "HELP")) {
- const help_command = if (args.items.len > 0)
- try self.allocator.dupe(u8, args.items[0])
+ const help_command = if (args.*.items.len > 0)
+ try self.allocator.dupe(u8, args.*.items[0])
else
null;
return Command{ .Builtin = BuiltinCommand{ .Help = .{ .command = help_command } } };
} else if (std.mem.eql(u8, cmd_upper, "ECHO")) {
- if (args.items.len == 0) {
+ if (args.*.items.len == 0) {
return Command{ .Builtin = BuiltinCommand.EchoPlain };
} else {
- const first_arg_upper = try std.ascii.allocUpperString(self.allocator, args.items[0]);
+ const first_arg_upper = try std.ascii.allocUpperString(self.allocator, args.*.items[0]);
defer self.allocator.free(first_arg_upper);
- if (std.mem.eql(u8, first_arg_upper, "ON") and args.items.len == 1) {
+ if (std.mem.eql(u8, first_arg_upper, "ON") and args.*.items.len == 1) {
return Command{ .Builtin = BuiltinCommand.EchoOn };
- } else if (std.mem.eql(u8, first_arg_upper, "OFF") and args.items.len == 1) {
+ } else if (std.mem.eql(u8, first_arg_upper, "OFF") and args.*.items.len == 1) {
return Command{ .Builtin = BuiltinCommand.EchoOff };
} else {
- const message = try std.mem.join(self.allocator, " ", args.items);
+ const message = try std.mem.join(self.allocator, " ", args.*.items);
return Command{ .Builtin = BuiltinCommand{ .EchoText = .{ .message = message } } };
}
}
@@ -307,9 +307,9 @@ const Parser = struct {
} else if (std.mem.eql(u8, cmd_upper, "VERIFY")) {
return Command{ .Builtin = BuiltinCommand.Verify };
} else if (std.mem.eql(u8, cmd_upper, "DIR")) {
- const separated = try self.separateFlagsFromArgs(args.items);
- defer separated.flags.deinit();
- defer separated.positional.deinit();
+ var separated = try self.separateFlagsFromArgs(args.*.items);
+ defer separated.flags.deinit(self.allocator);
+ defer separated.positional.deinit(self.allocator);
const path = if (separated.positional.items.len == 0)
try self.allocator.dupe(u8, ".")
@@ -338,74 +338,74 @@ const Parser = struct {
} else if (std.mem.eql(u8, cmd_upper, "TIME")) {
return Command{ .Builtin = BuiltinCommand.Time };
} else if (std.mem.eql(u8, cmd_upper, "TYPE")) {
- if (args.items.len == 0) {
+ if (args.*.items.len == 0) {
return error.ExpectedWord; // Will be caught and show "Bad command or file name"
}
- const file_spec = try parseFilespec(self.allocator, args.items[0]);
+ const file_spec = try parseFilespec(self.allocator, args.*.items[0]);
return Command{ .Builtin = BuiltinCommand{ .Type = .{ .file = file_spec } } };
} else if (std.mem.eql(u8, cmd_upper, "SORT")) {
return Command{ .Builtin = BuiltinCommand.Sort };
} else if (std.mem.eql(u8, cmd_upper, "CD") or std.mem.eql(u8, cmd_upper, "CHDIR")) {
- const path = if (args.items.len == 0)
+ const path = if (args.*.items.len == 0)
try self.allocator.dupe(u8, "")
else
- try self.allocator.dupe(u8, args.items[0]);
+ try self.allocator.dupe(u8, args.*.items[0]);
return Command{ .Builtin = BuiltinCommand{ .Chdir = .{ .path = path } } };
} else if (std.mem.eql(u8, cmd_upper, "COPY")) {
- if (args.items.len < 2) {
+ if (args.*.items.len < 2) {
return error.ExpectedWord; // Will show "Bad command or file name"
}
- const from_spec = try parseFilespec(self.allocator, args.items[0]);
- const to_spec = try parseFilespec(self.allocator, args.items[1]);
+ const from_spec = try parseFilespec(self.allocator, args.*.items[0]);
+ const to_spec = try parseFilespec(self.allocator, args.*.items[1]);
return Command{ .Builtin = BuiltinCommand{ .Copy = .{ .from = from_spec, .to = to_spec } } };
} else if (std.mem.eql(u8, cmd_upper, "DEL") or std.mem.eql(u8, cmd_upper, "ERASE")) {
- if (args.items.len == 0) {
+ if (args.*.items.len == 0) {
return error.ExpectedWord; // Will show "Bad command or file name"
}
- const path = try self.allocator.dupe(u8, args.items[0]);
+ const path = try self.allocator.dupe(u8, args.*.items[0]);
return Command{ .Builtin = BuiltinCommand{ .Remove = .{ .path = path } } };
} else if (std.mem.eql(u8, cmd_upper, "MD") or std.mem.eql(u8, cmd_upper, "MKDIR")) {
- if (args.items.len == 0) {
+ if (args.*.items.len == 0) {
return error.ExpectedWord; // Will show "Bad command or file name"
}
- const path = try self.allocator.dupe(u8, args.items[0]);
+ const path = try self.allocator.dupe(u8, args.*.items[0]);
return Command{ .Builtin = BuiltinCommand{ .Mkdir = .{ .path = path } } };
} else if (std.mem.eql(u8, cmd_upper, "RD") or std.mem.eql(u8, cmd_upper, "RMDIR")) {
- if (args.items.len == 0) {
+ if (args.*.items.len == 0) {
return error.ExpectedWord; // Will show "Bad command or file name"
}
- const path = try self.allocator.dupe(u8, args.items[0]);
+ const path = try self.allocator.dupe(u8, args.*.items[0]);
return Command{ .Builtin = BuiltinCommand{ .Rmdir = .{ .path = path } } };
} else if (std.mem.eql(u8, cmd_upper, "REN") or std.mem.eql(u8, cmd_upper, "RENAME")) {
- if (args.items.len < 2) {
+ if (args.*.items.len < 2) {
return error.ExpectedWord; // Will show "Bad command or file name"
}
- const from_spec = try parseFilespec(self.allocator, args.items[0]);
- const to_spec = try parseFilespec(self.allocator, args.items[1]);
+ const from_spec = try parseFilespec(self.allocator, args.*.items[0]);
+ const to_spec = try parseFilespec(self.allocator, args.*.items[1]);
return Command{ .Builtin = BuiltinCommand{ .Rename = .{ .from = from_spec, .to = to_spec } } };
} else if (std.mem.eql(u8, cmd_upper, "MOVE")) {
// MOVE command is more complex - for now just show not implemented
return Command{ .Builtin = BuiltinCommand.Move };
} else if (std.mem.eql(u8, cmd_upper, "PATH")) {
- if (args.items.len == 0) {
+ if (args.*.items.len == 0) {
return Command{ .Builtin = BuiltinCommand.PathGet };
} else {
// PATH=value or PATH value
- const value = if (std.mem.startsWith(u8, args.items[0], "="))
- try self.allocator.dupe(u8, args.items[0][1..]) // Skip the '='
+ const value = if (std.mem.startsWith(u8, args.*.items[0], "="))
+ try self.allocator.dupe(u8, args.*.items[0][1..]) // Skip the '='
else
- try self.allocator.dupe(u8, args.items[0]);
+ try self.allocator.dupe(u8, args.*.items[0]);
return Command{ .Builtin = BuiltinCommand{ .PathSet = .{ .value = value } } };
}
} else {
// External command - need to duplicate all strings
const program_copy = try self.allocator.dupe(u8, command_name);
- var args_copy = ArrayList([]const u8).init(self.allocator);
- for (args.items) |arg| {
+ var args_copy = ArrayList([]const u8){};
+ for (args.*.items) |arg| {
const arg_copy = try self.allocator.dupe(u8, arg);
- try args_copy.append(arg_copy);
+ try args_copy.append(self.allocator, arg_copy);
}
- args.deinit(); // Free the original args list (but not the strings, as they belong to tokens)
+ args.*.deinit(self.allocator); // Free the original args list (but not the strings, as they belong to tokens)
return Command{ .External = .{ .program = program_copy, .args = args_copy } };
}
}
@@ -420,14 +420,14 @@ const Parser = struct {
}
fn separateFlagsFromArgs(self: *Parser, args: []const []const u8) !struct { flags: ArrayList([]const u8), positional: ArrayList([]const u8) } {
- var flags = ArrayList([]const u8).init(self.allocator);
- var positional = ArrayList([]const u8).init(self.allocator);
+ var flags = ArrayList([]const u8){};
+ var positional = ArrayList([]const u8){};
for (args) |arg| {
if (arg.len > 0 and arg[0] == '/') {
- try flags.append(arg);
+ try flags.append(self.allocator, arg);
} else {
- try positional.append(arg);
+ try positional.append(self.allocator, arg);
}
}
@@ -463,7 +463,7 @@ pub fn parse(input: []const u8, allocator: Allocator) !Command {
else => {},
}
}
- tokens.deinit();
+ tokens.deinit(allocator);
}
var parser = Parser.init(tokens, allocator);
diff --git a/src/paths.zig b/src/paths.zig
index dd3ace2..abda053 100644
--- a/src/paths.zig
+++ b/src/paths.zig
@@ -3,18 +3,18 @@ const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList;
pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 {
- var result = ArrayList(u8).init(allocator);
- defer result.deinit();
+ var result = ArrayList(u8){};
+ defer result.deinit(allocator);
// Convert path to DOS format with uppercase drive letter and backslashes
- var converted_path = ArrayList(u8).init(allocator);
- defer converted_path.deinit();
+ var converted_path = ArrayList(u8){};
+ defer converted_path.deinit(allocator);
for (path) |ch| {
if (ch == '/') {
- try converted_path.append('\\');
+ try converted_path.append(allocator, '\\');
} else {
- try converted_path.append(std.ascii.toUpper(ch));
+ try converted_path.append(allocator, std.ascii.toUpper(ch));
}
}
@@ -26,7 +26,7 @@ pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 {
if (component.len == 0) continue;
if (!first) {
- try result.append('\\');
+ try result.append(allocator, '\\');
}
first = false;
@@ -34,22 +34,22 @@ pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 {
const short_name = try convertTo83(allocator, component);
defer allocator.free(short_name.name);
defer allocator.free(short_name.ext);
- try result.appendSlice(short_name.name);
+ try result.appendSlice(allocator, short_name.name);
if (short_name.ext.len > 0) {
- try result.append('.');
- try result.appendSlice(short_name.ext);
+ try result.append(allocator, '.');
+ try result.appendSlice(allocator, short_name.ext);
}
}
// Ensure it starts with a drive letter if it's an absolute path
if (result.items.len == 0 or (result.items.len >= 1 and result.items[0] == '\\')) {
- var prefixed = ArrayList(u8).init(allocator);
- defer prefixed.deinit();
- try prefixed.appendSlice("C:");
+ var prefixed = ArrayList(u8){};
+ defer prefixed.deinit(allocator);
+ try prefixed.appendSlice(allocator, "C:");
if (result.items.len > 0 and result.items[0] != '\\') {
- try prefixed.append('\\');
+ try prefixed.append(allocator, '\\');
}
- try prefixed.appendSlice(result.items);
+ try prefixed.appendSlice(allocator, result.items);
return allocator.dupe(u8, prefixed.items);
}
@@ -79,48 +79,48 @@ pub fn convertTo83(allocator: Allocator, filename: []const u8) !struct { name: [
}
// Clean name part (remove spaces and invalid chars, convert to uppercase)
- var clean_name = ArrayList(u8).init(allocator);
- defer clean_name.deinit();
+ var clean_name = ArrayList(u8){};
+ defer clean_name.deinit(allocator);
for (name_part) |ch| {
if (std.ascii.isAlphanumeric(ch)) {
- try clean_name.append(std.ascii.toUpper(ch));
+ try clean_name.append(allocator, std.ascii.toUpper(ch));
} else if (ch == '-' or ch == '_') {
- try clean_name.append(ch);
+ try clean_name.append(allocator, ch);
}
// Skip spaces and other invalid characters
}
// Clean extension part (max 3 chars, uppercase)
- var clean_ext = ArrayList(u8).init(allocator);
- defer clean_ext.deinit();
+ var clean_ext = ArrayList(u8){};
+ defer clean_ext.deinit(allocator);
for (ext_part) |ch| {
if (clean_ext.items.len >= 3) break;
if (std.ascii.isAlphanumeric(ch)) {
- try clean_ext.append(std.ascii.toUpper(ch));
+ try clean_ext.append(allocator, std.ascii.toUpper(ch));
}
}
- var name_result = ArrayList(u8).init(allocator);
- defer name_result.deinit();
- var ext_result = ArrayList(u8).init(allocator);
- defer ext_result.deinit();
+ var name_result = ArrayList(u8){};
+ defer name_result.deinit(allocator);
+ var ext_result = ArrayList(u8){};
+ defer ext_result.deinit(allocator);
// Build 8.3 filename
if (clean_name.items.len <= 8 and clean_ext.items.len <= 3) {
// Name fits in 8.3, use as-is
- try name_result.appendSlice(clean_name.items);
- try ext_result.appendSlice(clean_ext.items);
+ try name_result.appendSlice(allocator, clean_name.items);
+ try ext_result.appendSlice(allocator, clean_ext.items);
} else {
// Need to abbreviate with ~1
const max_name_len = if (clean_name.items.len > 6) 6 else clean_name.items.len;
- try name_result.appendSlice(clean_name.items[0..max_name_len]);
- try name_result.appendSlice("~1");
+ try name_result.appendSlice(allocator, clean_name.items[0..max_name_len]);
+ try name_result.appendSlice(allocator, "~1");
if (clean_ext.items.len > 0) {
const max_ext_len = if (clean_ext.items.len > 3) 3 else clean_ext.items.len;
- try ext_result.appendSlice(clean_ext.items[0..max_ext_len]);
+ try ext_result.appendSlice(allocator, clean_ext.items[0..max_ext_len]);
}
}