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