157 lines
4.6 KiB
Zig
157 lines
4.6 KiB
Zig
const std = @import("std");
|
|
const os = std.os;
|
|
const builtin = @import("builtin");
|
|
const path = std.fs.path;
|
|
const fs = std.fs;
|
|
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
|
|
// TODO: error management.
|
|
|
|
pub const cwd = fs.cwd();
|
|
|
|
const Options = struct {
|
|
verbose: bool = false,
|
|
};
|
|
|
|
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,
|
|
};
|
|
|
|
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| {
|
|
try print_file_in_dir (dir, entry.name);
|
|
}
|
|
}
|
|
|
|
pub fn ls() !void {
|
|
var cli = try lib.CLI.init();
|
|
defer cli.deinit();
|
|
|
|
// Skipping the executable binary name.
|
|
var arg_idx: usize = 1;
|
|
var nb_parameters: i32 = 0;
|
|
|
|
// case there are parameters
|
|
while(arg_idx < cli.args.len) {
|
|
const element = cli.nextArg(&arg_idx) orelse {
|
|
lib.warn("Null argument\n", .{});
|
|
return error.InvalidArgs;
|
|
};
|
|
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
|
|
if (nb_parameters == 0) {
|
|
try print_directory(".");
|
|
}
|
|
}
|
|
|
|
pub fn main() !void {
|
|
try ls();
|
|
}
|