Blob


1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
9 #define O_INTERACTIVE 1
10 #define O_NOACT (1<<1)
11 #define O_NOOVERRIDE (1<<2)
12 #define O_REPLACEALL (1<<3)
13 #define O_REPLACELAST (1<<4)
14 #define O_VERBOSE (1<<5)
16 #define MAX_FILENAME 4096
18 uint8_t opts;
19 char new[MAX_FILENAME], *newe = new + MAX_FILENAME-1;
21 void
22 warn(const char *fmt, ...)
23 {
24 char *w = strerror(errno);
25 fputs("rene: ", stderr);
26 if (fmt != NULL) {
27 va_list argp;
28 va_start(argp, fmt);
29 vfprintf(stderr, fmt, argp);
30 va_end(argp);
31 }
32 fprintf(stderr, ": %s\n", w);
33 }
35 void
36 err(int eval, const char *fmt, ...)
37 {
38 char *w = strerror(errno);
39 fputs("rene: ", stderr);
40 if (fmt != NULL) {
41 va_list argp;
42 va_start(argp, fmt);
43 vfprintf(stderr, fmt, argp);
44 va_end(argp);
45 }
46 fprintf(stderr, ": %s\n", w);
47 exit(eval);
48 }
50 void
51 errx(int eval, const char *fmt, ...)
52 {
53 fputs("rene: ", stderr);
54 if (fmt != NULL) {
55 va_list argp;
56 va_start(argp, fmt);
57 vfprintf(stderr, fmt, argp);
58 va_end(argp);
59 }
60 fputc('\n', stderr);
61 exit(eval);
62 }
64 int
65 ren(char *from, char *to, char *f)
66 {
67 int y = !(opts & O_NOOVERRIDE);
69 char *p = strrchr(f, '/');
70 if (p) {
71 if (*++p == '\0')
72 return 1;
73 } else
74 p = f;
75 if (!(p = strstr(p, from)))
76 return 1;
77 int fromlen = strlen(from);
78 if (opts & O_REPLACELAST)
79 for(char *x; (x = strstr(p+fromlen, from)); p = x)
80 ;
82 char *fp = f;
83 char *newp = new;
84 char *top = to;
85 for (;;) {
86 for (; fp != p; *newp++ = *fp++)
87 if (newp == newe)
88 toolong:
89 errx(1, "%s: final file name is too long", f);
90 if (!*fp)
91 break;
92 for (top = to; *top != '\0'; *newp++ = *top++)
93 if (newp == newe)
94 goto toolong;
95 fp += fromlen;
96 if (!(opts & O_REPLACEALL) || !(p = strstr(fp, from)))
97 p = strchr(fp, '\0');
98 }
99 *newp = '\0';
101 if (opts & O_INTERACTIVE && access(new, F_OK) == 0) {
102 fprintf(stderr, "replace %s with %s? ", from, to);
103 y = getchar() == 'y';
105 if (y && !(opts & O_NOACT) && !(y += rename(f, new))) {
106 warn("rename");
107 return 0;
109 if (opts & O_VERBOSE && y)
110 printf("%s -> %s\n", f, new);
111 return 1;
114 void
115 usage(void)
117 fputs("usage: rene [-ailnov] from to file ...\n", stderr);
118 exit(EXIT_FAILURE);
121 int
122 main(int argc, char *argv[])
124 int c, ret = 0;
125 #ifdef __OpenBSD__
126 if (pledge("stdio cpath rpath", NULL) == -1)
127 err(1, "pledge");
128 #endif
129 while ((c = getopt(argc, argv, "ailnov")) != -1) {
130 switch (c) {
131 case 'a':
132 opts |= O_REPLACEALL;
133 break;
134 case 'i':
135 opts |= O_INTERACTIVE;
136 break;
137 case 'l':
138 opts |= O_REPLACELAST;
139 break;
140 case 'n':
141 opts |= O_NOACT;
142 break;
143 case 'o':
144 opts |= O_NOOVERRIDE;
145 break;
146 case 'v':
147 opts |= O_VERBOSE;
148 break;
149 default:
150 usage();
153 argc -= optind;
154 argv += optind;
156 if (argc < 3 || !argv[0] || !argv[1] || !argv[0][0])
157 usage();
158 for (int i = 2; i < argc; i++)
159 if (!ren(argv[0], argv[1], argv[i]))
160 ret = 1;
161 return ret;