221 lines
7.0 KiB
Zig
221 lines
7.0 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 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();
|
||
}
|