zig-toybox/src/ls.zig

181 lines
5.3 KiB
Zig
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

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;
// // /absolute/path/file => fpath + sep + entry.name
// std.mem.copy (u8, fullname[0..], fpath);
// fullname[fpath.len] = path.sep; // '/' on Unix-like systems, '\' on Windows.
// std.mem.copy (u8, fullname[fpath.len+1..], entry.name);
// try print_file(fullname[0..fpath.len+1+entry.name.len]);
// Stats
// .size = @bitCast(u64, info.StandardInformation.EndOfFile),
// .mode = 0,
// .atime = LastAccessTime
// .mtime = LastWriteTime
// .ctime = CreationTime
// WON'T: human output => use human command instead
// TODO: error management.
// TODO: verbose output (-l).
pub const cwd = fs.cwd();
const Sorting = enum {
None,
DateCreation, // TODO
DateLastAccess, // TODO
DateLastWrite, // TODO
Size, // TODO
};
const Options = struct {
sorting: Sorting = Sorting.None,
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 dir: fs.Dir = cwd.openDir(dname.?, .{}) 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});
}
// lib.print("{}\n", .{try dir.statFile(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();
}