From ac4aab2bd44ac445ba526f0fee99a57f668f97e0 Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Thu, 27 Aug 2020 02:32:07 -0400 Subject: [PATCH 1/3] Add `mv`. --- src/mv.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/mv.c diff --git a/src/mv.c b/src/mv.c new file mode 100644 index 0000000..b02fe56 --- /dev/null +++ b/src/mv.c @@ -0,0 +1,92 @@ +/** + * NAME + * ==== + * mv - move (rename) files + * + * SYNOPSIS + * ======== + * mv [-if] source_file target_file + * mv [-if] source_file... target_dir + * mv [--help|--version] + * + * DESCRIPTION + * =========== + * Move files. + * + * -i Prompt when a file would be overwritten. + * -f Don't prompt when a file would be overwritten. + * + * --help Print help text and exit. + * --version Print version information and exit. + */ + +#include +#include +#include "boreutils.h" + +static int prompt(char *dest) { + char ret[2] = "-"; + fprintf(stderr, "mv: overwrite '%s'? [y/N] ", dest); + fgets(ret, 2, stdin); + + if (ret[0] == 'y' || ret[0] == 'Y') { + return 1; + } + return 0; +} + +static int would_overwrite(char *src, char *dest) { + (void)src; + return access(dest, F_OK) + 1; +} + +int main(int argc, char **argv) { + if (has_arg(argc, argv, "-h") || has_arg(argc, argv, "--help")) { + puts("Usage: mv [-if] source_file target_file"); + puts(" mv [-if] source_file... target_dir"); + puts("Move (rename) files."); + puts("-i Prompt when a file would be overwritten."); + puts("-f Don't prompt when a file would be overwritten."); + return 1; + } + + if (bu_handle_version(argc, argv)) { + return 0; + } + + int ret = 0; + int should_prompt = 0; + char *dest = argv[argc - 1]; + + int i = 1; + for (; i < argc; i++) { + if (argv[i][0] != '-') { + break; + } + + for (size_t j = 1; j < strlen(argv[i]); j++) { + if (argv[i][j] == 'f') { + should_prompt = 0; + } else if (argv[i][j] == 'i') { + should_prompt = 1; + } else { + char arg[3] = {'-', argv[i][j], 0}; + bu_invalid_argument(argv[0], arg); + } + } + } + + for (; i < argc - 1; i++) { + if (should_prompt && would_overwrite(argv[i], dest)) { + if (prompt(dest) == 0) { + continue; + } + } + + if (rename(argv[i], dest) == -1) { + perror("mv"); + ret = 1; + } + } + return ret; +} From d806fb200af6441c89659667471441919a4f4e5a Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Fri, 28 Aug 2020 12:26:14 -0400 Subject: [PATCH 2/3] Add (untested) mv implementation. --- src/mv.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/src/mv.c b/src/mv.c index b02fe56..1485943 100644 --- a/src/mv.c +++ b/src/mv.c @@ -20,8 +20,11 @@ * --version Print version information and exit. */ +#include #include +#include #include +#include #include "boreutils.h" static int prompt(char *dest) { @@ -35,9 +38,41 @@ static int prompt(char *dest) { return 0; } -static int would_overwrite(char *src, char *dest) { - (void)src; - return access(dest, F_OK) + 1; +// If dest is a directory, returns `/`. +// Otherwise, returns ``. +static char *normalize_dest(char *src, char *dest) { + struct stat statbuf; + if (stat(dest, &statbuf) != 0) { + // `dest` doesn't exist. + return dest; + } + + if (!S_ISDIR(statbuf.st_mode)) { + // `dest` is a file (not a directory). + return dest; + } + + // Beyond this point, `dest` is known to be a directory. + // This means we need `/`. + + // First, get the basename of `src`. + char *base_name = basename(src); + size_t base_name_size = strlen(base_name); + + size_t dest_size = strlen(dest); + // + <1 for slash> + + <1 for null terminator> + char *full_dest = malloc(sizeof(char) * (dest_size + 1 + base_name_size + 1)); + memset(full_dest, 0, dest_size + 1 + base_name_size + 1); + + strncpy(full_dest, dest, dest_size + 1); + if (dest[dest_size - 1] != '/') { + full_dest[dest_size] = '/'; + strncpy(full_dest + dest_size + 1, base_name, base_name_size + 1); + } else { + strncpy(full_dest + dest_size, base_name, base_name_size + 1); + } + + return full_dest; } int main(int argc, char **argv) { @@ -77,8 +112,9 @@ int main(int argc, char **argv) { } for (; i < argc - 1; i++) { - if (should_prompt && would_overwrite(argv[i], dest)) { - if (prompt(dest) == 0) { + char *normalized_dest = normalize_dest(argv[i], dest); + if (should_prompt && access(normalized_dest, F_OK) == 0) { + if (prompt(normalized_dest) == 0) { continue; } } From 088d26a5adea0d4234dafc289d35ef25716f2352 Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Fri, 28 Aug 2020 12:48:06 -0400 Subject: [PATCH 3/3] [mv] Avoid calling `normalize_dest()` when it's not required. --- src/mv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mv.c b/src/mv.c index 1485943..f82acda 100644 --- a/src/mv.c +++ b/src/mv.c @@ -112,10 +112,12 @@ int main(int argc, char **argv) { } for (; i < argc - 1; i++) { - char *normalized_dest = normalize_dest(argv[i], dest); - if (should_prompt && access(normalized_dest, F_OK) == 0) { - if (prompt(normalized_dest) == 0) { - continue; + if (should_prompt) { + char *normalized_dest = normalize_dest(argv[i], dest); + if (access(normalized_dest, F_OK) == 0) { + if (prompt(normalized_dest) == 0) { + continue; + } } }