hautils

[hare] Set of POSIX utilities
Log | Files | Refs | README | LICENSE

rm.ha (1363B)


      1 use fmt;
      2 use fs;
      3 use getopt;
      4 use main;
      5 use os;
      6 
      7 type config = struct {
      8 	status: int,
      9 	force: bool,
     10 	recur: bool,
     11 };
     12 
     13 export fn utilmain() (void | main::error) = {
     14 	const cmd = getopt::parse(os::args,
     15 		"remove files",
     16 		('f', "remove read-only files and ignore errors"),
     17 		('r', "remove directories and their contents"),
     18 		"files...");
     19 	defer getopt::finish(&cmd);
     20 
     21 	let conf = config { ... };
     22 	for (let i = 0z; i < len(cmd.opts); i += 1) {
     23 		switch (cmd.opts[i].0) {
     24 		case 'f' =>
     25 			conf.force = true;
     26 		case 'r' =>
     27 			conf.recur = true;
     28 		case => abort();
     29 		};
     30 	};
     31 
     32 	for (let i = 0z; i < len(cmd.args); i += 1) {
     33 		const target = cmd.args[i];
     34 		match (remove(&conf, target)) {
     35 		case let err: fs::error =>
     36 			conf.status = 1;
     37 			if (!conf.force) {
     38 				fmt::errorfln("{}: Error: {}",
     39 					target, fs::strerror(err))!;
     40 			};
     41 		case void => void;
     42 		};
     43 	};
     44 
     45 	os::exit(conf.status);
     46 };
     47 
     48 fn remove(conf: *config, path: str) (void | fs::error) = {
     49 	const st = os::stat(path)?;
     50 	if (fs::isdir(st.mode) && !conf.recur) {
     51 		if (!conf.force) {
     52 			conf.status = 1;
     53 			fmt::errorfln("{}: skipping directory", path)?;
     54 		};
     55 		return;
     56 	};
     57 
     58 	if (!os::access(path, os::amode::W_OK)? && !conf.force) {
     59 		conf.status = 1;
     60 		fmt::errorfln("{}: skipping read-only file", path)?;
     61 		return;
     62 	};
     63 
     64 	if (fs::isdir(st.mode)) {
     65 		os::rmdirall(path)?;
     66 	} else {
     67 		os::remove(path)?;
     68 	};
     69 };