~sircmpwn/hautils

23f32fd15646cd49a052d26090b40b525c7d1b84 — Curtis Arthaud 3 months ago cbc99e4
rmdir: new util

Signed-off-by: Curtis Arthaud <uku82@gmx.fr>
2 files changed, 78 insertions(+), 0 deletions(-)

M Makefile
A rmdir.ha
M Makefile => Makefile +2 -0
@@ 15,6 15,7 @@ utils=\
	nl \
	pwd \
	rm \
	rmdir \
	sleep \
	tee \
	touch \


@@ 44,6 45,7 @@ ls: ls.ha main/main.ha
nl: nl.ha main/main.ha
pwd: pwd.ha main/main.ha
rm: rm.ha main/main.ha
rmdir: rmdir.ha main/main.ha
sleep: sleep.ha main/main.ha
tee: tee.ha main/main.ha
touch: touch.ha

A rmdir.ha => rmdir.ha +76 -0
@@ 0,0 1,76 @@
use fmt;
use fs;
use getopt;
use main;
use os;
use path;
use strings;

type config = struct {
	status: int,
	parents: bool
};

export fn utilmain() (void | main::error) = {
	const cmd = getopt::parse(os::args,
		"remove empty directories",
		('p', "remove all directories composing the given pathname"),
		"dirs...");
	defer getopt::finish(&cmd);

	let conf = config { ... };
	for (let (opt, _) .. cmd.opts) {
		switch (opt) {
		case 'p' =>
			conf.parents = true;
		case => abort();
		};
	};

	for (let target .. cmd.args) {
		if (conf.parents) {
			let buf = path::init(target)!;
			let iter = path::riter(&buf);
			for (let sub => path::nextiter(&iter)) {
				let pbuf = path::init(path::iterrem(&iter), sub)!;
				const trgt = path::string(&pbuf);
				match (remove(&conf, trgt)) {
				case let err: fs::error =>
					conf.status = 1;
					fmt::errorfln("{}: Error: {}",
						trgt, fs::strerror(err))!;
					break;
				case void => void;
				};
			};
		} else {
			match (remove(&conf, target)) {
			case let err: fs::error =>
				const errstr = fs::strerror(err);
				conf.status = 1;
				fmt::errorfln("{}: Error: {}", target, errstr)!;
			case void => void;
			};
		};
	};

	os::exit(conf.status);
};

fn remove(conf: *config, path: str) (void | fs::error) = {
	const st = os::stat(path)?;

	if (!fs::isdir(st.mode)) {
		conf.status = 1;
		fmt::errorfln("{}: skipping non-directory", path)?;
		return;
	};

	if (!os::access(path, os::amode::W_OK)?) {
		conf.status = 1;
		fmt::errorfln("{}: skipping read-only directory", path)?;
		return;
	};

	os::rmdir(path)?;
};