util.c revision 1.2 1 #ifndef lint
2 static char rcsid[] = "$Id: util.c,v 1.2 1993/08/02 17:55:23 mycroft Exp $";
3 #endif /* not lint */
4
5 #include "EXTERN.h"
6 #include "common.h"
7 #include "INTERN.h"
8 #include "util.h"
9 #include "backupfile.h"
10
11 void my_exit();
12
13 static char *
14 private_strerror (errnum)
15 int errnum;
16 {
17 extern char *sys_errlist[];
18 extern int sys_nerr;
19
20 if (errnum > 0 && errnum <= sys_nerr)
21 return sys_errlist[errnum];
22 return "Unknown system error";
23 }
24 #define strerror private_strerror
25
26 /* Rename a file, copying it if necessary. */
27
28 int
29 move_file(from,to)
30 char *from, *to;
31 {
32 char bakname[512];
33 Reg1 char *s;
34 Reg2 int i;
35 Reg3 int fromfd;
36
37 /* to stdout? */
38
39 if (strEQ(to, "-")) {
40 #ifdef DEBUGGING
41 if (debug & 4)
42 say2("Moving %s to stdout.\n", from);
43 #endif
44 fromfd = open(from, 0);
45 if (fromfd < 0)
46 pfatal2("internal error, can't reopen %s", from);
47 while ((i=read(fromfd, buf, sizeof buf)) > 0)
48 if (write(1, buf, i) != 1)
49 pfatal1("write failed");
50 Close(fromfd);
51 return 0;
52 }
53
54 if (origprae) {
55 Strcpy(bakname, origprae);
56 Strcat(bakname, to);
57 } else {
58 #ifndef NODIR
59 char *backupname = find_backup_file_name(to);
60 if (backupname == (char *) 0)
61 fatal1("out of memory\n");
62 Strcpy(bakname, backupname);
63 free(backupname);
64 #else /* NODIR */
65 Strcpy(bakname, to);
66 Strcat(bakname, simple_backup_suffix);
67 #endif /* NODIR */
68 }
69
70 if (stat(to, &filestat) == 0) { /* output file exists */
71 dev_t to_device = filestat.st_dev;
72 ino_t to_inode = filestat.st_ino;
73 char *simplename = bakname;
74
75 for (s=bakname; *s; s++) {
76 if (*s == '/')
77 simplename = s+1;
78 }
79 /* Find a backup name that is not the same file.
80 Change the first lowercase char into uppercase;
81 if that isn't sufficient, chop off the first char and try again. */
82 while (stat(bakname, &filestat) == 0 &&
83 to_device == filestat.st_dev && to_inode == filestat.st_ino) {
84 /* Skip initial non-lowercase chars. */
85 for (s=simplename; *s && !islower(*s); s++) ;
86 if (*s)
87 *s = toupper(*s);
88 else
89 Strcpy(simplename, simplename+1);
90 }
91 while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
92 #ifdef DEBUGGING
93 if (debug & 4)
94 say3("Moving %s to %s.\n", to, bakname);
95 #endif
96 if (link(to, bakname) < 0) {
97 /* Maybe `to' is a symlink into a different file system.
98 Copying replaces the symlink with a file; using rename
99 would be better. */
100 Reg4 int tofd;
101 Reg5 int bakfd;
102
103 bakfd = creat(bakname, 0666);
104 if (bakfd < 0) {
105 say4("Can't backup %s, output is in %s: %s\n", to, from,
106 strerror(errno));
107 return -1;
108 }
109 tofd = open(to, 0);
110 if (tofd < 0)
111 pfatal2("internal error, can't open %s", to);
112 while ((i=read(tofd, buf, sizeof buf)) > 0)
113 if (write(bakfd, buf, i) != i)
114 pfatal1("write failed");
115 Close(tofd);
116 Close(bakfd);
117 }
118 while (unlink(to) >= 0) ;
119 }
120 #ifdef DEBUGGING
121 if (debug & 4)
122 say3("Moving %s to %s.\n", from, to);
123 #endif
124 if (link(from, to) < 0) { /* different file system? */
125 Reg4 int tofd;
126
127 tofd = creat(to, 0666);
128 if (tofd < 0) {
129 say4("Can't create %s, output is in %s: %s\n",
130 to, from, strerror(errno));
131 return -1;
132 }
133 fromfd = open(from, 0);
134 if (fromfd < 0)
135 pfatal2("internal error, can't reopen %s", from);
136 while ((i=read(fromfd, buf, sizeof buf)) > 0)
137 if (write(tofd, buf, i) != i)
138 pfatal1("write failed");
139 Close(fromfd);
140 Close(tofd);
141 }
142 Unlink(from);
143 return 0;
144 }
145
146 /* Copy a file. */
147
148 void
149 copy_file(from,to)
150 char *from, *to;
151 {
152 Reg3 int tofd;
153 Reg2 int fromfd;
154 Reg1 int i;
155
156 tofd = creat(to, 0666);
157 if (tofd < 0)
158 pfatal2("can't create %s", to);
159 fromfd = open(from, 0);
160 if (fromfd < 0)
161 pfatal2("internal error, can't reopen %s", from);
162 while ((i=read(fromfd, buf, sizeof buf)) > 0)
163 if (write(tofd, buf, i) != i)
164 pfatal2("write to %s failed", to);
165 Close(fromfd);
166 Close(tofd);
167 }
168
169 /* Allocate a unique area for a string. */
170
171 char *
172 savestr(s)
173 Reg1 char *s;
174 {
175 Reg3 char *rv;
176 Reg2 char *t;
177
178 if (!s)
179 s = "Oops";
180 t = s;
181 while (*t++);
182 rv = malloc((MEM) (t - s));
183 if (rv == Nullch) {
184 if (using_plan_a)
185 out_of_mem = TRUE;
186 else
187 fatal1("out of memory\n");
188 }
189 else {
190 t = rv;
191 while (*t++ = *s++);
192 }
193 return rv;
194 }
195
196 #if defined(lint) && defined(CANVARARG)
197
198 /*VARARGS ARGSUSED*/
199 say(pat) char *pat; { ; }
200 /*VARARGS ARGSUSED*/
201 fatal(pat) char *pat; { ; }
202 /*VARARGS ARGSUSED*/
203 pfatal(pat) char *pat; { ; }
204 /*VARARGS ARGSUSED*/
205 ask(pat) char *pat; { ; }
206
207 #else
208
209 /* Vanilla terminal output (buffered). */
210
211 void
212 say(pat,arg1,arg2,arg3)
213 char *pat;
214 long arg1,arg2,arg3;
215 {
216 fprintf(stderr, pat, arg1, arg2, arg3);
217 Fflush(stderr);
218 }
219
220 /* Terminal output, pun intended. */
221
222 void /* very void */
223 fatal(pat,arg1,arg2,arg3)
224 char *pat;
225 long arg1,arg2,arg3;
226 {
227 fprintf(stderr, "patch: **** ");
228 fprintf(stderr, pat, arg1, arg2, arg3);
229 my_exit(1);
230 }
231
232 /* Say something from patch, something from the system, then silence . . . */
233
234 void /* very void */
235 pfatal(pat,arg1,arg2,arg3)
236 char *pat;
237 long arg1,arg2,arg3;
238 {
239 int errnum = errno;
240
241 fprintf(stderr, "patch: **** ");
242 fprintf(stderr, pat, arg1, arg2, arg3);
243 fprintf(stderr, ": %s\n", strerror(errnum));
244 my_exit(1);
245 }
246
247 /* Get a response from the user, somehow or other. */
248
249 void
250 ask(pat,arg1,arg2,arg3)
251 char *pat;
252 long arg1,arg2,arg3;
253 {
254 int ttyfd;
255 int r;
256 bool tty2 = isatty(2);
257
258 Sprintf(buf, pat, arg1, arg2, arg3);
259 Fflush(stderr);
260 write(2, buf, strlen(buf));
261 if (tty2) { /* might be redirected to a file */
262 r = read(2, buf, sizeof buf);
263 }
264 else if (isatty(1)) { /* this may be new file output */
265 Fflush(stdout);
266 write(1, buf, strlen(buf));
267 r = read(1, buf, sizeof buf);
268 }
269 else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
270 /* might be deleted or unwriteable */
271 write(ttyfd, buf, strlen(buf));
272 r = read(ttyfd, buf, sizeof buf);
273 Close(ttyfd);
274 }
275 else if (isatty(0)) { /* this is probably patch input */
276 Fflush(stdin);
277 write(0, buf, strlen(buf));
278 r = read(0, buf, sizeof buf);
279 }
280 else { /* no terminal at all--default it */
281 buf[0] = '\n';
282 r = 1;
283 }
284 if (r <= 0)
285 buf[0] = 0;
286 else
287 buf[r] = '\0';
288 if (!tty2)
289 say1(buf);
290 }
291 #endif /* lint */
292
293 /* How to handle certain events when not in a critical region. */
294
295 void
296 set_signals(reset)
297 int reset;
298 {
299 #ifndef lint
300 #ifdef VOIDSIG
301 static void (*hupval)(),(*intval)();
302 #else
303 static int (*hupval)(),(*intval)();
304 #endif
305
306 if (!reset) {
307 hupval = signal(SIGHUP, SIG_IGN);
308 if (hupval != SIG_IGN)
309 #ifdef VOIDSIG
310 hupval = my_exit;
311 #else
312 hupval = (int(*)())my_exit;
313 #endif
314 intval = signal(SIGINT, SIG_IGN);
315 if (intval != SIG_IGN)
316 #ifdef VOIDSIG
317 intval = my_exit;
318 #else
319 intval = (int(*)())my_exit;
320 #endif
321 }
322 Signal(SIGHUP, hupval);
323 Signal(SIGINT, intval);
324 #endif
325 }
326
327 /* How to handle certain events when in a critical region. */
328
329 void
330 ignore_signals()
331 {
332 #ifndef lint
333 Signal(SIGHUP, SIG_IGN);
334 Signal(SIGINT, SIG_IGN);
335 #endif
336 }
337
338 /* Make sure we'll have the directories to create a file.
339 If `striplast' is TRUE, ignore the last element of `filename'. */
340
341 void
342 makedirs(filename,striplast)
343 Reg1 char *filename;
344 bool striplast;
345 {
346 char tmpbuf[256];
347 Reg2 char *s = tmpbuf;
348 char *dirv[20]; /* Point to the NULs between elements. */
349 Reg3 int i;
350 Reg4 int dirvp = 0; /* Number of finished entries in dirv. */
351
352 /* Copy `filename' into `tmpbuf' with a NUL instead of a slash
353 between the directories. */
354 while (*filename) {
355 if (*filename == '/') {
356 filename++;
357 dirv[dirvp++] = s;
358 *s++ = '\0';
359 }
360 else {
361 *s++ = *filename++;
362 }
363 }
364 *s = '\0';
365 dirv[dirvp] = s;
366 if (striplast)
367 dirvp--;
368 if (dirvp < 0)
369 return;
370
371 strcpy(buf, "mkdir");
372 s = buf;
373 for (i=0; i<=dirvp; i++) {
374 struct stat sbuf;
375
376 if (stat(tmpbuf, &sbuf) && errno == ENOENT) {
377 while (*s) s++;
378 *s++ = ' ';
379 strcpy(s, tmpbuf);
380 }
381 *dirv[i] = '/';
382 }
383 if (s != buf)
384 system(buf);
385 }
386
387 /* Make filenames more reasonable. */
388
389 char *
390 fetchname(at,strip_leading,assume_exists)
391 char *at;
392 int strip_leading;
393 int assume_exists;
394 {
395 char *fullname;
396 char *name;
397 Reg1 char *t;
398 char tmpbuf[200];
399 int sleading = strip_leading;
400
401 if (!at)
402 return Nullch;
403 while (isspace(*at))
404 at++;
405 #ifdef DEBUGGING
406 if (debug & 128)
407 say4("fetchname %s %d %d\n",at,strip_leading,assume_exists);
408 #endif
409 if (strnEQ(at, "/dev/null", 9)) /* so files can be created by diffing */
410 return Nullch; /* against /dev/null. */
411 name = fullname = t = savestr(at);
412
413 /* Strip off up to `sleading' leading slashes and null terminate. */
414 for (; *t && !isspace(*t); t++)
415 if (*t == '/')
416 if (--sleading >= 0)
417 name = t+1;
418 *t = '\0';
419
420 /* If no -p option was given (957 is the default value!),
421 we were given a relative pathname,
422 and the leading directories that we just stripped off all exist,
423 put them back on. */
424 if (strip_leading == 957 && name != fullname && *fullname != '/') {
425 name[-1] = '\0';
426 if (stat(fullname, &filestat) == 0 && S_ISDIR (filestat.st_mode)) {
427 name[-1] = '/';
428 name=fullname;
429 }
430 }
431
432 name = savestr(name);
433 free(fullname);
434
435 if (stat(name, &filestat) && !assume_exists) {
436 char *filebase = basename(name);
437 int pathlen = filebase - name;
438
439 /* Put any leading path into `tmpbuf'. */
440 strncpy(tmpbuf, name, pathlen);
441
442 #define try(f, a1, a2) (Sprintf(tmpbuf + pathlen, f, a1, a2), stat(tmpbuf, &filestat) == 0)
443 if ( try("RCS/%s%s", filebase, RCSSUFFIX)
444 || try("RCS/%s" , filebase, 0)
445 || try( "%s%s", filebase, RCSSUFFIX)
446 || try("SCCS/%s%s", SCCSPREFIX, filebase)
447 || try( "%s%s", SCCSPREFIX, filebase))
448 return name;
449 free(name);
450 name = Nullch;
451 }
452
453 return name;
454 }
455