Commit | Line | Data |
---|---|---|
8c4ebc23 JH |
1 | /* Supporting routines which may sometimes be missing. |
2 | Copyright (C) 1988, 1992 Free Software Foundation | |
3 | ||
4 | This file is part of GNU Tar. | |
5 | ||
6 | GNU Tar is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU Tar is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU Tar; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | #include <stdio.h> | |
21 | #include <sys/types.h> | |
22 | #include <signal.h> | |
23 | #include <errno.h> | |
24 | #ifndef STDC_HEADERS | |
25 | extern int errno; | |
26 | #endif | |
27 | ||
28 | #ifdef BSD42 | |
29 | #include <sys/file.h> | |
30 | #else | |
31 | #ifndef V7 | |
32 | #include <fcntl.h> | |
33 | #endif | |
34 | #endif | |
35 | ||
36 | #include "tar.h" | |
37 | #include "port.h" | |
38 | ||
39 | extern long baserec; | |
40 | ||
41 | /* All machine-dependent #ifdefs should appear here, instead of | |
42 | being scattered through the file. For UN*X systems, it is better to | |
43 | figure out what is needed in the configure script, for most of the | |
44 | features. */ | |
45 | ||
46 | #ifdef __MSDOS__ | |
47 | char TTY_NAME[] = "con"; | |
48 | #define HAVE_STRSTR | |
49 | #define HAVE_RENAME | |
50 | #define HAVE_MKDIR | |
51 | #else | |
52 | char TTY_NAME[] = "/dev/tty"; | |
53 | #endif | |
54 | ||
55 | /* End of system-dependent #ifdefs */ | |
56 | ||
57 | ||
58 | #ifndef HAVE_VALLOC | |
59 | /* | |
60 | * valloc() does a malloc() on a page boundary. On some systems, | |
61 | * this can make large block I/O more efficient. | |
62 | */ | |
63 | char * | |
64 | valloc (size) | |
65 | unsigned size; | |
66 | { | |
67 | return (malloc (size)); | |
68 | } | |
69 | ||
70 | #endif /* !HAVE_VALLOC */ | |
71 | ||
72 | #ifndef HAVE_MKDIR | |
73 | /* | |
74 | * Written by Robert Rother, Mariah Corporation, August 1985. | |
75 | * | |
76 | * If you want it, it's yours. All I ask in return is that if you | |
77 | * figure out how to do this in a Bourne Shell script you send me | |
78 | * a copy. | |
79 | * sdcsvax!rmr or rmr@uscd | |
80 | * | |
81 | * Severely hacked over by John Gilmore to make a 4.2BSD compatible | |
82 | * subroutine. 11Mar86; hoptoad!gnu | |
83 | * | |
84 | * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir, | |
85 | * subroutine didn't return EEXIST. It does now. | |
86 | */ | |
87 | ||
88 | /* | |
89 | * Make a directory. | |
90 | */ | |
91 | int | |
92 | mkdir (dpath, dmode) | |
93 | char *dpath; | |
94 | int dmode; | |
95 | { | |
96 | int cpid, status; | |
97 | struct stat statbuf; | |
98 | ||
99 | if (stat (dpath, &statbuf) == 0) | |
100 | { | |
101 | errno = EEXIST; /* Stat worked, so it already exists */ | |
102 | return -1; | |
103 | } | |
104 | ||
105 | /* If stat fails for a reason other than non-existence, return error */ | |
106 | if (errno != ENOENT) | |
107 | return -1; | |
108 | ||
109 | switch (cpid = fork ()) | |
110 | { | |
111 | ||
112 | case -1: /* Error in fork() */ | |
113 | return (-1); /* Errno is set already */ | |
114 | ||
115 | case 0: /* Child process */ | |
116 | /* | |
117 | * Cheap hack to set mode of new directory. Since this | |
118 | * child process is going away anyway, we zap its umask. | |
119 | * FIXME, this won't suffice to set SUID, SGID, etc. on this | |
120 | * directory. Does anybody care? | |
121 | */ | |
122 | status = umask (0); /* Get current umask */ | |
123 | status = umask (status | (0777 & ~dmode)); /* Set for mkdir */ | |
124 | execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); | |
125 | _exit (-1); /* Can't exec /bin/mkdir */ | |
126 | ||
127 | default: /* Parent process */ | |
128 | while (cpid != wait (&status)); /* Wait for kid to finish */ | |
129 | } | |
130 | ||
131 | if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) | |
132 | { | |
133 | errno = EIO; /* We don't know why, but */ | |
134 | return -1; /* /bin/mkdir failed */ | |
135 | } | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
140 | int | |
141 | rmdir (dpath) | |
142 | char *dpath; | |
143 | { | |
144 | int cpid, status; | |
145 | struct stat statbuf; | |
146 | ||
147 | if (stat (dpath, &statbuf) != 0) | |
148 | { | |
149 | /* Stat just set errno. We don't have to */ | |
150 | return -1; | |
151 | } | |
152 | ||
153 | switch (cpid = fork ()) | |
154 | { | |
155 | ||
156 | case -1: /* Error in fork() */ | |
157 | return (-1); /* Errno is set already */ | |
158 | ||
159 | case 0: /* Child process */ | |
160 | execl ("/bin/rmdir", "rmdir", dpath, (char *) 0); | |
161 | _exit (-1); /* Can't exec /bin/mkdir */ | |
162 | ||
163 | default: /* Parent process */ | |
164 | while (cpid != wait (&status)); /* Wait for kid to finish */ | |
165 | } | |
166 | ||
167 | if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) | |
168 | { | |
169 | errno = EIO; /* We don't know why, but */ | |
170 | return -1; /* /bin/mkdir failed */ | |
171 | } | |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
176 | #endif /* !HAVE_MKDIR */ | |
177 | ||
178 | #ifndef HAVE_RENAME | |
179 | /* Rename file FROM to file TO. | |
180 | Return 0 if successful, -1 if not. */ | |
181 | ||
182 | int | |
183 | rename (from, to) | |
184 | char *from; | |
185 | char *to; | |
186 | { | |
187 | struct stat from_stats; | |
188 | ||
189 | if (stat (from, &from_stats)) | |
190 | return -1; | |
191 | ||
192 | if (unlink (to) && errno != ENOENT) | |
193 | return -1; | |
194 | ||
195 | if (link (from, to)) | |
196 | return -1; | |
197 | ||
198 | if (unlink (from) && errno != ENOENT) | |
199 | { | |
200 | unlink (to); | |
201 | return -1; | |
202 | } | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
207 | #endif /* !HAVE_RENAME */ | |
208 | ||
209 | #ifdef minix | |
210 | /* Minix has bcopy but not bzero, and no memset. Thanks, Andy. */ | |
211 | void | |
212 | bzero (s1, n) | |
213 | register char *s1; | |
214 | register int n; | |
215 | { | |
216 | while (n--) | |
217 | *s1++ = '\0'; | |
218 | } | |
219 | ||
220 | /* It also has no bcmp() */ | |
221 | int | |
222 | bcmp (s1, s2, n) | |
223 | register char *s1, *s2; | |
224 | register int n; | |
225 | { | |
226 | for (; n--; ++s1, ++s2) | |
227 | { | |
228 | if (*s1 != *s2) | |
229 | return *s1 - *s2; | |
230 | } | |
231 | return 0; | |
232 | } | |
233 | ||
234 | /* | |
235 | * Groan, Minix doesn't have execlp either! | |
236 | * | |
237 | * execlp(file,arg0,arg1...argn,(char *)NULL) | |
238 | * exec a program, automatically searching for the program through | |
239 | * all the directories on the PATH. | |
240 | * | |
241 | * This version is naive about variable argument lists, it assumes | |
242 | * a straightforward C calling sequence. If your system has odd stacks | |
243 | * *and* doesn't have execlp, YOU get to fix it. | |
244 | */ | |
245 | int | |
246 | execlp (filename, arg0) | |
247 | char *filename, *arg0; | |
248 | { | |
249 | register char *p, *path; | |
250 | register char *fnbuffer; | |
251 | char **argstart = &arg0; | |
252 | struct stat statbuf; | |
253 | extern char **environ; | |
254 | ||
255 | if ((p = getenv ("PATH")) == NULL) | |
256 | { | |
257 | /* couldn't find path variable -- try to exec given filename */ | |
258 | return execve (filename, argstart, environ); | |
259 | } | |
260 | ||
261 | /* | |
262 | * make a place to build the filename. We malloc larger than we | |
263 | * need, but we know it will fit in this. | |
264 | */ | |
265 | fnbuffer = malloc (strlen (p) + 1 + strlen (filename)); | |
266 | if (fnbuffer == NULL) | |
267 | { | |
268 | errno = ENOMEM; | |
269 | return -1; | |
270 | } | |
271 | ||
272 | /* | |
273 | * try each component of the path to see if the file's there | |
274 | * and executable. | |
275 | */ | |
276 | for (path = p; path; path = p) | |
277 | { | |
278 | /* construct full path name to try */ | |
279 | if ((p = index (path, ':')) == NULL) | |
280 | { | |
281 | strcpy (fnbuffer, path); | |
282 | } | |
283 | else | |
284 | { | |
285 | strncpy (fnbuffer, path, p - path); | |
286 | fnbuffer[p - path] = '\0'; | |
287 | p++; /* Skip : for next time */ | |
288 | } | |
289 | if (strlen (fnbuffer) != 0) | |
290 | strcat (fnbuffer, "/"); | |
291 | strcat (fnbuffer, filename); | |
292 | ||
293 | /* check to see if file is there and is a normal file */ | |
294 | if (stat (fnbuffer, &statbuf) < 0) | |
295 | { | |
296 | if (errno == ENOENT) | |
297 | continue; /* file not there,keep on looking */ | |
298 | else | |
299 | goto fail; /* failed for some reason, return */ | |
300 | } | |
301 | if (!S_ISREG (statbuf.st_mode)) | |
302 | continue; | |
303 | ||
304 | if (execve (fnbuffer, argstart, environ) < 0 | |
305 | && errno != ENOENT | |
306 | && errno != ENOEXEC) | |
307 | { | |
308 | /* failed, for some other reason besides "file | |
309 | * not found" or "not a.out format" | |
310 | */ | |
311 | goto fail; | |
312 | } | |
313 | ||
314 | /* | |
315 | * If we got error ENOEXEC, the file is executable but is | |
316 | * not an object file. Try to execute it as a shell script, | |
317 | * returning error if we can't execute /bin/sh. | |
318 | * | |
319 | * FIXME, this code is broken in several ways. Shell | |
320 | * scripts should not in general be executed by the user's | |
321 | * SHELL variable program. On more mature systems, the | |
322 | * script can specify with #!/bin/whatever. Also, this | |
323 | * code clobbers argstart[-1] if the exec of the shell | |
324 | * fails. | |
325 | */ | |
326 | if (errno == ENOEXEC) | |
327 | { | |
328 | char *shell; | |
329 | ||
330 | /* Try to execute command "sh arg0 arg1 ..." */ | |
331 | if ((shell = getenv ("SHELL")) == NULL) | |
332 | shell = "/bin/sh"; | |
333 | argstart[-1] = shell; | |
334 | argstart[0] = fnbuffer; | |
335 | execve (shell, &argstart[-1], environ); | |
336 | goto fail; /* Exec didn't work */ | |
337 | } | |
338 | ||
339 | /* | |
340 | * If we succeeded, the execve() doesn't return, so we | |
341 | * can only be here is if the file hasn't been found yet. | |
342 | * Try the next place on the path. | |
343 | */ | |
344 | } | |
345 | ||
346 | /* all attempts failed to locate the file. Give up. */ | |
347 | errno = ENOENT; | |
348 | ||
349 | fail: | |
350 | free (fnbuffer); | |
351 | return -1; | |
352 | } | |
353 | ||
354 | #endif /* minix */ | |
355 | ||
356 | ||
357 | #ifdef EMUL_OPEN3 | |
358 | #include "open3.h" | |
359 | /* | |
360 | * open3 -- routine to emulate the 3-argument open system | |
361 | * call that is present in most modern Unix systems. | |
362 | * This version attempts to support all the flag bits except for O_NDELAY | |
363 | * and O_APPEND, which are silently ignored. The emulation is not as efficient | |
364 | * as the real thing (at worst, 4 system calls instead of one), but there's | |
365 | * not much I can do about that. | |
366 | * | |
367 | * Written 6/10/87 by rmtodd@uokmax | |
368 | * | |
369 | * open3(path, flag, mode) | |
370 | * Attempts to open the file specified by | |
371 | * the given pathname. The following flag bits (#defined in tar.h) | |
372 | * specify options to the routine: | |
373 | * O_RDONLY file open for read only | |
374 | * O_WRONLY file open for write only | |
375 | * O_RDWR file open for both read & write | |
376 | * (Needless to say, you should only specify one of the above). | |
377 | * O_CREAT file is created with specified mode if it needs to be. | |
378 | * O_TRUNC if file exists, it is truncated to 0 bytes | |
379 | * O_EXCL used with O_CREAT--routine returns error if file exists | |
380 | * Function returns file descriptor if successful, -1 and errno if not. | |
381 | */ | |
382 | ||
383 | /* | |
384 | * array to give arguments to access for various modes | |
385 | * FIXME, this table depends on the specific integer values of O_XXX, | |
386 | * and also contains integers (args to 'access') that should be #define's. | |
387 | */ | |
388 | static int modes[] = | |
389 | { | |
390 | 04, /* O_RDONLY */ | |
391 | 02, /* O_WRONLY */ | |
392 | 06, /* O_RDWR */ | |
393 | 06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */ | |
394 | }; | |
395 | ||
396 | /* Shut off the automatic emulation of open(), we'll need it. */ | |
397 | #undef open | |
398 | ||
399 | int | |
400 | open3 (path, flags, mode) | |
401 | char *path; | |
402 | int flags, mode; | |
403 | { | |
404 | int exists = 1; | |
405 | int call_creat = 0; | |
406 | int fd; | |
407 | /* | |
408 | * We actually do the work by calling the open() or creat() system | |
409 | * call, depending on the flags. Call_creat is true if we will use | |
410 | * creat(), false if we will use open(). | |
411 | */ | |
412 | ||
413 | /* | |
414 | * See if the file exists and is accessible in the requested mode. | |
415 | * | |
416 | * Strictly speaking we shouldn't be using access, since access checks | |
417 | * against real uid, and the open call should check against euid. | |
418 | * Most cases real uid == euid, so it won't matter. FIXME. | |
419 | * FIXME, the construction "flags & 3" and the modes table depends | |
420 | * on the specific integer values of the O_XXX #define's. Foo! | |
421 | */ | |
422 | if (access (path, modes[flags & 3]) < 0) | |
423 | { | |
424 | if (errno == ENOENT) | |
425 | { | |
426 | /* the file does not exist */ | |
427 | exists = 0; | |
428 | } | |
429 | else | |
430 | { | |
431 | /* probably permission violation */ | |
432 | if (flags & O_EXCL) | |
433 | { | |
434 | /* Oops, the file exists, we didn't want it. */ | |
435 | /* No matter what the error, claim EEXIST. */ | |
436 | errno = EEXIST; | |
437 | } | |
438 | return -1; | |
439 | } | |
440 | } | |
441 | ||
442 | /* if we have the O_CREAT bit set, check for O_EXCL */ | |
443 | if (flags & O_CREAT) | |
444 | { | |
445 | if ((flags & O_EXCL) && exists) | |
446 | { | |
447 | /* Oops, the file exists and we didn't want it to. */ | |
448 | errno = EEXIST; | |
449 | return -1; | |
450 | } | |
451 | /* | |
452 | * If the file doesn't exist, be sure to call creat() so that | |
453 | * it will be created with the proper mode. | |
454 | */ | |
455 | if (!exists) | |
456 | call_creat = 1; | |
457 | } | |
458 | else | |
459 | { | |
460 | /* If O_CREAT isn't set and the file doesn't exist, error. */ | |
461 | if (!exists) | |
462 | { | |
463 | errno = ENOENT; | |
464 | return -1; | |
465 | } | |
466 | } | |
467 | ||
468 | /* | |
469 | * If the O_TRUNC flag is set and the file exists, we want to call | |
470 | * creat() anyway, since creat() guarantees that the file will be | |
471 | * truncated and open()-for-writing doesn't. | |
472 | * (If the file doesn't exist, we're calling creat() anyway and the | |
473 | * file will be created with zero length.) | |
474 | */ | |
475 | if ((flags & O_TRUNC) && exists) | |
476 | call_creat = 1; | |
477 | /* actually do the call */ | |
478 | if (call_creat) | |
479 | { | |
480 | /* | |
481 | * call creat. May have to close and reopen the file if we | |
482 | * want O_RDONLY or O_RDWR access -- creat() only gives | |
483 | * O_WRONLY. | |
484 | */ | |
485 | fd = creat (path, mode); | |
486 | if (fd < 0 || (flags & O_WRONLY)) | |
487 | return fd; | |
488 | if (close (fd) < 0) | |
489 | return -1; | |
490 | /* Fall out to reopen the file we've created */ | |
491 | } | |
492 | ||
493 | /* | |
494 | * calling old open, we strip most of the new flags just in case. | |
495 | */ | |
496 | return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY)); | |
497 | } | |
498 | ||
499 | #endif /* EMUL_OPEN3 */ | |
500 | ||
501 | #ifndef HAVE_MKNOD | |
502 | #ifdef __MSDOS__ | |
503 | typedef int dev_t; | |
504 | #endif | |
505 | /* Fake mknod by complaining */ | |
506 | int | |
507 | mknod (path, mode, dev) | |
508 | char *path; | |
509 | unsigned short mode; | |
510 | dev_t dev; | |
511 | { | |
512 | int fd; | |
513 | ||
514 | errno = ENXIO; /* No such device or address */ | |
515 | return -1; /* Just give an error */ | |
516 | } | |
517 | ||
518 | /* Fake links by copying */ | |
519 | int | |
520 | link (path1, path2) | |
521 | char *path1; | |
522 | char *path2; | |
523 | { | |
524 | char buf[256]; | |
525 | int ifd, ofd; | |
526 | int nrbytes; | |
527 | int nwbytes; | |
528 | ||
529 | fprintf (stderr, "%s: %s: cannot link to %s, copying instead\n", | |
530 | tar, path1, path2); | |
531 | if ((ifd = open (path1, O_RDONLY | O_BINARY)) < 0) | |
532 | return -1; | |
533 | if ((ofd = creat (path2, 0666)) < 0) | |
534 | return -1; | |
535 | setmode (ofd, O_BINARY); | |
536 | while ((nrbytes = read (ifd, buf, sizeof (buf))) > 0) | |
537 | { | |
538 | if ((nwbytes = write (ofd, buf, nrbytes)) != nrbytes) | |
539 | { | |
540 | nrbytes = -1; | |
541 | break; | |
542 | } | |
543 | } | |
544 | /* Note use of "|" rather than "||" below: we want to close | |
545 | * the files even if an error occurs. | |
546 | */ | |
547 | if ((nrbytes < 0) | (0 != close (ifd)) | (0 != close (ofd))) | |
548 | { | |
549 | unlink (path2); | |
550 | return -1; | |
551 | } | |
552 | return 0; | |
553 | } | |
554 | ||
555 | /* everyone owns everything on MS-DOS (or is it no one owns anything?) */ | |
556 | int | |
557 | chown (path, uid, gid) | |
558 | char *path; | |
559 | int uid; | |
560 | int gid; | |
561 | { | |
562 | return 0; | |
563 | } | |
564 | ||
565 | int | |
566 | geteuid () | |
567 | { | |
568 | return 0; | |
569 | } | |
570 | ||
571 | #endif /* !HAVE_MKNOD */ | |
572 | ||
573 | #ifdef __TURBOC__ | |
574 | #include <time.h> | |
575 | #include <fcntl.h> | |
576 | #include <io.h> | |
577 | ||
578 | struct utimbuf | |
579 | { | |
580 | time_t actime; /* Access time. */ | |
581 | time_t modtime; /* Modification time. */ | |
582 | }; | |
583 | ||
584 | int | |
585 | utime (char *filename, struct utimbuf *utb) | |
586 | { | |
587 | struct tm *tm; | |
588 | struct ftime filetime; | |
589 | time_t when; | |
590 | int fd; | |
591 | int status; | |
592 | ||
593 | if (utb == 0) | |
594 | when = time (0); | |
595 | else | |
596 | when = utb->modtime; | |
597 | ||
598 | fd = _open (filename, O_RDWR); | |
599 | if (fd == -1) | |
600 | return -1; | |
601 | ||
602 | tm = localtime (&when); | |
603 | if (tm->tm_year < 80) | |
604 | filetime.ft_year = 0; | |
605 | else | |
606 | filetime.ft_year = tm->tm_year - 80; | |
607 | filetime.ft_month = tm->tm_mon + 1; | |
608 | filetime.ft_day = tm->tm_mday; | |
609 | if (tm->tm_hour < 0) | |
610 | filetime.ft_hour = 0; | |
611 | else | |
612 | filetime.ft_hour = tm->tm_hour; | |
613 | filetime.ft_min = tm->tm_min; | |
614 | filetime.ft_tsec = tm->tm_sec / 2; | |
615 | ||
616 | status = setftime (fd, &filetime); | |
617 | _close (fd); | |
618 | return status; | |
619 | } | |
620 | ||
621 | #endif /* __TURBOC__ */ | |
622 | ||
623 | /* Stash argv[0] here so panic will know what the program is called */ | |
624 | char *myname = 0; | |
625 | ||
626 | void | |
627 | panic (s) | |
628 | char *s; | |
629 | { | |
630 | if (myname) | |
631 | fprintf (stderr, "%s:", myname); | |
632 | fprintf (stderr, s); | |
633 | putc ('\n', stderr); | |
634 | exit (12); | |
635 | } | |
636 | ||
637 | ||
638 | PTR | |
639 | ck_malloc (size) | |
640 | size_t size; | |
641 | { | |
642 | PTR ret; | |
643 | ||
644 | if (!size) | |
645 | size++; | |
646 | ret = malloc (size); | |
647 | if (ret == 0) | |
648 | panic ("Couldn't allocate memory"); | |
649 | return ret; | |
650 | } | |
651 | ||
652 | /* Used by alloca.c and bison.simple. */ | |
653 | char * | |
654 | xmalloc (size) | |
655 | size_t size; | |
656 | { | |
657 | return (char *) ck_malloc (size); | |
658 | } | |
659 | ||
660 | PTR | |
661 | ck_realloc (ptr, size) | |
662 | PTR ptr; | |
663 | size_t size; | |
664 | { | |
665 | PTR ret; | |
666 | ||
667 | if (!ptr) | |
668 | ret = ck_malloc (size); | |
669 | else | |
670 | ret = realloc (ptr, size); | |
671 | if (ret == 0) | |
672 | panic ("Couldn't re-allocate memory"); | |
673 | return ret; | |
674 | } | |
675 | ||
676 | /* Implement a variable sized buffer of 'stuff'. We don't know what it is, | |
677 | nor do we care, as long as it doesn't mind being aligned on a char boundry. | |
678 | */ | |
679 | ||
680 | struct buffer | |
681 | { | |
682 | int allocated; | |
683 | int length; | |
684 | char *b; | |
685 | }; | |
686 | ||
687 | #define MIN_ALLOCATE 50 | |
688 | ||
689 | char * | |
690 | init_buffer () | |
691 | { | |
692 | struct buffer *b; | |
693 | ||
694 | b = (struct buffer *) ck_malloc (sizeof (struct buffer)); | |
695 | b->allocated = MIN_ALLOCATE; | |
696 | b->b = (char *) ck_malloc (MIN_ALLOCATE); | |
697 | b->length = 0; | |
698 | return (char *) b; | |
699 | } | |
700 | ||
701 | void | |
702 | flush_buffer (bb) | |
703 | char *bb; | |
704 | { | |
705 | struct buffer *b; | |
706 | ||
707 | b = (struct buffer *) bb; | |
708 | free (b->b); | |
709 | b->b = 0; | |
710 | b->allocated = 0; | |
711 | b->length = 0; | |
712 | free ((void *) b); | |
713 | } | |
714 | ||
715 | void | |
716 | add_buffer (bb, p, n) | |
717 | char *bb; | |
718 | char *p; | |
719 | int n; | |
720 | { | |
721 | struct buffer *b; | |
722 | ||
723 | b = (struct buffer *) bb; | |
724 | if (b->length + n > b->allocated) | |
725 | { | |
726 | b->allocated = b->length + n + MIN_ALLOCATE; | |
727 | b->b = (char *) ck_realloc (b->b, b->allocated); | |
728 | } | |
729 | bcopy (p, b->b + b->length, n); | |
730 | b->length += n; | |
731 | } | |
732 | ||
733 | char * | |
734 | get_buffer (bb) | |
735 | char *bb; | |
736 | { | |
737 | struct buffer *b; | |
738 | ||
739 | b = (struct buffer *) bb; | |
740 | return b->b; | |
741 | } | |
742 | ||
743 | char * | |
744 | merge_sort (list, n, off, cmp) | |
745 | char *list; | |
746 | int (*cmp) (); | |
747 | unsigned n; | |
748 | int off; | |
749 | { | |
750 | char *ret; | |
751 | ||
752 | char *alist, *blist; | |
753 | unsigned alength, blength; | |
754 | ||
755 | char *tptr; | |
756 | int tmp; | |
757 | char **prev; | |
758 | #define NEXTOF(ptr) (* ((char **)(((char *)(ptr))+off) ) ) | |
759 | if (n == 1) | |
760 | return list; | |
761 | if (n == 2) | |
762 | { | |
763 | if ((*cmp) (list, NEXTOF (list)) > 0) | |
764 | { | |
765 | ret = NEXTOF (list); | |
766 | NEXTOF (ret) = list; | |
767 | NEXTOF (list) = 0; | |
768 | return ret; | |
769 | } | |
770 | return list; | |
771 | } | |
772 | alist = list; | |
773 | alength = (n + 1) / 2; | |
774 | blength = n / 2; | |
775 | for (tptr = list, tmp = (n - 1) / 2; tmp; tptr = NEXTOF (tptr), tmp--) | |
776 | ; | |
777 | blist = NEXTOF (tptr); | |
778 | NEXTOF (tptr) = 0; | |
779 | ||
780 | alist = merge_sort (alist, alength, off, cmp); | |
781 | blist = merge_sort (blist, blength, off, cmp); | |
782 | prev = &ret; | |
783 | for (; alist && blist;) | |
784 | { | |
785 | if ((*cmp) (alist, blist) < 0) | |
786 | { | |
787 | tptr = NEXTOF (alist); | |
788 | *prev = alist; | |
789 | prev = &(NEXTOF (alist)); | |
790 | alist = tptr; | |
791 | } | |
792 | else | |
793 | { | |
794 | tptr = NEXTOF (blist); | |
795 | *prev = blist; | |
796 | prev = &(NEXTOF (blist)); | |
797 | blist = tptr; | |
798 | } | |
799 | } | |
800 | if (alist) | |
801 | *prev = alist; | |
802 | else | |
803 | *prev = blist; | |
804 | ||
805 | return ret; | |
806 | } | |
807 | ||
808 | void | |
809 | ck_close (fd) | |
810 | int fd; | |
811 | { | |
812 | if (close (fd) < 0) | |
813 | { | |
814 | msg_perror ("can't close a file #%d", fd); | |
815 | exit (EX_SYSTEM); | |
816 | } | |
817 | } | |
818 | ||
819 | #include <ctype.h> | |
820 | ||
821 | /* Quote_copy_string is like quote_string, but instead of modifying the | |
822 | string in place, it malloc-s a copy of the string, and returns that. | |
823 | If the string does not have to be quoted, it returns the NULL string. | |
824 | The allocated copy can, of course, be freed with free() after the | |
825 | caller is done with it. | |
826 | */ | |
827 | char * | |
828 | quote_copy_string (string) | |
829 | char *string; | |
830 | { | |
831 | char *from_here; | |
832 | char *to_there = 0; | |
833 | char *copy_buf = 0; | |
834 | int c; | |
835 | int copying = 0; | |
836 | ||
837 | from_here = string; | |
838 | while (*from_here) | |
839 | { | |
840 | c = *from_here++; | |
841 | if (c == '\\') | |
842 | { | |
843 | if (!copying) | |
844 | { | |
845 | int n; | |
846 | ||
847 | n = (from_here - string) - 1; | |
848 | copying++; | |
849 | copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4); | |
850 | if (!copy_buf) | |
851 | return 0; | |
852 | bcopy (string, copy_buf, n); | |
853 | to_there = copy_buf + n; | |
854 | } | |
855 | *to_there++ = '\\'; | |
856 | *to_there++ = '\\'; | |
857 | } | |
858 | else if (isprint (c)) | |
859 | { | |
860 | if (copying) | |
861 | *to_there++ = c; | |
862 | } | |
863 | else | |
864 | { | |
865 | if (!copying) | |
866 | { | |
867 | int n; | |
868 | ||
869 | n = (from_here - string) - 1; | |
870 | copying++; | |
871 | copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4); | |
872 | if (!copy_buf) | |
873 | return 0; | |
874 | bcopy (string, copy_buf, n); | |
875 | to_there = copy_buf + n; | |
876 | } | |
877 | *to_there++ = '\\'; | |
878 | if (c == '\n') | |
879 | *to_there++ = 'n'; | |
880 | else if (c == '\t') | |
881 | *to_there++ = 't'; | |
882 | else if (c == '\f') | |
883 | *to_there++ = 'f'; | |
884 | else if (c == '\b') | |
885 | *to_there++ = 'b'; | |
886 | else if (c == '\r') | |
887 | *to_there++ = 'r'; | |
888 | else if (c == '\177') | |
889 | *to_there++ = '?'; | |
890 | else | |
891 | { | |
892 | to_there[0] = (c >> 6) + '0'; | |
893 | to_there[1] = ((c >> 3) & 07) + '0'; | |
894 | to_there[2] = (c & 07) + '0'; | |
895 | to_there += 3; | |
896 | } | |
897 | } | |
898 | } | |
899 | if (copying) | |
900 | { | |
901 | *to_there = '\0'; | |
902 | return copy_buf; | |
903 | } | |
904 | return (char *) 0; | |
905 | } | |
906 | ||
907 | ||
908 | /* Un_quote_string takes a quoted c-string (like those produced by | |
909 | quote_string or quote_copy_string and turns it back into the | |
910 | un-quoted original. This is done in place. | |
911 | */ | |
912 | ||
913 | /* There is no un-quote-copy-string. Write it yourself */ | |
914 | ||
915 | char * | |
916 | un_quote_string (string) | |
917 | char *string; | |
918 | { | |
919 | char *ret; | |
920 | char *from_here; | |
921 | char *to_there; | |
922 | int tmp; | |
923 | ||
924 | ret = string; | |
925 | to_there = string; | |
926 | from_here = string; | |
927 | while (*from_here) | |
928 | { | |
929 | if (*from_here != '\\') | |
930 | { | |
931 | if (from_here != to_there) | |
932 | *to_there++ = *from_here++; | |
933 | else | |
934 | from_here++, to_there++; | |
935 | continue; | |
936 | } | |
937 | switch (*++from_here) | |
938 | { | |
939 | case '\\': | |
940 | *to_there++ = *from_here++; | |
941 | break; | |
942 | case 'n': | |
943 | *to_there++ = '\n'; | |
944 | from_here++; | |
945 | break; | |
946 | case 't': | |
947 | *to_there++ = '\t'; | |
948 | from_here++; | |
949 | break; | |
950 | case 'f': | |
951 | *to_there++ = '\f'; | |
952 | from_here++; | |
953 | break; | |
954 | case 'b': | |
955 | *to_there++ = '\b'; | |
956 | from_here++; | |
957 | break; | |
958 | case 'r': | |
959 | *to_there++ = '\r'; | |
960 | from_here++; | |
961 | break; | |
962 | case '?': | |
963 | *to_there++ = 0177; | |
964 | from_here++; | |
965 | break; | |
966 | case '0': | |
967 | case '1': | |
968 | case '2': | |
969 | case '3': | |
970 | case '4': | |
971 | case '5': | |
972 | case '6': | |
973 | case '7': | |
974 | tmp = *from_here - '0'; | |
975 | from_here++; | |
976 | if (*from_here < '0' || *from_here > '7') | |
977 | { | |
978 | *to_there++ = tmp; | |
979 | break; | |
980 | } | |
981 | tmp = tmp * 8 + *from_here - '0'; | |
982 | from_here++; | |
983 | if (*from_here < '0' || *from_here > '7') | |
984 | { | |
985 | *to_there++ = tmp; | |
986 | break; | |
987 | } | |
988 | tmp = tmp * 8 + *from_here - '0'; | |
989 | from_here++; | |
990 | *to_there = tmp; | |
991 | break; | |
992 | default: | |
993 | ret = 0; | |
994 | *to_there++ = '\\'; | |
995 | *to_there++ = *from_here++; | |
996 | break; | |
997 | } | |
998 | } | |
999 | if (*to_there) | |
1000 | *to_there++ = '\0'; | |
1001 | return ret; | |
1002 | } | |
1003 | ||
1004 | #ifndef __MSDOS__ | |
1005 | void | |
1006 | ck_pipe (pipes) | |
1007 | int *pipes; | |
1008 | { | |
1009 | if (pipe (pipes) < 0) | |
1010 | { | |
1011 | msg_perror ("can't open a pipe"); | |
1012 | exit (EX_SYSTEM); | |
1013 | } | |
1014 | } | |
1015 | #endif /* !__MSDOS__ */ | |
1016 | ||
1017 | #ifndef HAVE_STRSTR | |
1018 | /* | |
1019 | * strstr - find first occurrence of wanted in s | |
1020 | */ | |
1021 | ||
1022 | char * /* found string, or NULL if none */ | |
1023 | strstr (s, wanted) | |
1024 | char *s; | |
1025 | char *wanted; | |
1026 | { | |
1027 | register char *scan; | |
1028 | register size_t len; | |
1029 | register char firstc; | |
1030 | ||
1031 | if (*wanted == '\0') | |
1032 | return (char *) 0; | |
1033 | /* | |
1034 | * The odd placement of the two tests is so "" is findable. | |
1035 | * Also, we inline the first char for speed. | |
1036 | * The ++ on scan has been moved down for optimization. | |
1037 | */ | |
1038 | firstc = *wanted; | |
1039 | len = strlen (wanted); | |
1040 | for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;) | |
1041 | if (*scan++ == '\0') | |
1042 | return (char *) 0; | |
1043 | return scan; | |
1044 | } | |
1045 | ||
1046 | #endif /* !HAVE_STRSTR */ | |
1047 | ||
1048 | #ifndef HAVE_FTRUNCATE | |
1049 | ||
1050 | #ifdef F_CHSIZE | |
1051 | int | |
1052 | ftruncate (fd, length) | |
1053 | int fd; | |
1054 | off_t length; | |
1055 | { | |
1056 | return fcntl (fd, F_CHSIZE, length); | |
1057 | } | |
1058 | ||
1059 | #else /* !F_CHSIZE */ | |
1060 | #ifdef F_FREESP | |
1061 | /* code courtesy of William Kucharski, kucharsk@Solbourne.com */ | |
1062 | ||
1063 | int | |
1064 | ftruncate (fd, length) | |
1065 | int fd; /* file descriptor */ | |
1066 | off_t length; /* length to set file to */ | |
1067 | { | |
1068 | struct flock fl; | |
1069 | ||
1070 | fl.l_whence = 0; | |
1071 | fl.l_len = 0; | |
1072 | fl.l_start = length; | |
1073 | fl.l_type = F_WRLCK; /* write lock on file space */ | |
1074 | ||
1075 | /* | |
1076 | * This relies on the UNDOCUMENTED F_FREESP argument to | |
1077 | * fcntl(2), which truncates the file so that it ends at the | |
1078 | * position indicated by fl.l_start. | |
1079 | * | |
1080 | * Will minor miracles never cease? | |
1081 | */ | |
1082 | ||
1083 | if (fcntl (fd, F_FREESP, &fl) < 0) | |
1084 | return -1; | |
1085 | ||
1086 | return 0; | |
1087 | } | |
1088 | ||
1089 | #else /* !F_FREESP */ | |
1090 | ||
1091 | int | |
1092 | ftruncate (fd, length) | |
1093 | int fd; | |
1094 | off_t length; | |
1095 | { | |
1096 | errno = EIO; | |
1097 | return -1; | |
1098 | } | |
1099 | ||
1100 | #endif /* !F_FREESP */ | |
1101 | #endif /* !F_CHSIZE */ | |
1102 | #endif /* !HAVE_FTRUNCATE */ | |
1103 | ||
1104 | ||
1105 | extern FILE *msg_file; | |
1106 | ||
1107 | #if defined (HAVE_VPRINTF) && __STDC__ | |
1108 | #include <stdarg.h> | |
1109 | ||
1110 | void | |
1111 | msg (char *str,...) | |
1112 | { | |
1113 | va_list args; | |
1114 | ||
1115 | va_start (args, str); | |
1116 | fflush (msg_file); | |
1117 | fprintf (stderr, "%s: ", tar); | |
1118 | if (f_sayblock) | |
1119 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1120 | vfprintf (stderr, str, args); | |
1121 | va_end (args); | |
1122 | putc ('\n', stderr); | |
1123 | fflush (stderr); | |
1124 | } | |
1125 | ||
1126 | void | |
1127 | msg_perror (char *str,...) | |
1128 | { | |
1129 | va_list args; | |
1130 | int save_e; | |
1131 | ||
1132 | save_e = errno; | |
1133 | fflush (msg_file); | |
1134 | fprintf (stderr, "%s: ", tar); | |
1135 | if (f_sayblock) | |
1136 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1137 | va_start (args, str); | |
1138 | vfprintf (stderr, str, args); | |
1139 | va_end (args); | |
1140 | errno = save_e; | |
1141 | perror (" "); | |
1142 | fflush (stderr); | |
1143 | } | |
1144 | ||
1145 | #endif /* HAVE_VPRINTF and __STDC__ */ | |
1146 | ||
1147 | #if defined(HAVE_VPRINTF) && !__STDC__ | |
1148 | #include <varargs.h> | |
1149 | void | |
1150 | msg (str, va_alist) | |
1151 | char *str; | |
1152 | va_dcl | |
1153 | { | |
1154 | va_list args; | |
1155 | ||
1156 | fflush (msg_file); | |
1157 | fprintf (stderr, "%s: ", tar); | |
1158 | if (f_sayblock) | |
1159 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1160 | va_start (args); | |
1161 | vfprintf (stderr, str, args); | |
1162 | va_end (args); | |
1163 | putc ('\n', stderr); | |
1164 | fflush (stderr); | |
1165 | } | |
1166 | ||
1167 | void | |
1168 | msg_perror (str, va_alist) | |
1169 | char *str; | |
1170 | va_dcl | |
1171 | { | |
1172 | va_list args; | |
1173 | int save_e; | |
1174 | ||
1175 | save_e = errno; | |
1176 | fflush (msg_file); | |
1177 | fprintf (stderr, "%s: ", tar); | |
1178 | if (f_sayblock) | |
1179 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1180 | va_start (args); | |
1181 | vfprintf (stderr, str, args); | |
1182 | va_end (args); | |
1183 | errno = save_e; | |
1184 | perror (" "); | |
1185 | fflush (stderr); | |
1186 | } | |
1187 | ||
1188 | #endif /* HAVE_VPRINTF and not __STDC__ */ | |
1189 | ||
1190 | #if !defined(HAVE_VPRINTF) && defined(HAVE_DOPRNT) | |
1191 | void | |
1192 | msg (str, args) | |
1193 | char *str; | |
1194 | int args; | |
1195 | { | |
1196 | fflush (msg_file); | |
1197 | fprintf (stderr, "%s: ", tar); | |
1198 | if (f_sayblock) | |
1199 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1200 | _doprnt (str, &args, stderr); | |
1201 | putc ('\n', stderr); | |
1202 | fflush (stderr); | |
1203 | } | |
1204 | ||
1205 | void | |
1206 | msg_perror (str, args) | |
1207 | char *str; | |
1208 | int args; | |
1209 | { | |
1210 | int save_e; | |
1211 | ||
1212 | save_e = errno; | |
1213 | fflush (msg_file); | |
1214 | fprintf (stderr, "%s: ", tar); | |
1215 | if (f_sayblock) | |
1216 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1217 | _doprnt (str, &args, stderr); | |
1218 | errno = save_e; | |
1219 | perror (" "); | |
1220 | fflush (stderr); | |
1221 | } | |
1222 | ||
1223 | #endif /* !HAVE_VPRINTF and HAVE_DOPRNT */ | |
1224 | ||
1225 | #if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT) | |
1226 | void | |
1227 | msg (str, a1, a2, a3, a4, a5, a6) | |
1228 | char *str; | |
1229 | { | |
1230 | fflush (msg_file); | |
1231 | fprintf (stderr, "%s: ", tar); | |
1232 | if (f_sayblock) | |
1233 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1234 | fprintf (stderr, str, a1, a2, a3, a4, a5, a6); | |
1235 | putc ('\n', stderr); | |
1236 | fflush (stderr); | |
1237 | } | |
1238 | ||
1239 | void | |
1240 | msg_perror (str, a1, a2, a3, a4, a5, a6) | |
1241 | char *str; | |
1242 | { | |
1243 | int save_e; | |
1244 | ||
1245 | save_e = errno; | |
1246 | fflush (msg_file); | |
1247 | fprintf (stderr, "%s: ", tar); | |
1248 | if (f_sayblock) | |
1249 | fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); | |
1250 | fprintf (stderr, str, a1, a2, a3, a4, a5, a6); | |
1251 | fprintf (stderr, ": "); | |
1252 | errno = save_e; | |
1253 | perror (" "); | |
1254 | } | |
1255 | ||
1256 | #endif /* !HAVE_VPRINTF and !HAVE_DOPRNT */ |