sys

A set of unix utils in hare!
Log | Files | Refs | README

ls.ha (3397B)


      1 use fmt;
      2 use os;
      3 use getopt;
      4 use fs;
      5 use strings;
      6 use io;
      7 
      8 use color;
      9 use util;
     10 
     11 type mode = enum uint {
     12 	DIR = 1 << 0,
     13 	COLOR = 1 << 1,
     14 	ALL = 1 << 2,
     15 };
     16 
     17 let script = false;
     18 let color = true;
     19 let all = false;
     20 let showdirs = true;
     21 let path = "";
     22 
     23 fn bit(ent: uint, m: uint) bool = ((ent & m) == m);
     24 
     25 fn getcol(ent: str, link: bool) color::col = {
     26 	let m = os::stat(ent)!.mode;
     27 
     28 	if (bit(m, fs::mode::BLK) || bit(m, fs::mode::CHR))
     29 		return (color::colors::YELLOW, color::mode::BOLD)
     30 
     31 	else if (bit(m, fs::mode::DIR)) {
     32 		if (link)
     33 			return (color::colors::BLUE, color::mode::ITAL);
     34 		return (color::colors::BLUE, color::mode::BOLD);
     35 	} else if (link) 
     36 		return (color::colors::NORM, color::mode::ITAL)
     37 
     38 	else if (bit(m, fs::mode::OTHER_X) ||
     39 		bit(m, fs::mode::USER_X) ||
     40 		bit(m, fs::mode::GROUP_X)) return (color::colors::GREEN, color::mode::BOLD)
     41 
     42 
     43 
     44 	else return (color::colors::NORM, color::mode::NORM);
     45 };
     46 
     47 fn printent(ent: fs::dirent, opts: mode, file: str) void = {
     48 	if (!bit(opts, mode::ALL)) {
     49 		match (strings::index(ent.name, '.')) {
     50 		case void => yield;
     51 		case let i: size => if (i == 0) return;
     52 		};
     53 	};
     54 
     55 	let res = fmt::asprint(ent.name)!;
     56 	defer free(res);
     57 
     58 	if (bit(opts, mode::DIR) && bit(ent.ftype, fs::mode::DIR) && !bit(ent.ftype, fs::mode::BLK)) 
     59 		res = fmt::asprintf("{}{}", res, "/")!;
     60 
     61 	let link = false;
     62 	if (bit(ent.ftype, fs::mode::LINK)) {
     63 		link = true;
     64 		file = os::readlink(ent.name)!;
     65 		if (bit(opts, mode::DIR) && bit(os::stat(file)!.mode, fs::mode::DIR)) 
     66 			res = fmt::asprintf("{}{}", res, "/")!;
     67 	};
     68 
     69 
     70 	if (bit(opts, mode::COLOR)) 
     71 		color::println(res, getcol(file, link))
     72 	else
     73 		fmt::println(res)!;
     74 };
     75 
     76 export fn main() void = {
     77 	const cmd = getopt::parse(os::args,
     78 		"list directory contents",
     79 		('s', "scriptable output, equivelant to -aCD"),
     80 		('a', "show all files, including hidden files"),
     81 		('c', "color output (default)"),
     82 		('d', "show dirs with '/' (default)"),
     83 		('A', "don't show all files (default)"),
     84 		('C', "no color output"),
     85 		('D', "don't show dirs with '/'"),
     86 		"where"
     87 	);
     88 	defer getopt::finish(&cmd);
     89 
     90 	for (let opt .. cmd.opts) {
     91 		switch (opt.0) {
     92 		case 's' => script = true;
     93 		case 'a' => all = true;
     94 		case 'c' => color = true;
     95 		case 'A' => all = false;
     96 		case 'C' => color = false;
     97 		case 'd' => showdirs = true;
     98 		case 'D' => showdirs = false;
     99 		case => abort();
    100 		};
    101 	};
    102 
    103 	if (len(cmd.args) > 1) util::die("can only list one directory")
    104 	else if (len(cmd.args) == 1) path = cmd.args[0]
    105 	else path = "./";
    106 
    107 	if (script) {
    108 		all = true;
    109 		color = false;
    110 		showdirs = false;
    111 	};
    112 	let dir = match (os::diropen(path)) {
    113 	case let fs: *fs::fs => os::chdir(fs)!;
    114 	case let e: fs::error => util::die(fs::strerror(e));
    115 	};
    116 
    117 	let dir = match (os::diropen("./")) {
    118 	case let fs: *fs::fs => yield fs;
    119 	case let e: fs::error => util::die(fs::strerror(e));
    120 	};
    121 	defer fs::close(dir);
    122 
    123 	let iter = match(fs::iter(dir, "./")) {
    124 	case let iter: *fs::iterator => yield iter;
    125 	case let e: fs::error => util::die(fs::strerror(e));
    126 	};
    127 	defer fs::finish(iter);
    128 
    129 	let dirs: []fs::dirent = [];
    130 	defer free(dirs);
    131 
    132 	for (let dirent = fs::next(iter)!; dirent is fs::dirent; dirent = fs::next(iter)!) {
    133 		let d = dirent as fs::dirent;
    134 		append(dirs, d)!;
    135 	};
    136 
    137 	for (let ent .. dirs) {
    138 		let opts: mode = 0;
    139 
    140 		if (all) opts |= mode::ALL;
    141 		if (color) opts |= mode::COLOR;
    142 		if (showdirs) opts |= mode::DIR;
    143 
    144 		printent(ent, opts, ent.name);
    145 	};
    146 };