summaryrefslogtreecommitdiff
path: root/src/commands/mv.c
blob: f3e759a397fd4e63b1918ee302c2f5391990686d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "../command.h"

static struct {
    bool prompt;
    bool dont_overwrite;
    bool refuse_if_dir;
    bool verbose;
} flags;

static void help(void) {
    printf("Usage: mv [-inT] SOURCE... DIRECTORY\n\n");
    printf("Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n");
    printf("\t-i\tInteractive, prompt before overwriting\n");
    printf("\t-n\tDon't overwrite an existing file\n");
    printf("\t-T\tRefuse to move if DEST is a directory\n");
    printf("\t-v\tVerbose\n");
}

static int short_arg(char c, char* next) {
    UNUSED(next);
    switch (c) {
        case 't':
            flags.prompt = true;
            break;
        case 'n':
            flags.dont_overwrite = true;
            break;
        case 'T':
            flags.refuse_if_dir = true;
            break;
        case 'v':
            flags.verbose = true;
            break;
        default:
            return ARG_UNUSED;
    }
    return ARG_USED;
}

static void mv_dir(bool exists) {
    if (exists && flags.dont_overwrite) {
        if (flags.verbose) output("skipping '%s'; overwrise is false", get_path_buffer_2());
        return;
    }
    if (exists && flags.prompt) {
        fprintf(stderr, "overwrite '%s'? ", get_path_buffer_2());
        fflush(stderr);
        char c = getchar();
        if (c != 'y' && c != 'Y') {
            if (flags.verbose) output("skipping...");
            return;
        }
    }
    
    if (rename(get_path_buffer(), get_path_buffer_2()) < 0) {
        error_s("cannot move '%s': %s", get_path_buffer(), strerror(errno));
    } else if (flags.verbose) {
        output("moved '%s'", get_path_buffer());
    }
}

COMMAND(mv) {

    flags.refuse_if_dir = false;
    flags.dont_overwrite = false;
    flags.prompt = false;
    flags.verbose = false;

    int start = parse_args(argc, argv, help, short_arg, NULL);

    if (argc - start < 2) {
        global_help(help);
    }

    push_path_buffer_2(argv[argc-1]);

    bool dest = true;
    struct stat s;
    if (lstat(get_path_buffer_2(), &s) < 0 && argc - start > 2) {
        dest = false;
        error("cannot stat '%s': %s", get_path_buffer_2(), strerror(errno));
    }
    
    if (dest && flags.refuse_if_dir) {
        if (S_ISDIR(s.st_mode)) {
            error("target '%s': Is A Directory", get_path_buffer_2());
        }
    }

    if (argc - start == 2) {
        push_path_buffer(argv[argc-2]);
        mv_dir(dest);
        return EXIT_SUCCESS;
    }

    if (dest && !S_ISDIR(s.st_mode)) {
        error("target '%s': Is Not A Directory", get_path_buffer_2());
    }

    for (int i = start; i < argc - 1; i++) {
        int save = push_path_buffer(argv[i]);
        bool exists = lstat(get_path_buffer(), &s) >= 0;
        mv_dir(exists);
        pop_path_buffer(save);
    }

    return EXIT_SUCCESS;
}