Compare commits
10 commits
5c97005205
...
cc71aaf6a2
| Author | SHA1 | Date | |
|---|---|---|---|
| cc71aaf6a2 | |||
| 98d88e8cd4 | |||
| 28990d9cb1 | |||
| 3efae0c623 | |||
| 15f1dab417 | |||
| d046fe6180 | |||
| f25404f2f2 | |||
| 7ce6b0651c | |||
| 9109646d8f | |||
| 16d6067f21 |
7 changed files with 246 additions and 34 deletions
30
Makefile
Normal file
30
Makefile
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
all: global-compilation
|
||||||
|
|
||||||
|
OPT_CACHE = --global-cache-dir /tmp/.global-cache-dir
|
||||||
|
OPT_MODE = ReleaseSmall
|
||||||
|
#OPT_MODE = ReleaseFast
|
||||||
|
#OPT_MODE = ReleaseSafe
|
||||||
|
#OPT_MODE = Debug
|
||||||
|
OPT_STRIP = --strip
|
||||||
|
opts = -O $(OPT_MODE) $(OPT_CACHE) $(OPT_STRIP)
|
||||||
|
|
||||||
|
individual_apps != ls src/*.zig |\
|
||||||
|
grep -v lib.zig |\
|
||||||
|
grep -v zig-cache |\
|
||||||
|
grep -v test.zig |\
|
||||||
|
sed "s_src/__" |\
|
||||||
|
sed "s/.zig$$//"
|
||||||
|
|
||||||
|
$(individual_apps):
|
||||||
|
@echo $@
|
||||||
|
@zig build-exe $(opts) src/$@.zig
|
||||||
|
|
||||||
|
individual-compilation:
|
||||||
|
@echo "individual apps: $(individual_apps)"
|
||||||
|
@for i in $(individual_apps); do echo "$${i}"; zig build-exe $(opts) src/$${i}.zig; done
|
||||||
|
|
||||||
|
global-compilation: src/main.zig
|
||||||
|
zig build-exe $(opts) src/main.zig
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: $(global-compilation) $(individual-compilation)
|
||||||
25
src/cat.zig
25
src/cat.zig
|
|
@ -1,5 +1,5 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const lib = @import("./lib.zig");
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
pub fn main() anyerror!void {
|
pub fn main() anyerror!void {
|
||||||
const args = try std.process.argsAlloc(std.heap.page_allocator);
|
const args = try std.process.argsAlloc(std.heap.page_allocator);
|
||||||
|
|
@ -8,34 +8,27 @@ pub fn main() anyerror!void {
|
||||||
try print_input();
|
try print_input();
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = args[1..];
|
for (args[1..]) |f| {
|
||||||
for (files) |f| {
|
if (std.mem.eql(u8, f, "-")) { try print_input(); }
|
||||||
if (std.mem.eql(u8, f, "-")) { try print_input(); }
|
|
||||||
else { try print_file (f); }
|
else { try print_file (f); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_input() !void {
|
fn print_input() !void {
|
||||||
const stdin = std.io.getStdIn().reader();
|
try print_all (std.io.getStdIn());
|
||||||
var buffer: [4096]u8 = undefined;
|
|
||||||
while (true) {
|
|
||||||
const nbytes = try stdin.read(&buffer);
|
|
||||||
lib.print("{s}", .{buffer[0..nbytes]});
|
|
||||||
if (nbytes == 0) break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_file(dest: []const u8) !void {
|
fn print_file(dest: []const u8) !void {
|
||||||
// open file and defer closing
|
|
||||||
var file = try std.fs.cwd().openFile(dest, .{ .mode = .read_only });
|
var file = try std.fs.cwd().openFile(dest, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
try print_all (file);
|
||||||
|
}
|
||||||
|
|
||||||
// read file content and print everything
|
fn print_all(reader: std.fs.File) !void {
|
||||||
var buffer: [4096]u8 = undefined;
|
var buffer: [4096]u8 = undefined;
|
||||||
var nbytes : u64 = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
nbytes = try file.read(&buffer);
|
const nbytes = try reader.read(&buffer);
|
||||||
lib.print("{s}", .{buffer[0..nbytes]});
|
try stdout.print("{s}", .{buffer[0..nbytes]});
|
||||||
if (nbytes == 0) break;
|
if (nbytes == 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
pub fn nextArg(args: [][]const u8, idx: *usize) ?[]const u8 {
|
|
||||||
if (idx.* >= args.len) return null;
|
|
||||||
defer idx.* += 1;
|
|
||||||
return args[idx.*];
|
|
||||||
}
|
|
||||||
35
src/lib.zig
35
src/lib.zig
|
|
@ -2,15 +2,46 @@ const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
const process = std.process;
|
const process = std.process;
|
||||||
|
const fmt = std.fmt;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
|
const io = std.io;
|
||||||
|
|
||||||
pub const warn = std.debug.print;
|
pub const warn = std.debug.print;
|
||||||
pub fn print(comptime format: []const u8, args: anytype) void {
|
pub fn print(comptime format: []const u8, args: anytype) void {
|
||||||
nosuspend stdout.print(format, args) catch return;
|
nosuspend stdout.print(format, args) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cli_arguments = @import("./cli_arguments.zig");
|
// const depth = 3;
|
||||||
|
|
||||||
|
pub const FixedBufferWriter = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
depth: u32 = 3,
|
||||||
|
fbs: io.FixedBufferStream([]u8),
|
||||||
|
fmtopts: fmt.FormatOptions = fmt.FormatOptions{},
|
||||||
|
|
||||||
|
pub fn put(self: *Self, str: []const u8) !void {
|
||||||
|
var writer = self.fbs.writer();
|
||||||
|
try fmt.formatType(str, "s", self.fmtopts, writer, self.depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn putf(self: *Self, comptime format: []const u8, args: anytype) !void {
|
||||||
|
var writer = self.fbs.writer();
|
||||||
|
try fmt.format(writer, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(buffer: []u8) Self {
|
||||||
|
return Self{
|
||||||
|
.fbs = io.fixedBufferStream(buffer),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getWritten(self: *Self) []u8 {
|
||||||
|
defer self.fbs.reset();
|
||||||
|
return self.fbs.getWritten();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
pub const CLI = struct {
|
pub const CLI = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
|
||||||
128
src/ls.zig
128
src/ls.zig
|
|
@ -1,23 +1,124 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const os = std.os;
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const path = std.fs.path;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const lib = @import("./lib.zig");
|
const lib = @import("./lib.zig");
|
||||||
|
|
||||||
|
const fmt = std.fmt;
|
||||||
|
|
||||||
|
const Kind = std.fs.File.Kind;
|
||||||
|
const PermissionsUnix = std.fs.File.PermissionsUnix;
|
||||||
|
|
||||||
// WON'T: human output => use human command instead
|
// WON'T: human output => use human command instead
|
||||||
// TODO: error management.
|
// TODO: error management.
|
||||||
// TODO: verbose output (-l).
|
|
||||||
|
|
||||||
pub const cwd = fs.cwd();
|
pub const cwd = fs.cwd();
|
||||||
|
|
||||||
// Either print directory's content or file.
|
const Options = struct {
|
||||||
fn print_element(path: []const u8) !void {
|
verbose: bool = false,
|
||||||
var dir: fs.Dir = cwd.openDir(path, .{.iterate = true}) catch |err| switch (err) {
|
};
|
||||||
error.NotDir => return lib.print("{s}\n", .{path}),
|
|
||||||
|
var options: Options = Options {};
|
||||||
|
|
||||||
|
fn print_stats(fpath: []const u8, stats: os.system.Stat) !void {
|
||||||
|
var buffer = [_]u8 {0} ** (std.fs.MAX_PATH_BYTES + 100);
|
||||||
|
var writer = lib.FixedBufferWriter.init(&buffer);
|
||||||
|
|
||||||
|
// print kind (directory, file, pipe, etc.)
|
||||||
|
const kind = fs.File.Stat.systemStatKindToFsKind(stats);
|
||||||
|
switch (kind) {
|
||||||
|
.File => try writer.put("-"),
|
||||||
|
.Directory => try writer.put("d"),
|
||||||
|
.CharacterDevice => try writer.put("c"),
|
||||||
|
.BlockDevice => try writer.put("b"),
|
||||||
|
.NamedPipe => try writer.put("p"),
|
||||||
|
.SymLink => try writer.put("s"),
|
||||||
|
.UnixDomainSocket => try writer.put("s"),
|
||||||
|
else => {
|
||||||
|
if (builtin.os.tag == .solaris) switch (kind) {
|
||||||
|
.Door => try writer.put("D"), // TODO: what to print here?
|
||||||
|
.EventPort => try writer.put("e"), // TODO: what to print here?
|
||||||
|
else => try writer.put("?"),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// print rights
|
||||||
|
const perms = PermissionsUnix.unixNew(stats.mode);
|
||||||
|
const classes = [_]PermissionsUnix.Class {
|
||||||
|
PermissionsUnix.Class.user,
|
||||||
|
PermissionsUnix.Class.group,
|
||||||
|
PermissionsUnix.Class.other
|
||||||
|
};
|
||||||
|
const rights = [_]PermissionsUnix.Permission {
|
||||||
|
PermissionsUnix.Permission.read,
|
||||||
|
PermissionsUnix.Permission.write,
|
||||||
|
PermissionsUnix.Permission.execute
|
||||||
|
};
|
||||||
|
for (classes) |c| {
|
||||||
|
for (rights) |r| {
|
||||||
|
if (perms.unixHas(c,r)) {
|
||||||
|
switch(r) {
|
||||||
|
.read => try writer.put("r"),
|
||||||
|
.write => try writer.put("w"),
|
||||||
|
.execute => try writer.put("x"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try writer.put("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: print user & group, not just uid and gid
|
||||||
|
try writer.putf("\t{}\t{}\t", .{stats.uid, stats.gid});
|
||||||
|
try writer.putf("{}\t", .{stats.size});
|
||||||
|
try writer.putf("{}\t", .{stats.mtim.tv_sec});
|
||||||
|
try writer.putf("{s}\n", .{fpath});
|
||||||
|
|
||||||
|
return lib.print("{s}", .{writer.getWritten()});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_file (fpath: []const u8) !void {
|
||||||
|
if (options.verbose == false) {
|
||||||
|
return lib.print("{s}\n", .{fpath});
|
||||||
|
}
|
||||||
|
|
||||||
|
const dname = path.dirname(fpath);
|
||||||
|
var dpath = dname orelse ".";
|
||||||
|
var dir: fs.Dir = cwd.openDir(dpath, .{}) catch |err| switch (err) {
|
||||||
|
error.AccessDenied => return lib.print("{s}: access denied\n", .{dname}),
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
var dir_it = dir.iterate();
|
|
||||||
|
|
||||||
|
const bname = path.basename(fpath);
|
||||||
|
try print_file_in_dir (dir, bname);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_file_in_dir (dir: fs.Dir, entryname: []const u8) !void {
|
||||||
|
if (options.verbose == false) {
|
||||||
|
return lib.print("{s}\n", .{entryname});
|
||||||
|
}
|
||||||
|
|
||||||
|
return try print_stats (entryname, try dir.fstatat(entryname));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either print directory's content or file.
|
||||||
|
fn print_directory(fpath: []const u8) !void {
|
||||||
|
var dir: fs.Dir = cwd.openDir(fpath, .{.iterate = true}) catch |err| switch (err) {
|
||||||
|
error.AccessDenied => return lib.print("{s}: access denied\n", .{fpath}),
|
||||||
|
error.NotDir => {
|
||||||
|
// fpath is a simple file, just print the file infos
|
||||||
|
return try print_file(fpath);
|
||||||
|
},
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
|
||||||
|
// fpath is a directory: print info on each file
|
||||||
|
var dir_it = dir.iterate();
|
||||||
while (try dir_it.next()) |entry| {
|
while (try dir_it.next()) |entry| {
|
||||||
lib.print("{s}\n", .{entry.name});
|
try print_file_in_dir (dir, entry.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,6 +128,7 @@ pub fn ls() !void {
|
||||||
|
|
||||||
// Skipping the executable binary name.
|
// Skipping the executable binary name.
|
||||||
var arg_idx: usize = 1;
|
var arg_idx: usize = 1;
|
||||||
|
var nb_parameters: i32 = 0;
|
||||||
|
|
||||||
// case there are parameters
|
// case there are parameters
|
||||||
while(arg_idx < cli.args.len) {
|
while(arg_idx < cli.args.len) {
|
||||||
|
|
@ -34,12 +136,18 @@ pub fn ls() !void {
|
||||||
lib.warn("Null argument\n", .{});
|
lib.warn("Null argument\n", .{});
|
||||||
return error.InvalidArgs;
|
return error.InvalidArgs;
|
||||||
};
|
};
|
||||||
try print_element(element);
|
if (std.mem.eql(u8, element, "-l")) {
|
||||||
|
options.verbose = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nb_parameters += 1;
|
||||||
|
try print_directory(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// case there were no parameter, print current directory
|
// case there were no parameter, print current directory
|
||||||
if (cli.args.len == 1) {
|
if (nb_parameters == 0) {
|
||||||
try print_element(".");
|
try print_directory(".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
30
src/main.zig
Normal file
30
src/main.zig
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const eq = std.mem.eql;
|
||||||
|
|
||||||
|
const ls = @import("ls.zig");
|
||||||
|
const cat = @import("cat.zig");
|
||||||
|
|
||||||
|
const lib = @import("lib.zig");
|
||||||
|
|
||||||
|
fn help() void {
|
||||||
|
const help_string =
|
||||||
|
\\
|
||||||
|
\\ toying with a single tool: zig build-exe ls.zig
|
||||||
|
\\ (currently ± working tools: cat, ls)
|
||||||
|
\\
|
||||||
|
\\ global compilation: zig build-exe main.zig
|
||||||
|
\\ -> produces "main" that includes all tools
|
||||||
|
\\ you can invoke each tool by creating a symbolic link to "main"
|
||||||
|
\\ ex: ln -s main ls <- now you have "ls" working as your well-known "ls" :)
|
||||||
|
;
|
||||||
|
lib.print("{s}\n", .{help_string});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
const args = try std.process.argsAlloc(std.heap.page_allocator);
|
||||||
|
const bname = std.fs.path.basename(args[0]);
|
||||||
|
|
||||||
|
if (eq(u8, bname, "ls")) { try ls.main(); }
|
||||||
|
else if (eq(u8, bname, "cat")) { try cat.main(); }
|
||||||
|
else { help(); }
|
||||||
|
}
|
||||||
26
src/test.zig
Normal file
26
src/test.zig
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const path = std.fs.path;
|
||||||
|
const lib = @import("./lib.zig");
|
||||||
|
const fmt = std.fmt;
|
||||||
|
|
||||||
|
const default_max_depth = 3;
|
||||||
|
|
||||||
|
test "print type" {
|
||||||
|
lib.print("hello\n", .{});
|
||||||
|
|
||||||
|
var buffer = [_]u8{0} ** 3;
|
||||||
|
const T = @TypeOf(std.io.fixedBufferStream(&buffer));
|
||||||
|
lib.print("hello: {}\n", .{T});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "buffer stuff" {
|
||||||
|
var buffer = [_]u8 {0} ** (std.fs.MAX_PATH_BYTES + 100);
|
||||||
|
var fbs = std.io.fixedBufferStream(&buffer);
|
||||||
|
|
||||||
|
var writer = fbs.writer();
|
||||||
|
try fmt.formatType('W', "c", fmt.FormatOptions{}, writer, default_max_depth);
|
||||||
|
try fmt.formatType("ritten", "s", fmt.FormatOptions{}, writer, default_max_depth);
|
||||||
|
|
||||||
|
lib.print("{s}\n", .{fbs.getWritten()});
|
||||||
|
fbs.reset();
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue