]>
Commit | Line | Data |
---|---|---|
eb63b9b8 KZ |
1 | /* |
2 | * rename.c - aeb 2000-01-01 | |
3 | * | |
4 | -------------------------------------------------------------- | |
5 | #!/bin/sh | |
6 | if [ $# -le 2 ]; then echo call: rename from to files; exit; fi | |
7 | FROM="$1" | |
8 | TO="$2" | |
9 | shift | |
10 | shift | |
11 | for i in $@; do N=`echo "$i" | sed "s/$FROM/$TO/g"`; mv "$i" "$N"; done | |
12 | -------------------------------------------------------------- | |
13 | * This shell script will do renames of files, but may fail | |
14 | * in cases involving special characters. Here a C version. | |
15 | */ | |
16 | #include <stdio.h> | |
17 | #include <string.h> | |
18 | #include <stdlib.h> | |
19 | #include <errno.h> | |
d200a926 | 20 | #include <getopt.h> |
5a2a8177 JM |
21 | #include <unistd.h> |
22 | #include <sys/types.h> | |
23 | #include <sys/stat.h> | |
87f3feac | 24 | |
eb63b9b8 | 25 | #include "nls.h" |
87f3feac | 26 | #include "xalloc.h" |
d200a926 | 27 | #include "c.h" |
c05a80ca | 28 | #include "closestream.h" |
eb63b9b8 | 29 | |
d6cf9e16 SK |
30 | #define RENAME_EXIT_SOMEOK 2 |
31 | #define RENAME_EXIT_NOTHING 4 | |
32 | #define RENAME_EXIT_UNEXPLAINED 64 | |
33 | ||
5651128a | 34 | static int string_replace(char *from, char *to, char *s, char *orig, char **newname) |
d200a926 | 35 | { |
5651128a SK |
36 | char *p, *q, *where; |
37 | ||
38 | where = strstr(s, from); | |
39 | if (where == NULL) | |
40 | return 1; | |
41 | p = orig; | |
42 | *newname = xmalloc(strlen(orig) + strlen(to) + 1); | |
43 | q = *newname; | |
eb63b9b8 KZ |
44 | while (p < where) |
45 | *q++ = *p++; | |
46 | p = to; | |
47 | while (*p) | |
48 | *q++ = *p++; | |
5651128a | 49 | p = where + strlen(from); |
eb63b9b8 KZ |
50 | while (*p) |
51 | *q++ = *p++; | |
22853e4a | 52 | *q = 0; |
5651128a SK |
53 | return 0; |
54 | } | |
eb63b9b8 | 55 | |
990bf1f0 | 56 | static int do_symlink(char *from, char *to, char *s, int verbose, int noact) |
5651128a SK |
57 | { |
58 | char *newname = NULL, *target = NULL; | |
59 | int ret = 1; | |
60 | struct stat sb; | |
61 | ||
62 | if (lstat(s, &sb) == -1) { | |
fc14ceba | 63 | warn(_("stat of %s failed"), s); |
5651128a SK |
64 | return 2; |
65 | } | |
66 | if (!S_ISLNK(sb.st_mode)) { | |
67 | warnx(_("%s: not a symbolic link"), s); | |
68 | return 2; | |
69 | } | |
70 | target = xmalloc(sb.st_size + 1); | |
71 | if (readlink(s, target, sb.st_size + 1) < 0) { | |
72 | warn(_("%s: readlink failed"), s); | |
73 | free(target); | |
74 | return 2; | |
75 | } | |
76 | target[sb.st_size] = '\0'; | |
77 | if (string_replace(from, to, target, target, &newname)) | |
78 | ret = 0; | |
990bf1f0 | 79 | else if (!noact && 0 > unlink(s)) { |
5651128a SK |
80 | warn(_("%s: unlink failed"), s); |
81 | ret = 2; | |
990bf1f0 | 82 | } else if (!noact && symlink(newname, s) != 0) { |
5651128a SK |
83 | warn(_("%s: symlinking to %s failed"), s, newname); |
84 | ret = 2; | |
5a2a8177 | 85 | } |
990bf1f0 | 86 | if (verbose && (noact || ret == 1)) |
5651128a | 87 | printf("%s: `%s' -> `%s'\n", s, target, newname); |
d200a926 | 88 | free(newname); |
23b4715b | 89 | free(target); |
d6cf9e16 | 90 | return ret; |
eb63b9b8 KZ |
91 | } |
92 | ||
990bf1f0 | 93 | static int do_file(char *from, char *to, char *s, int verbose, int noact) |
5651128a | 94 | { |
9fa6088a | 95 | char *newname = NULL, *file=NULL; |
5651128a SK |
96 | int ret = 1; |
97 | ||
9fa6088a AH |
98 | if (strchr(from, '/') == NULL && strchr(to, '/') == NULL) |
99 | file = strrchr(s, '/'); | |
5651128a SK |
100 | if (file == NULL) |
101 | file = s; | |
102 | if (string_replace(from, to, file, s, &newname)) | |
103 | return 0; | |
990bf1f0 | 104 | else if (!noact && rename(s, newname) != 0) { |
5651128a SK |
105 | warn(_("%s: rename to %s failed"), s, newname); |
106 | ret = 2; | |
107 | } | |
990bf1f0 | 108 | if (verbose && (noact || ret == 1)) |
5651128a SK |
109 | printf("`%s' -> `%s'\n", s, newname); |
110 | free(newname); | |
111 | return ret; | |
112 | } | |
113 | ||
d200a926 SK |
114 | static void __attribute__ ((__noreturn__)) usage(FILE * out) |
115 | { | |
540dfebe | 116 | fputs(USAGE_HEADER, out); |
d200a926 | 117 | fprintf(out, |
09af3db4 | 118 | _(" %s [options] <expression> <replacement> <file>...\n"), |
d200a926 | 119 | program_invocation_short_name); |
451dbcfa BS |
120 | |
121 | fputs(USAGE_SEPARATOR, out); | |
122 | fputs(_("Rename files.\n"), out); | |
123 | ||
540dfebe SK |
124 | fputs(USAGE_OPTIONS, out); |
125 | fputs(_(" -v, --verbose explain what is being done\n"), out); | |
09af3db4 | 126 | fputs(_(" -s, --symlink act on the target of symlinks\n"), out); |
990bf1f0 | 127 | fputs(_(" -n, --no-act do not make any changes\n"), out); |
540dfebe SK |
128 | fputs(USAGE_SEPARATOR, out); |
129 | fputs(USAGE_HELP, out); | |
130 | fputs(USAGE_VERSION, out); | |
131 | fprintf(out, USAGE_MAN_TAIL("rename(1)")); | |
d200a926 SK |
132 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); |
133 | } | |
eb63b9b8 | 134 | |
d200a926 SK |
135 | int main(int argc, char **argv) |
136 | { | |
137 | char *from, *to; | |
990bf1f0 AR |
138 | int i, c, ret = 0, verbose = 0, noact = 0; |
139 | int (*do_rename)(char *from, char *to, char *s, int verbose, int noact) = do_file; | |
d200a926 SK |
140 | |
141 | static const struct option longopts[] = { | |
142 | {"verbose", no_argument, NULL, 'v'}, | |
143 | {"version", no_argument, NULL, 'V'}, | |
144 | {"help", no_argument, NULL, 'h'}, | |
990bf1f0 | 145 | {"no-act", no_argument, NULL, 'n'}, |
5a2a8177 | 146 | {"symlink", no_argument, NULL, 's'}, |
d200a926 SK |
147 | {NULL, 0, NULL, 0} |
148 | }; | |
eb63b9b8 KZ |
149 | |
150 | setlocale(LC_ALL, ""); | |
151 | bindtextdomain(PACKAGE, LOCALEDIR); | |
152 | textdomain(PACKAGE); | |
c05a80ca | 153 | atexit(close_stdout); |
eb63b9b8 | 154 | |
990bf1f0 | 155 | while ((c = getopt_long(argc, argv, "vsVhn", longopts, NULL)) != -1) |
d200a926 SK |
156 | switch (c) { |
157 | case 'v': | |
158 | verbose = 1; | |
159 | break; | |
990bf1f0 AR |
160 | case 'n': |
161 | noact = 1; | |
162 | break; | |
5a2a8177 | 163 | case 's': |
5651128a | 164 | do_rename = do_symlink; |
5a2a8177 | 165 | break; |
d200a926 | 166 | case 'V': |
c717b032 | 167 | printf(UTIL_LINUX_VERSION); |
d200a926 SK |
168 | return EXIT_SUCCESS; |
169 | case 'h': | |
170 | usage(stdout); | |
990bf1f0 | 171 | /* fallthrough */ |
d200a926 | 172 | default: |
677ec86c | 173 | errtryhelp(EXIT_FAILURE); |
eb63b9b8 | 174 | } |
d200a926 SK |
175 | |
176 | argc -= optind; | |
177 | argv += optind; | |
eb63b9b8 KZ |
178 | |
179 | if (argc < 3) { | |
8c219bf4 | 180 | warnx(_("not enough arguments")); |
d200a926 | 181 | usage(stderr); |
eb63b9b8 KZ |
182 | } |
183 | ||
d200a926 SK |
184 | from = argv[0]; |
185 | to = argv[1]; | |
186 | ||
187 | for (i = 2; i < argc; i++) | |
990bf1f0 | 188 | ret |= do_rename(from, to, argv[i], verbose, noact); |
d6cf9e16 SK |
189 | |
190 | switch (ret) { | |
191 | case 0: | |
192 | return RENAME_EXIT_NOTHING; | |
193 | case 1: | |
194 | return EXIT_SUCCESS; | |
195 | case 2: | |
196 | return EXIT_FAILURE; | |
197 | case 3: | |
198 | return RENAME_EXIT_SOMEOK; | |
199 | default: | |
200 | return RENAME_EXIT_UNEXPLAINED; | |
201 | } | |
eb63b9b8 | 202 | } |