diff options
Diffstat (limited to 'src/commands/rm.c')
-rw-r--r-- | src/commands/rm.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/commands/rm.c b/src/commands/rm.c new file mode 100644 index 0000000..b85f91a --- /dev/null +++ b/src/commands/rm.c @@ -0,0 +1,132 @@ +#include "../command.h" +#include <dirent.h> +#include <string.h> + +static struct { + bool force; + bool prompt; + bool verbose; + bool recurse; +} flags; + +#ifdef FRENCH + static bool get_frenched; +#endif + +static void help(void) { + printf("Usage: rm [-irfv] FILE...\n\n"); + printf("Remove (unlink) FILESs\n\n"); + printf("\t-i\tAlways prompt before removing\n"); + printf("\t-f\tForce, never prompt\n"); + printf("\t-v\tVerbose\n"); + printf("\t-R,-r\tRecurse\n"); +} + +static int short_arg(char c, char* next) { + UNUSED(next); + switch (c) { + case 'i': + flags.prompt = true; + break; + case 'f': + flags.force = true; + break; + case 'v': + flags.verbose = true; + break; + case 'R': + case 'r': + flags.recurse = true; + break; + default: + return ARG_INVALID; + } + return ARG_UNUSED; +} + +static void rm_file(char* path); + +static bool rm_dir() { + DIR* d = opendir(get_path_buffer()); + if (d == NULL) { + error_s("failed to stat '%s': %s\n", get_path_buffer(), strerror(errno)); + return false; + } + + struct dirent* file; + while ((file = readdir(d)) != NULL) { + if (is_dot_dir(file->d_name)) continue; + rm_file(file->d_name); + } + + closedir(d); + return true; +} + +static void rm_file(char* path) { + int save = push_path_buffer(path); + + struct stat s; + if (lstat(get_path_buffer(), &s) < 0) { + pop_path_buffer(save); + error_s("failed to stat '%s': %s\n", get_path_buffer(), strerror(errno)); + return; + } + + if (S_ISDIR(s.st_mode)) { + if (!flags.force) { + error_s("cannot delete '%s': Is a directory\n", get_path_buffer()); + pop_path_buffer(save); + return; + } + if (flags.recurse && !rm_dir()) { + pop_path_buffer(save); + return; + } + } + + if (flags.prompt) { + fprintf(stderr, "delete '%s'? ", get_path_buffer()); + fflush(stderr); + char c = getchar(); + if (c != 'y' && c != 'Y') { + fprintf(stderr, "Skipping...\n"); + pop_path_buffer(save); + return; + } + } + + if (remove(get_path_buffer()) < 0) { + error_s("failed to delete '%s': %s\n", get_path_buffer(), strerror(errno)); + } else if (flags.verbose) { + output("deleted '%s'\n", get_path_buffer()); + } + + pop_path_buffer(save); +} + +COMMAND(rm) { + if (argc < 1) { + global_help(help); + return EXIT_SUCCESS; + } + + flags.prompt = false; + flags.force = false; + flags.verbose = false; + flags.recurse = false; + + int start = parse_args(argc, argv, help, short_arg, NULL); + +#ifdef FRENCH + if (streql(argv[0], "-rf")) { + printf("\x1b[94mremoving \x1b[97mthe \x1b[91mfrench \x1b[93m(beguette noises)\x1b[0m\n"); + } +#endif + + for (int i = start; i < argc; i++) { + rm_file(argv[i]); + } + + return EXIT_SUCCESS; +} |