zig-toybox/src/ls.zig

221 lines
7.0 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 depth = 3;
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 it: u16 = 0;
var fbs = std.io.fixedBufferStream(&buffer);
var writer = fbs.writer();
const fmtopts = fmt.FormatOptions{};
// try std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
// fbs.reset();
// print kind (directory, file, pipe, etc.)
const kind = fs.File.Stat.system_stat_kind_to_fs_kind(stats);
switch (kind) {
.File => try fmt.formatType('-', "c", fmtopts, writer, depth),
.Directory => try fmt.formatType('d', "c", fmtopts, writer, depth),
.CharacterDevice => try fmt.formatType('c', "c", fmtopts, writer, depth),
.BlockDevice => try fmt.formatType('b', "c", fmtopts, writer, depth),
.NamedPipe => try fmt.formatType('p', "c", fmtopts, writer, depth),
.SymLink => try fmt.formatType('s', "c", fmtopts, writer, depth),
.UnixDomainSocket => try fmt.formatType('s', "c", fmtopts, writer, depth),
else => {
if (builtin.os.tag == .solaris) switch (kind) {
.Door => try fmt.formatType('D', "c", fmtopts, writer, depth), // TODO: what to print here?
.EventPort => try fmt.formatType('e', "c", fmtopts, writer, depth), // TODO: what to print here?
else => try fmt.formatType('?', "c", fmtopts, writer, depth),
};
},
}
// 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 fmt.formatType('r', "c", fmtopts, writer, depth),
.write => try fmt.formatType('w', "c", fmtopts, writer, depth),
.execute => try fmt.formatType('x', "c", fmtopts, writer, depth),
}
}
else {
try fmt.formatType('-', "c", fmtopts, writer, depth);
}
}
}
// TODO: print user & group
try fmt.formatType('\t', "c", fmtopts, writer, depth);
try fmt.formatType(stats.uid, "", fmtopts, writer, depth);
try fmt.formatType('\t', "c", fmtopts, writer, depth);
try fmt.formatType(stats.gid, "", fmtopts, writer, depth);
// TODO: print size
// TODO: print date last write
// lib.print("{s}: {}\n", .{fpath, stats});
// std.mem.copy (u8, buffer[it..], fpath);
try fmt.formatType('\t', "c", fmtopts, writer, depth);
try fmt.formatType(fpath, "s", fmtopts, writer, depth);
try fmt.formatType('\n', "c", fmtopts, writer, depth);
// TODO: print user & group
// TODO: print size
// TODO: print date last write
// lib.print("{s}: {}\n", .{fpath, stats});
return lib.print("{s}", .{fbs.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);
// // First, try to open the file to stat it.
// var f: std.fs.File = undefined;
// f = switch (path.isAbsolute(fpath)) {
// true => std.fs.openFileAbsolute(fpath, .{.mode = .read_only}),
// else => cwd.openFile(fpath, .{.mode = .read_only}),
// } catch |err| switch(err) {
// error.AccessDenied => {
// lib.print("access denied\n", .{});
// // try to read the content of the parent directory
// return err;
// },
// else => return err,
// };
// defer f.close();
//
// const stats = try f.stat();
// return print_stats (fpath, stats);
}
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();
}