133 lines
3 KiB
C
133 lines
3 KiB
C
|
#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;
|
||
|
}
|