Blob


1 #include <errno.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
8 #define O_INTERACTIVE 1
9 #define O_NOACT (1<<1)
10 #define O_NOOVERRIDE (1<<2)
11 #define O_REPLACEALL (1<<3)
12 #define O_REPLACELAST (1<<4)
13 #define O_VERBOSE (1<<5)
15 uint8_t opts;
17 void
18 warn(const char *fmt, ...)
19 {
20 char *w = strerror(errno);
21 fputs("rene: ", stderr);
22 if (fmt != NULL) {
23 va_list argp;
24 va_start(argp, fmt);
25 vfprintf(stderr, fmt, argp);
26 va_end(argp);
27 }
28 fprintf(stderr, ": %s\n", w);
29 }
31 void
32 err(int eval, const char *fmt, ...)
33 {
34 char *w = strerror(errno);
35 fputs("rene: ", stderr);
36 if (fmt != NULL) {
37 va_list argp;
38 va_start(argp, fmt);
39 vfprintf(stderr, fmt, argp);
40 va_end(argp);
41 }
42 fprintf(stderr, ": %s\n", w);
43 exit(eval);
44 }
46 int
47 strrep(char *from, char *to, char *s, char **new)
48 {
49 char *p = strrchr(s, '/');
50 if (p) {
51 if (*++p == '\0')
52 return 0;
53 } else
54 p = s;
55 p = strstr(p, from);
56 if (!p)
57 return 0;
58 int fromlen = strlen(from);
59 int count = 1;
60 if (opts & O_REPLACELAST || opts & O_REPLACEALL) {
61 char *temp = p;
62 while (temp) {
63 temp = strstr(temp+fromlen, from);
64 count = (opts & O_REPLACEALL && temp) ? count + 1 :
65 count;
66 p = (opts & O_REPLACELAST && temp) ? temp : p;
67 }
68 }
70 if (!(*new =
71 malloc(strlen(s) + strlen(to)*count - fromlen*count + 1))) {
72 warn("malloc");
73 return 0;
74 }
76 char *newp = *new;
77 char *top = to;
78 while (p) {
79 for (; s != p; *newp++ = *s++)
80 ;
81 for (; *top != '\0'; *newp++ = *top++)
82 ;
83 s += fromlen;
84 p = opts & O_REPLACEALL ? strstr(s, from) : strchr(s, '\0');
85 p = p ? p : strchr(s, '\0');
86 for (; s != p; *newp++ = *s++)
87 ;
88 p = (*p == '\0') ? NULL : p;
89 top = to;
90 }
91 *newp = '\0';
92 return 1;
93 }
95 int
96 ask(char *from, char *to)
97 {
98 fprintf(stderr, "replace %s with %s? ", from, to);
99 return getchar() == 'y';
102 void
103 ren(char *from, char *to, char *f)
105 int yes = 1;
106 char *new = NULL;
107 if (!strrep(from, to, f, &new))
108 return;
109 if ((opts & O_NOOVERRIDE || opts & O_INTERACTIVE) &&
110 access(new, F_OK) == 0)
111 yes = opts & O_NOOVERRIDE ? 0 : ask(f, new);
112 if (yes && !(opts & O_NOACT) && !(yes += rename(f, new)))
113 warn("rename");
114 if (opts & O_VERBOSE && yes)
115 printf("%s -> %s\n", f, new);
118 void
119 usage(void)
121 fputs("usage: rene [-ailnov] from to file ...\n", stderr);
122 exit(EXIT_FAILURE);
125 int
126 main(int argc, char *argv[])
128 char *from, *to;
130 #ifdef __OpenBSD__
131 if (pledge("stdio cpath rpath", NULL) == -1)
132 err(1, "pledge");
133 #endif
135 int c;
136 while ((c = getopt(argc, argv, "ailnov")) != -1) {
137 switch (c) {
138 case 'a':
139 opts |= O_REPLACEALL;
140 break;
141 case 'i':
142 opts |= O_INTERACTIVE;
143 break;
144 case 'l':
145 opts |= O_REPLACELAST;
146 break;
147 case 'n':
148 opts |= O_NOACT;
149 break;
150 case 'o':
151 opts |= O_NOOVERRIDE;
152 break;
153 case 'v':
154 opts |= O_VERBOSE;
155 break;
156 default:
157 usage();
160 argc -= optind;
161 argv += optind;
163 if (argc < 3)
164 usage();
165 from = argv[0];
166 to = argv[1];
167 for (int i = 2; i < argc; i++)
168 ren(from, to, argv[i]);
169 return 0;