aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/tar/port.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/tar/port.c')
-rw-r--r--gnu/usr.bin/tar/port.c1256
1 files changed, 1256 insertions, 0 deletions
diff --git a/gnu/usr.bin/tar/port.c b/gnu/usr.bin/tar/port.c
new file mode 100644
index 000000000000..10ec32ed7288
--- /dev/null
+++ b/gnu/usr.bin/tar/port.c
@@ -0,0 +1,1256 @@
+/* Supporting routines which may sometimes be missing.
+ Copyright (C) 1988, 1992 Free Software Foundation
+
+This file is part of GNU Tar.
+
+GNU Tar is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Tar is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Tar; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+#ifdef BSD42
+#include <sys/file.h>
+#else
+#ifndef V7
+#include <fcntl.h>
+#endif
+#endif
+
+#include "tar.h"
+#include "port.h"
+
+extern long baserec;
+
+/* All machine-dependent #ifdefs should appear here, instead of
+ being scattered through the file. For UN*X systems, it is better to
+ figure out what is needed in the configure script, for most of the
+ features. */
+
+#ifdef __MSDOS__
+char TTY_NAME[] = "con";
+#define HAVE_STRSTR
+#define HAVE_RENAME
+#define HAVE_MKDIR
+#else
+char TTY_NAME[] = "/dev/tty";
+#endif
+
+/* End of system-dependent #ifdefs */
+
+
+#ifndef HAVE_VALLOC
+/*
+ * valloc() does a malloc() on a page boundary. On some systems,
+ * this can make large block I/O more efficient.
+ */
+char *
+valloc (size)
+ unsigned size;
+{
+ return (malloc (size));
+}
+
+#endif /* !HAVE_VALLOC */
+
+#ifndef HAVE_MKDIR
+/*
+ * Written by Robert Rother, Mariah Corporation, August 1985.
+ *
+ * If you want it, it's yours. All I ask in return is that if you
+ * figure out how to do this in a Bourne Shell script you send me
+ * a copy.
+ * sdcsvax!rmr or rmr@uscd
+ *
+ * Severely hacked over by John Gilmore to make a 4.2BSD compatible
+ * subroutine. 11Mar86; hoptoad!gnu
+ *
+ * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
+ * subroutine didn't return EEXIST. It does now.
+ */
+
+/*
+ * Make a directory.
+ */
+int
+mkdir (dpath, dmode)
+ char *dpath;
+ int dmode;
+{
+ int cpid, status;
+ struct stat statbuf;
+
+ if (stat (dpath, &statbuf) == 0)
+ {
+ errno = EEXIST; /* Stat worked, so it already exists */
+ return -1;
+ }
+
+ /* If stat fails for a reason other than non-existence, return error */
+ if (errno != ENOENT)
+ return -1;
+
+ switch (cpid = fork ())
+ {
+
+ case -1: /* Error in fork() */
+ return (-1); /* Errno is set already */
+
+ case 0: /* Child process */
+ /*
+ * Cheap hack to set mode of new directory. Since this
+ * child process is going away anyway, we zap its umask.
+ * FIXME, this won't suffice to set SUID, SGID, etc. on this
+ * directory. Does anybody care?
+ */
+ status = umask (0); /* Get current umask */
+ status = umask (status | (0777 & ~dmode)); /* Set for mkdir */
+ execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
+ _exit (-1); /* Can't exec /bin/mkdir */
+
+ default: /* Parent process */
+ while (cpid != wait (&status)); /* Wait for kid to finish */
+ }
+
+ if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0)
+ {
+ errno = EIO; /* We don't know why, but */
+ return -1; /* /bin/mkdir failed */
+ }
+
+ return 0;
+}
+
+int
+rmdir (dpath)
+ char *dpath;
+{
+ int cpid, status;
+ struct stat statbuf;
+
+ if (stat (dpath, &statbuf) != 0)
+ {
+ /* Stat just set errno. We don't have to */
+ return -1;
+ }
+
+ switch (cpid = fork ())
+ {
+
+ case -1: /* Error in fork() */
+ return (-1); /* Errno is set already */
+
+ case 0: /* Child process */
+ execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
+ _exit (-1); /* Can't exec /bin/mkdir */
+
+ default: /* Parent process */
+ while (cpid != wait (&status)); /* Wait for kid to finish */
+ }
+
+ if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0)
+ {
+ errno = EIO; /* We don't know why, but */
+ return -1; /* /bin/mkdir failed */
+ }
+
+ return 0;
+}
+
+#endif /* !HAVE_MKDIR */
+
+#ifndef HAVE_RENAME
+/* Rename file FROM to file TO.
+ Return 0 if successful, -1 if not. */
+
+int
+rename (from, to)
+ char *from;
+ char *to;
+{
+ struct stat from_stats;
+
+ if (stat (from, &from_stats))
+ return -1;
+
+ if (unlink (to) && errno != ENOENT)
+ return -1;
+
+ if (link (from, to))
+ return -1;
+
+ if (unlink (from) && errno != ENOENT)
+ {
+ unlink (to);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* !HAVE_RENAME */
+
+#ifdef minix
+/* Minix has bcopy but not bzero, and no memset. Thanks, Andy. */
+void
+bzero (s1, n)
+ register char *s1;
+ register int n;
+{
+ while (n--)
+ *s1++ = '\0';
+}
+
+/* It also has no bcmp() */
+int
+bcmp (s1, s2, n)
+ register char *s1, *s2;
+ register int n;
+{
+ for (; n--; ++s1, ++s2)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ }
+ return 0;
+}
+
+/*
+ * Groan, Minix doesn't have execlp either!
+ *
+ * execlp(file,arg0,arg1...argn,(char *)NULL)
+ * exec a program, automatically searching for the program through
+ * all the directories on the PATH.
+ *
+ * This version is naive about variable argument lists, it assumes
+ * a straightforward C calling sequence. If your system has odd stacks
+ * *and* doesn't have execlp, YOU get to fix it.
+ */
+int
+execlp (filename, arg0)
+ char *filename, *arg0;
+{
+ register char *p, *path;
+ register char *fnbuffer;
+ char **argstart = &arg0;
+ struct stat statbuf;
+ extern char **environ;
+
+ if ((p = getenv ("PATH")) == NULL)
+ {
+ /* couldn't find path variable -- try to exec given filename */
+ return execve (filename, argstart, environ);
+ }
+
+ /*
+ * make a place to build the filename. We malloc larger than we
+ * need, but we know it will fit in this.
+ */
+ fnbuffer = malloc (strlen (p) + 1 + strlen (filename));
+ if (fnbuffer == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /*
+ * try each component of the path to see if the file's there
+ * and executable.
+ */
+ for (path = p; path; path = p)
+ {
+ /* construct full path name to try */
+ if ((p = index (path, ':')) == NULL)
+ {
+ strcpy (fnbuffer, path);
+ }
+ else
+ {
+ strncpy (fnbuffer, path, p - path);
+ fnbuffer[p - path] = '\0';
+ p++; /* Skip : for next time */
+ }
+ if (strlen (fnbuffer) != 0)
+ strcat (fnbuffer, "/");
+ strcat (fnbuffer, filename);
+
+ /* check to see if file is there and is a normal file */
+ if (stat (fnbuffer, &statbuf) < 0)
+ {
+ if (errno == ENOENT)
+ continue; /* file not there,keep on looking */
+ else
+ goto fail; /* failed for some reason, return */
+ }
+ if (!S_ISREG (statbuf.st_mode))
+ continue;
+
+ if (execve (fnbuffer, argstart, environ) < 0
+ && errno != ENOENT
+ && errno != ENOEXEC)
+ {
+ /* failed, for some other reason besides "file
+ * not found" or "not a.out format"
+ */
+ goto fail;
+ }
+
+ /*
+ * If we got error ENOEXEC, the file is executable but is
+ * not an object file. Try to execute it as a shell script,
+ * returning error if we can't execute /bin/sh.
+ *
+ * FIXME, this code is broken in several ways. Shell
+ * scripts should not in general be executed by the user's
+ * SHELL variable program. On more mature systems, the
+ * script can specify with #!/bin/whatever. Also, this
+ * code clobbers argstart[-1] if the exec of the shell
+ * fails.
+ */
+ if (errno == ENOEXEC)
+ {
+ char *shell;
+
+ /* Try to execute command "sh arg0 arg1 ..." */
+ if ((shell = getenv ("SHELL")) == NULL)
+ shell = "/bin/sh";
+ argstart[-1] = shell;
+ argstart[0] = fnbuffer;
+ execve (shell, &argstart[-1], environ);
+ goto fail; /* Exec didn't work */
+ }
+
+ /*
+ * If we succeeded, the execve() doesn't return, so we
+ * can only be here is if the file hasn't been found yet.
+ * Try the next place on the path.
+ */
+ }
+
+ /* all attempts failed to locate the file. Give up. */
+ errno = ENOENT;
+
+fail:
+ free (fnbuffer);
+ return -1;
+}
+
+#endif /* minix */
+
+
+#ifdef EMUL_OPEN3
+#include "open3.h"
+/*
+ * open3 -- routine to emulate the 3-argument open system
+ * call that is present in most modern Unix systems.
+ * This version attempts to support all the flag bits except for O_NDELAY
+ * and O_APPEND, which are silently ignored. The emulation is not as efficient
+ * as the real thing (at worst, 4 system calls instead of one), but there's
+ * not much I can do about that.
+ *
+ * Written 6/10/87 by rmtodd@uokmax
+ *
+ * open3(path, flag, mode)
+ * Attempts to open the file specified by
+ * the given pathname. The following flag bits (#defined in tar.h)
+ * specify options to the routine:
+ * O_RDONLY file open for read only
+ * O_WRONLY file open for write only
+ * O_RDWR file open for both read & write
+ * (Needless to say, you should only specify one of the above).
+ * O_CREAT file is created with specified mode if it needs to be.
+ * O_TRUNC if file exists, it is truncated to 0 bytes
+ * O_EXCL used with O_CREAT--routine returns error if file exists
+ * Function returns file descriptor if successful, -1 and errno if not.
+ */
+
+/*
+ * array to give arguments to access for various modes
+ * FIXME, this table depends on the specific integer values of O_XXX,
+ * and also contains integers (args to 'access') that should be #define's.
+ */
+static int modes[] =
+{
+ 04, /* O_RDONLY */
+ 02, /* O_WRONLY */
+ 06, /* O_RDWR */
+ 06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
+};
+
+/* Shut off the automatic emulation of open(), we'll need it. */
+#undef open
+
+int
+open3 (path, flags, mode)
+ char *path;
+ int flags, mode;
+{
+ int exists = 1;
+ int call_creat = 0;
+ int fd;
+ /*
+ * We actually do the work by calling the open() or creat() system
+ * call, depending on the flags. Call_creat is true if we will use
+ * creat(), false if we will use open().
+ */
+
+ /*
+ * See if the file exists and is accessible in the requested mode.
+ *
+ * Strictly speaking we shouldn't be using access, since access checks
+ * against real uid, and the open call should check against euid.
+ * Most cases real uid == euid, so it won't matter. FIXME.
+ * FIXME, the construction "flags & 3" and the modes table depends
+ * on the specific integer values of the O_XXX #define's. Foo!
+ */
+ if (access (path, modes[flags & 3]) < 0)
+ {
+ if (errno == ENOENT)
+ {
+ /* the file does not exist */
+ exists = 0;
+ }
+ else
+ {
+ /* probably permission violation */
+ if (flags & O_EXCL)
+ {
+ /* Oops, the file exists, we didn't want it. */
+ /* No matter what the error, claim EEXIST. */
+ errno = EEXIST;
+ }
+ return -1;
+ }
+ }
+
+ /* if we have the O_CREAT bit set, check for O_EXCL */
+ if (flags & O_CREAT)
+ {
+ if ((flags & O_EXCL) && exists)
+ {
+ /* Oops, the file exists and we didn't want it to. */
+ errno = EEXIST;
+ return -1;
+ }
+ /*
+ * If the file doesn't exist, be sure to call creat() so that
+ * it will be created with the proper mode.
+ */
+ if (!exists)
+ call_creat = 1;
+ }
+ else
+ {
+ /* If O_CREAT isn't set and the file doesn't exist, error. */
+ if (!exists)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ }
+
+ /*
+ * If the O_TRUNC flag is set and the file exists, we want to call
+ * creat() anyway, since creat() guarantees that the file will be
+ * truncated and open()-for-writing doesn't.
+ * (If the file doesn't exist, we're calling creat() anyway and the
+ * file will be created with zero length.)
+ */
+ if ((flags & O_TRUNC) && exists)
+ call_creat = 1;
+ /* actually do the call */
+ if (call_creat)
+ {
+ /*
+ * call creat. May have to close and reopen the file if we
+ * want O_RDONLY or O_RDWR access -- creat() only gives
+ * O_WRONLY.
+ */
+ fd = creat (path, mode);
+ if (fd < 0 || (flags & O_WRONLY))
+ return fd;
+ if (close (fd) < 0)
+ return -1;
+ /* Fall out to reopen the file we've created */
+ }
+
+ /*
+ * calling old open, we strip most of the new flags just in case.
+ */
+ return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY));
+}
+
+#endif /* EMUL_OPEN3 */
+
+#ifndef HAVE_MKNOD
+#ifdef __MSDOS__
+typedef int dev_t;
+#endif
+/* Fake mknod by complaining */
+int
+mknod (path, mode, dev)
+ char *path;
+ unsigned short mode;
+ dev_t dev;
+{
+ int fd;
+
+ errno = ENXIO; /* No such device or address */
+ return -1; /* Just give an error */
+}
+
+/* Fake links by copying */
+int
+link (path1, path2)
+ char *path1;
+ char *path2;
+{
+ char buf[256];
+ int ifd, ofd;
+ int nrbytes;
+ int nwbytes;
+
+ fprintf (stderr, "%s: %s: cannot link to %s, copying instead\n",
+ tar, path1, path2);
+ if ((ifd = open (path1, O_RDONLY | O_BINARY)) < 0)
+ return -1;
+ if ((ofd = creat (path2, 0666)) < 0)
+ return -1;
+ setmode (ofd, O_BINARY);
+ while ((nrbytes = read (ifd, buf, sizeof (buf))) > 0)
+ {
+ if ((nwbytes = write (ofd, buf, nrbytes)) != nrbytes)
+ {
+ nrbytes = -1;
+ break;
+ }
+ }
+ /* Note use of "|" rather than "||" below: we want to close
+ * the files even if an error occurs.
+ */
+ if ((nrbytes < 0) | (0 != close (ifd)) | (0 != close (ofd)))
+ {
+ unlink (path2);
+ return -1;
+ }
+ return 0;
+}
+
+/* everyone owns everything on MS-DOS (or is it no one owns anything?) */
+int
+chown (path, uid, gid)
+ char *path;
+ int uid;
+ int gid;
+{
+ return 0;
+}
+
+int
+geteuid ()
+{
+ return 0;
+}
+
+#endif /* !HAVE_MKNOD */
+
+#ifdef __TURBOC__
+#include <time.h>
+#include <fcntl.h>
+#include <io.h>
+
+struct utimbuf
+{
+ time_t actime; /* Access time. */
+ time_t modtime; /* Modification time. */
+};
+
+int
+utime (char *filename, struct utimbuf *utb)
+{
+ struct tm *tm;
+ struct ftime filetime;
+ time_t when;
+ int fd;
+ int status;
+
+ if (utb == 0)
+ when = time (0);
+ else
+ when = utb->modtime;
+
+ fd = _open (filename, O_RDWR);
+ if (fd == -1)
+ return -1;
+
+ tm = localtime (&when);
+ if (tm->tm_year < 80)
+ filetime.ft_year = 0;
+ else
+ filetime.ft_year = tm->tm_year - 80;
+ filetime.ft_month = tm->tm_mon + 1;
+ filetime.ft_day = tm->tm_mday;
+ if (tm->tm_hour < 0)
+ filetime.ft_hour = 0;
+ else
+ filetime.ft_hour = tm->tm_hour;
+ filetime.ft_min = tm->tm_min;
+ filetime.ft_tsec = tm->tm_sec / 2;
+
+ status = setftime (fd, &filetime);
+ _close (fd);
+ return status;
+}
+
+#endif /* __TURBOC__ */
+
+/* Stash argv[0] here so panic will know what the program is called */
+char *myname = 0;
+
+void
+panic (s)
+ char *s;
+{
+ if (myname)
+ fprintf (stderr, "%s:", myname);
+ fprintf (stderr, s);
+ putc ('\n', stderr);
+ exit (12);
+}
+
+
+PTR
+ck_malloc (size)
+ size_t size;
+{
+ PTR ret;
+
+ if (!size)
+ size++;
+ ret = malloc (size);
+ if (ret == 0)
+ panic ("Couldn't allocate memory");
+ return ret;
+}
+
+/* Used by alloca.c and bison.simple. */
+char *
+xmalloc (size)
+ size_t size;
+{
+ return (char *) ck_malloc (size);
+}
+
+PTR
+ck_realloc (ptr, size)
+ PTR ptr;
+ size_t size;
+{
+ PTR ret;
+
+ if (!ptr)
+ ret = ck_malloc (size);
+ else
+ ret = realloc (ptr, size);
+ if (ret == 0)
+ panic ("Couldn't re-allocate memory");
+ return ret;
+}
+
+/* Implement a variable sized buffer of 'stuff'. We don't know what it is,
+ nor do we care, as long as it doesn't mind being aligned on a char boundry.
+ */
+
+struct buffer
+ {
+ int allocated;
+ int length;
+ char *b;
+ };
+
+#define MIN_ALLOCATE 50
+
+char *
+init_buffer ()
+{
+ struct buffer *b;
+
+ b = (struct buffer *) ck_malloc (sizeof (struct buffer));
+ b->allocated = MIN_ALLOCATE;
+ b->b = (char *) ck_malloc (MIN_ALLOCATE);
+ b->length = 0;
+ return (char *) b;
+}
+
+void
+flush_buffer (bb)
+ char *bb;
+{
+ struct buffer *b;
+
+ b = (struct buffer *) bb;
+ free (b->b);
+ b->b = 0;
+ b->allocated = 0;
+ b->length = 0;
+ free ((void *) b);
+}
+
+void
+add_buffer (bb, p, n)
+ char *bb;
+ char *p;
+ int n;
+{
+ struct buffer *b;
+
+ b = (struct buffer *) bb;
+ if (b->length + n > b->allocated)
+ {
+ b->allocated = b->length + n + MIN_ALLOCATE;
+ b->b = (char *) ck_realloc (b->b, b->allocated);
+ }
+ bcopy (p, b->b + b->length, n);
+ b->length += n;
+}
+
+char *
+get_buffer (bb)
+ char *bb;
+{
+ struct buffer *b;
+
+ b = (struct buffer *) bb;
+ return b->b;
+}
+
+char *
+merge_sort (list, n, off, cmp)
+ char *list;
+ int (*cmp) ();
+ unsigned n;
+ int off;
+{
+ char *ret;
+
+ char *alist, *blist;
+ unsigned alength, blength;
+
+ char *tptr;
+ int tmp;
+ char **prev;
+#define NEXTOF(ptr) (* ((char **)(((char *)(ptr))+off) ) )
+ if (n == 1)
+ return list;
+ if (n == 2)
+ {
+ if ((*cmp) (list, NEXTOF (list)) > 0)
+ {
+ ret = NEXTOF (list);
+ NEXTOF (ret) = list;
+ NEXTOF (list) = 0;
+ return ret;
+ }
+ return list;
+ }
+ alist = list;
+ alength = (n + 1) / 2;
+ blength = n / 2;
+ for (tptr = list, tmp = (n - 1) / 2; tmp; tptr = NEXTOF (tptr), tmp--)
+ ;
+ blist = NEXTOF (tptr);
+ NEXTOF (tptr) = 0;
+
+ alist = merge_sort (alist, alength, off, cmp);
+ blist = merge_sort (blist, blength, off, cmp);
+ prev = &ret;
+ for (; alist && blist;)
+ {
+ if ((*cmp) (alist, blist) < 0)
+ {
+ tptr = NEXTOF (alist);
+ *prev = alist;
+ prev = &(NEXTOF (alist));
+ alist = tptr;
+ }
+ else
+ {
+ tptr = NEXTOF (blist);
+ *prev = blist;
+ prev = &(NEXTOF (blist));
+ blist = tptr;
+ }
+ }
+ if (alist)
+ *prev = alist;
+ else
+ *prev = blist;
+
+ return ret;
+}
+
+void
+ck_close (fd)
+ int fd;
+{
+ if (close (fd) < 0)
+ {
+ msg_perror ("can't close a file #%d", fd);
+ exit (EX_SYSTEM);
+ }
+}
+
+#include <ctype.h>
+
+/* Quote_copy_string is like quote_string, but instead of modifying the
+ string in place, it malloc-s a copy of the string, and returns that.
+ If the string does not have to be quoted, it returns the NULL string.
+ The allocated copy can, of course, be freed with free() after the
+ caller is done with it.
+ */
+char *
+quote_copy_string (string)
+ char *string;
+{
+ char *from_here;
+ char *to_there = 0;
+ char *copy_buf = 0;
+ int c;
+ int copying = 0;
+
+ from_here = string;
+ while (*from_here)
+ {
+ c = *from_here++;
+ if (c == '\\')
+ {
+ if (!copying)
+ {
+ int n;
+
+ n = (from_here - string) - 1;
+ copying++;
+ copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4);
+ if (!copy_buf)
+ return 0;
+ bcopy (string, copy_buf, n);
+ to_there = copy_buf + n;
+ }
+ *to_there++ = '\\';
+ *to_there++ = '\\';
+ }
+ else if (isprint (c))
+ {
+ if (copying)
+ *to_there++ = c;
+ }
+ else
+ {
+ if (!copying)
+ {
+ int n;
+
+ n = (from_here - string) - 1;
+ copying++;
+ copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4);
+ if (!copy_buf)
+ return 0;
+ bcopy (string, copy_buf, n);
+ to_there = copy_buf + n;
+ }
+ *to_there++ = '\\';
+ if (c == '\n')
+ *to_there++ = 'n';
+ else if (c == '\t')
+ *to_there++ = 't';
+ else if (c == '\f')
+ *to_there++ = 'f';
+ else if (c == '\b')
+ *to_there++ = 'b';
+ else if (c == '\r')
+ *to_there++ = 'r';
+ else if (c == '\177')
+ *to_there++ = '?';
+ else
+ {
+ to_there[0] = (c >> 6) + '0';
+ to_there[1] = ((c >> 3) & 07) + '0';
+ to_there[2] = (c & 07) + '0';
+ to_there += 3;
+ }
+ }
+ }
+ if (copying)
+ {
+ *to_there = '\0';
+ return copy_buf;
+ }
+ return (char *) 0;
+}
+
+
+/* Un_quote_string takes a quoted c-string (like those produced by
+ quote_string or quote_copy_string and turns it back into the
+ un-quoted original. This is done in place.
+ */
+
+/* There is no un-quote-copy-string. Write it yourself */
+
+char *
+un_quote_string (string)
+ char *string;
+{
+ char *ret;
+ char *from_here;
+ char *to_there;
+ int tmp;
+
+ ret = string;
+ to_there = string;
+ from_here = string;
+ while (*from_here)
+ {
+ if (*from_here != '\\')
+ {
+ if (from_here != to_there)
+ *to_there++ = *from_here++;
+ else
+ from_here++, to_there++;
+ continue;
+ }
+ switch (*++from_here)
+ {
+ case '\\':
+ *to_there++ = *from_here++;
+ break;
+ case 'n':
+ *to_there++ = '\n';
+ from_here++;
+ break;
+ case 't':
+ *to_there++ = '\t';
+ from_here++;
+ break;
+ case 'f':
+ *to_there++ = '\f';
+ from_here++;
+ break;
+ case 'b':
+ *to_there++ = '\b';
+ from_here++;
+ break;
+ case 'r':
+ *to_there++ = '\r';
+ from_here++;
+ break;
+ case '?':
+ *to_there++ = 0177;
+ from_here++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ tmp = *from_here - '0';
+ from_here++;
+ if (*from_here < '0' || *from_here > '7')
+ {
+ *to_there++ = tmp;
+ break;
+ }
+ tmp = tmp * 8 + *from_here - '0';
+ from_here++;
+ if (*from_here < '0' || *from_here > '7')
+ {
+ *to_there++ = tmp;
+ break;
+ }
+ tmp = tmp * 8 + *from_here - '0';
+ from_here++;
+ *to_there = tmp;
+ break;
+ default:
+ ret = 0;
+ *to_there++ = '\\';
+ *to_there++ = *from_here++;
+ break;
+ }
+ }
+ if (*to_there)
+ *to_there++ = '\0';
+ return ret;
+}
+
+#ifndef __MSDOS__
+void
+ck_pipe (pipes)
+ int *pipes;
+{
+ if (pipe (pipes) < 0)
+ {
+ msg_perror ("can't open a pipe");
+ exit (EX_SYSTEM);
+ }
+}
+#endif /* !__MSDOS__ */
+
+#ifndef HAVE_STRSTR
+/*
+ * strstr - find first occurrence of wanted in s
+ */
+
+char * /* found string, or NULL if none */
+strstr (s, wanted)
+ char *s;
+ char *wanted;
+{
+ register char *scan;
+ register size_t len;
+ register char firstc;
+
+ if (*wanted == '\0')
+ return (char *) 0;
+ /*
+ * The odd placement of the two tests is so "" is findable.
+ * Also, we inline the first char for speed.
+ * The ++ on scan has been moved down for optimization.
+ */
+ firstc = *wanted;
+ len = strlen (wanted);
+ for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
+ if (*scan++ == '\0')
+ return (char *) 0;
+ return scan;
+}
+
+#endif /* !HAVE_STRSTR */
+
+#ifndef HAVE_FTRUNCATE
+
+#ifdef F_CHSIZE
+int
+ftruncate (fd, length)
+ int fd;
+ off_t length;
+{
+ return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* !F_CHSIZE */
+#ifdef F_FREESP
+/* code courtesy of William Kucharski, kucharsk@Solbourne.com */
+
+int
+ftruncate (fd, length)
+ int fd; /* file descriptor */
+ off_t length; /* length to set file to */
+{
+ struct flock fl;
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = length;
+ fl.l_type = F_WRLCK; /* write lock on file space */
+
+ /*
+ * This relies on the UNDOCUMENTED F_FREESP argument to
+ * fcntl(2), which truncates the file so that it ends at the
+ * position indicated by fl.l_start.
+ *
+ * Will minor miracles never cease?
+ */
+
+ if (fcntl (fd, F_FREESP, &fl) < 0)
+ return -1;
+
+ return 0;
+}
+
+#else /* !F_FREESP */
+
+int
+ftruncate (fd, length)
+ int fd;
+ off_t length;
+{
+ errno = EIO;
+ return -1;
+}
+
+#endif /* !F_FREESP */
+#endif /* !F_CHSIZE */
+#endif /* !HAVE_FTRUNCATE */
+
+
+extern FILE *msg_file;
+
+#if defined (HAVE_VPRINTF) && __STDC__
+#include <stdarg.h>
+
+void
+msg (char *str,...)
+{
+ va_list args;
+
+ va_start (args, str);
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ vfprintf (stderr, str, args);
+ va_end (args);
+ putc ('\n', stderr);
+ fflush (stderr);
+}
+
+void
+msg_perror (char *str,...)
+{
+ va_list args;
+ int save_e;
+
+ save_e = errno;
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ va_start (args, str);
+ vfprintf (stderr, str, args);
+ va_end (args);
+ errno = save_e;
+ perror (" ");
+ fflush (stderr);
+}
+
+#endif /* HAVE_VPRINTF and __STDC__ */
+
+#if defined(HAVE_VPRINTF) && !__STDC__
+#include <varargs.h>
+void
+msg (str, va_alist)
+ char *str;
+ va_dcl
+{
+ va_list args;
+
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ va_start (args);
+ vfprintf (stderr, str, args);
+ va_end (args);
+ putc ('\n', stderr);
+ fflush (stderr);
+}
+
+void
+msg_perror (str, va_alist)
+ char *str;
+ va_dcl
+{
+ va_list args;
+ int save_e;
+
+ save_e = errno;
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ va_start (args);
+ vfprintf (stderr, str, args);
+ va_end (args);
+ errno = save_e;
+ perror (" ");
+ fflush (stderr);
+}
+
+#endif /* HAVE_VPRINTF and not __STDC__ */
+
+#if !defined(HAVE_VPRINTF) && defined(HAVE_DOPRNT)
+void
+msg (str, args)
+ char *str;
+ int args;
+{
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ _doprnt (str, &args, stderr);
+ putc ('\n', stderr);
+ fflush (stderr);
+}
+
+void
+msg_perror (str, args)
+ char *str;
+ int args;
+{
+ int save_e;
+
+ save_e = errno;
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ _doprnt (str, &args, stderr);
+ errno = save_e;
+ perror (" ");
+ fflush (stderr);
+}
+
+#endif /* !HAVE_VPRINTF and HAVE_DOPRNT */
+
+#if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT)
+void
+msg (str, a1, a2, a3, a4, a5, a6)
+ char *str;
+{
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ fprintf (stderr, str, a1, a2, a3, a4, a5, a6);
+ putc ('\n', stderr);
+ fflush (stderr);
+}
+
+void
+msg_perror (str, a1, a2, a3, a4, a5, a6)
+ char *str;
+{
+ int save_e;
+
+ save_e = errno;
+ fflush (msg_file);
+ fprintf (stderr, "%s: ", tar);
+ if (f_sayblock)
+ fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
+ fprintf (stderr, str, a1, a2, a3, a4, a5, a6);
+ fprintf (stderr, ": ");
+ errno = save_e;
+ perror (" ");
+}
+
+#endif /* !HAVE_VPRINTF and !HAVE_DOPRNT */