home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / tar-1.11.8-src.tgz / tar.out / fsf / tar / src / port.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  18KB  |  823 lines

  1. /* Supporting routines which may sometimes be missing.
  2.    Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
  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 "system.h"
  21.  
  22. #include <signal.h>
  23.  
  24. #define ISPRINT(Char) (ISASCII (Char) && isprint (Char))
  25.  
  26. extern long baserec;
  27.  
  28. /* All machine-dependent #ifdefs should appear here, instead of
  29.    being scattered through the file.  For UN*X systems, it is better to
  30.    figure out what is needed in the configure script, for most of the
  31.    features. */
  32.  
  33. #ifdef __MSDOS__
  34. char TTY_NAME[] = "con";
  35. #define HAVE_STRSTR
  36. #define HAVE_RENAME
  37. #define HAVE_MKDIR
  38. #else
  39. char TTY_NAME[] = "/dev/tty";
  40. #endif
  41.  
  42. /* End of system-dependent #ifdefs */
  43.  
  44. /* I'm not sure the following inclusion is useful...  */
  45. #include "tar.h"
  46.  
  47. #ifdef minix
  48.  
  49. /*-------------------------------------------------------------------------.
  50. | Groan, Minix doesn't have execlp either!                   |
  51. |                                        |
  52. | execlp(file,arg0,arg1...argn,(char *)NULL)                   |
  53. |                                        |
  54. | exec a program, automatically searching for the program through all the  |
  55. | directories on the PATH.                           |
  56. |                                        |
  57. | This version is naive about variable argument lists, it assumes a       |
  58. | straightforward C calling sequence.  If your system has odd stacks *and* |
  59. | doesn't have execlp, YOU get to fix it.                   |
  60. `-------------------------------------------------------------------------*/
  61.  
  62. int
  63. execlp (char *filename, char *arg0)
  64. {
  65.   register char *p, *path;
  66.   register char *fnbuffer;
  67.   char **argstart = &arg0;
  68.   struct stat statbuf;
  69.   extern char **environ;
  70.  
  71.   if (p = getenv ("PATH"), p == NULL)
  72.     {
  73.  
  74.       /* Could not find path variable -- try to exec given filename.  */
  75.  
  76.       return execve (filename, argstart, environ);
  77.     }
  78.  
  79.   /* Make a place to build the filename.  We malloc larger than we need,
  80.      but we know it will fit in this.  */
  81.  
  82.   fnbuffer = malloc (strlen (p) + 1 + strlen (filename));
  83.   if (fnbuffer == NULL)
  84.     {
  85.       errno = ENOMEM;
  86.       return -1;
  87.     }
  88.  
  89.   /* Try each component of the path to see if the file's there and
  90.      executable.  */
  91.  
  92.   for (path = p; path; path = p)
  93.     {
  94.  
  95.       /* Construct full path name to try.  */
  96.  
  97.       if (p = strchr (path, ':'), !p)
  98.     strcpy (fnbuffer, path);
  99.       else
  100.     {
  101.       strncpy (fnbuffer, path, p - path);
  102.       fnbuffer[p - path] = '\0';
  103.       p++;            /* skip : for next time */
  104.     }
  105.       if (strlen (fnbuffer) != 0)
  106.     strcat (fnbuffer, "/");
  107.       strcat (fnbuffer, filename);
  108.  
  109.       /* Check to see if file is there and is a normal file.  */
  110.  
  111.       if (stat (fnbuffer, &statbuf) < 0)
  112.     {
  113.       if (errno == ENOENT)
  114.         continue;        /* file not there,keep on looking */
  115.       else
  116.         goto fail;        /* failed for some reason, return */
  117.     }
  118.       if (!S_ISREG (statbuf.st_mode))
  119.     continue;
  120.  
  121.       if (execve (fnbuffer, argstart, environ) < 0
  122.       && errno != ENOENT
  123.       && errno != ENOEXEC)
  124.     {
  125.  
  126.       /* Failed, for some other reason besides "file.  */
  127.  
  128.       goto fail;
  129.     }
  130.  
  131.       /* If we got error ENOEXEC, the file is executable but is not an
  132.      object file.  Try to execute it as a shell script, returning
  133.      error if we can't execute /bin/sh.
  134.  
  135.      FIXME, this code is broken in several ways.  Shell scripts
  136.      should not in general be executed by the user's SHELL variable
  137.      program.  On more mature systems, the script can specify with
  138.      #!/bin/whatever.  Also, this code clobbers argstart[-1] if the
  139.      exec of the shell fails.  */
  140.  
  141.       if (errno == ENOEXEC)
  142.     {
  143.       char *shell;
  144.  
  145.       /* Try to execute command "sh arg0 arg1 ...".  */
  146.  
  147.       if (shell = getenv ("SHELL"), shell == NULL)
  148.         shell = "/bin/sh";
  149.       argstart[-1] = shell;
  150.       argstart[0] = fnbuffer;
  151.       execve (shell, &argstart[-1], environ);
  152.       goto fail;        /* exec didn't work */
  153.     }
  154.  
  155.       /* If we succeeded, the execve() doesn't return, so we can only be
  156.      here is if the file hasn't been found yet.  Try the next place
  157.      on the path.  */
  158.  
  159.     }
  160.  
  161.   /* All attempts failed to locate the file.  Give up.  */
  162.  
  163.   errno = ENOENT;
  164.  
  165. fail:
  166.   free (fnbuffer);
  167.   return -1;
  168. }
  169.  
  170. #endif /* minix */
  171.  
  172. #ifdef EMUL_OPEN3
  173. #include "open3.h"
  174.  
  175. /*-----------------------------------------------------------------------.
  176. | open3 -- routine to emulate the 3-argument open system.         |
  177. |                                      |
  178. | open3 (path, flag, mode);                         |
  179. |                                      |
  180. | Attempts to open the file specified by the given pathname.  The     |
  181. | following flag bits specify options to the routine.  Needless to say,     |
  182. | you should only specify one of the first three.  Function returns file |
  183. | descriptor if successful, -1 and errno if not.             |
  184. `-----------------------------------------------------------------------*/
  185.  
  186. /* The following symbols should #defined in system.h...  Are they?  FIXME 
  187.  
  188.    O_RDONLY    file open for read only
  189.    O_WRONLY    file open for write only
  190.    O_RDWR    file open for both read & write
  191.  
  192.    O_CREAT    file is created with specified mode if it needs to be
  193.    O_TRUNC    if file exists, it is truncated to 0 bytes
  194.    O_EXCL    used with O_CREAT--routine returns error if file exists  */
  195.  
  196. /* Call that if present in most modern Unix systems.  This version
  197.    attempts to support all the flag bits except for O_NDELAY and
  198.    O_APPEND, which are silently ignored.  The emulation is not as
  199.    efficient as the real thing (at worst, 4 system calls instead of one),
  200.    but there's not much I can do about that.
  201.  
  202.    Written 6/10/87 by Richard Todd.  */
  203.  
  204. /* array to give arguments to access for various modes FIXME, this table
  205.    depends on the specific integer values of O_*, and also contains
  206.    integers (args to 'access') that should be #define's.  */
  207.  
  208. static int modes[] =
  209.   {
  210.     04,                /* O_RDONLY */
  211.     02,                /* O_WRONLY */
  212.     06,                /* O_RDWR */
  213.     06,                /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
  214.   };
  215.  
  216. /* Shut off the automatic emulation of open(), we'll need it. */
  217. #undef open
  218.  
  219. int
  220. open3 (char *path, int flags, int mode)
  221. {
  222.   int exists = 1;
  223.   int call_creat = 0;
  224.   int fd;
  225.  
  226.   /* We actually do the work by calling the open() or creat() system
  227.      call, depending on the flags.  Call_creat is true if we will use
  228.      creat(), false if we will use open().  */
  229.  
  230.   /* See if the file exists and is accessible in the requested mode.
  231.  
  232.      Strictly speaking we shouldn't be using access, since access checks
  233.      against real uid, and the open call should check against euid.  Most
  234.      cases real uid == euid, so it won't matter.  FIXME.  FIXME, the
  235.      construction "flags & 3" and the modes table depends on the specific
  236.      integer values of the O_* #define's.  Foo!  */
  237.  
  238.   if (access (path, modes[flags & 3]) < 0)
  239.     {
  240.       if (errno == ENOENT)
  241.     {
  242.  
  243.       /* The file does not exist.  */
  244.  
  245.       exists = 0;
  246.     }
  247.       else
  248.     {
  249.  
  250.       /* Probably permission violation.  */
  251.  
  252.       if (flags & O_EXCL)
  253.         {
  254.  
  255.           /* Oops, the file exists, we didn't want it.  No matter
  256.          what the error, claim EEXIST.  */
  257.  
  258.           errno = EEXIST;
  259.         }
  260.       return -1;
  261.     }
  262.     }
  263.  
  264.   /* If we have the O_CREAT bit set, check for O_EXCL.  */
  265.  
  266.   if (flags & O_CREAT)
  267.     {
  268.       if ((flags & O_EXCL) && exists)
  269.     {
  270.  
  271.       /* Oops, the file exists and we didn't want it to.  */
  272.  
  273.       errno = EEXIST;
  274.       return -1;
  275.     }
  276.  
  277.       /* If the file doesn't exist, be sure to call creat() so that it
  278.      will be created with the proper mode.  */
  279.  
  280.       if (!exists)
  281.     call_creat = 1;
  282.     }
  283.   else
  284.     {
  285.  
  286.       /* If O_CREAT isn't set and the file doesn't exist, error.  */
  287.  
  288.       if (!exists)
  289.     {
  290.       errno = ENOENT;
  291.       return -1;
  292.     }
  293.     }
  294.  
  295.   /* If the O_TRUNC flag is set and the file exists, we want to call
  296.      creat() anyway, since creat() guarantees that the file will be
  297.      truncated and open()-for-writing doesn't.  (If the file doesn't
  298.      exist, we're calling creat() anyway and the file will be created
  299.      with zero length.)  */
  300.  
  301.   if ((flags & O_TRUNC) && exists)
  302.     call_creat = 1;
  303.  
  304.   /* Actually do the call.  */
  305.  
  306.   if (call_creat)
  307.     {
  308.  
  309.       /* Call creat.  May have to close and reopen the file if we want
  310.      O_RDONLY or O_RDWR access -- creat() only gives O_WRONLY.  */
  311.  
  312.       fd = creat (path, mode);
  313.       if (fd < 0 || (flags & O_WRONLY))
  314.     return fd;
  315.       if (close (fd) < 0)
  316.     return -1;
  317.  
  318.       /* Fall out to reopen the file we've created.  */
  319.     }
  320.  
  321.   /* Calling old open, we strip most of the new flags just in case.  */
  322.  
  323.   return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY));
  324. }
  325.  
  326. #endif /* EMUL_OPEN3 */
  327.  
  328. #ifndef HAVE_MKNOD
  329. #ifdef __MSDOS__
  330. typedef int dev_t;
  331. #endif
  332.  
  333. /*----------------------------.
  334. | Fake mknod by complaining.  |
  335. `----------------------------*/
  336.  
  337. int
  338. mknod (char *path, unsigned short mode, dev_t dev)
  339. {
  340.   int fd;
  341.  
  342.   errno = ENXIO;        /* no such device or address */
  343.   return -1;            /* just give an error */
  344. }
  345.  
  346. /*------------------------.
  347. | Fake links by copying.  |
  348. `------------------------*/
  349.  
  350. int
  351. link (char *path1, char *path2)
  352. {
  353.   char buf[256];
  354.   int ifd, ofd;
  355.   int nrbytes;
  356.   int nwbytes;
  357.  
  358.   WARN ((0, 0, _("%s: Cannot link to %s, copying instead"), path1, path2));
  359.   if (ifd = open (path1, O_RDONLY | O_BINARY), ifd < 0)
  360.     return -1;
  361.   if (ofd = creat (path2, 0666), ofd < 0)
  362.     return -1;
  363. #ifdef __MSDOS__
  364.   setmode (ofd, O_BINARY);
  365. #endif
  366.   while (nrbytes = read (ifd, buf, sizeof (buf)), nrbytes > 0)
  367.     {
  368.       if (nwbytes = write (ofd, buf, nrbytes), nwbytes != nrbytes)
  369.     {
  370.       nrbytes = -1;
  371.       break;
  372.     }
  373.     }
  374.  
  375.   /* Note use of "|" rather than "||" below: we want to close.  */
  376.  
  377.   if ((nrbytes < 0) | (close (ifd) != 0) | (close (ofd) != 0))
  378.     {
  379.       unlink (path2);
  380.       return -1;
  381.     }
  382.   return 0;
  383. }
  384.  
  385. /* Everyone owns everything on MS-DOS (or is it no one owns anything?).  */
  386.  
  387. /*---.
  388. | ?  |
  389. `---*/
  390.  
  391. static int
  392. chown (char *path, int uid, int gid)
  393. {
  394.   return 0;
  395. }
  396.  
  397. /*---.
  398. | ?  |
  399. `---*/
  400.  
  401. int
  402. geteuid (void)
  403. {
  404.   return 0;
  405. }
  406.  
  407. #endif /* !HAVE_MKNOD */
  408.  
  409. #ifdef __TURBOC__
  410. #include <time.h>
  411. #include <fcntl.h>
  412. #include <io.h>
  413.  
  414. struct utimbuf
  415.   {
  416.     time_t actime;        /* access time */
  417.     time_t modtime;        /* modification time */
  418.   };
  419.  
  420. /*---.
  421. | ?  |
  422. `---*/
  423.  
  424. int
  425. utime (char *filename, struct utimbuf *utb)
  426. {
  427.   struct tm *tm;
  428.   struct ftime filetime;
  429.   time_t when;
  430.   int fd;
  431.   int status;
  432.  
  433.   if (utb == 0)
  434.     when = time (0);
  435.   else
  436.     when = utb->modtime;
  437.  
  438.   fd = _open (filename, O_RDWR);
  439.   if (fd == -1)
  440.     return -1;
  441.  
  442.   tm = localtime (&when);
  443.   if (tm->tm_year < 80)
  444.     filetime.ft_year = 0;
  445.   else
  446.     filetime.ft_year = tm->tm_year - 80;
  447.   filetime.ft_month = tm->tm_mon + 1;
  448.   filetime.ft_day = tm->tm_mday;
  449.   if (tm->tm_hour < 0)
  450.     filetime.ft_hour = 0;
  451.   else
  452.     filetime.ft_hour = tm->tm_hour;
  453.   filetime.ft_min = tm->tm_min;
  454.   filetime.ft_tsec = tm->tm_sec / 2;
  455.  
  456.   status = setftime (fd, &filetime);
  457.   _close (fd);
  458.   return status;
  459. }
  460.  
  461. #endif /* __TURBOC__ */
  462.  
  463. /*---.
  464. | ?  |
  465. `---*/
  466.  
  467. voidstar
  468. ck_malloc (size_t size)
  469. {
  470.   if (!size)
  471.     size++;
  472.   return xmalloc (size);
  473. }
  474.  
  475. /* Implement a variable sized buffer of 'stuff'.  We don't know what it
  476.    is, nor do we care, as long as it doesn't mind being aligned on a char
  477.    boundry.  */
  478.  
  479. struct buffer
  480.   {
  481.     int allocated;
  482.     int length;
  483.     char *b;
  484.   };
  485.  
  486. /*---.
  487. | ?  |
  488. `---*/
  489.  
  490. #define MIN_ALLOCATE 50
  491.  
  492. char *
  493. init_buffer (void)
  494. {
  495.   struct buffer *b;
  496.  
  497.   b = (struct buffer *) xmalloc (sizeof (struct buffer));
  498.   b->allocated = MIN_ALLOCATE;
  499.   b->b = (char *) xmalloc (MIN_ALLOCATE);
  500.   b->length = 0;
  501.   return (char *) b;
  502. }
  503.  
  504. /*---.
  505. | ?  |
  506. `---*/
  507.  
  508. void
  509. flush_buffer (char *bb)
  510. {
  511.   struct buffer *b;
  512.  
  513.   b = (struct buffer *) bb;
  514.   free (b->b);
  515.   b->b = 0;
  516.   b->allocated = 0;
  517.   b->length = 0;
  518.   free ((void *) b);
  519. }
  520.  
  521. /*---.
  522. | ?  |
  523. `---*/
  524.  
  525. void
  526. add_buffer (char *bb, const char *p, int n)
  527. {
  528.   struct buffer *b;
  529.  
  530.   b = (struct buffer *) bb;
  531.   if (b->length + n > b->allocated)
  532.     {
  533.       b->allocated = b->length + n + MIN_ALLOCATE;
  534.       b->b = (char *) xrealloc (b->b, (size_t) b->allocated);
  535.     }
  536.   memcpy (b->b + b->length, p, (size_t) n);
  537.   b->length += n;
  538. }
  539.  
  540. /*---.
  541. | ?  |
  542. `---*/
  543.  
  544. char *
  545. get_buffer (char *bb)
  546. {
  547.   struct buffer *b;
  548.  
  549.   b = (struct buffer *) bb;
  550.   return b->b;
  551. }
  552.  
  553. /*---.
  554. | ?  |
  555. `---*/
  556.  
  557. char *
  558. merge_sort (char *list, unsigned n, int off, int (*cmp) ())
  559. {
  560.   char *ret;
  561.  
  562.   char *alist, *blist;
  563.   unsigned alength, blength;
  564.  
  565.   char *tptr;
  566.   int tmp;
  567.   char **prev;
  568. #define NEXTOF(Ptr)    (* ((char **)(((char *)(Ptr))+off) ) )
  569.   if (n == 1)
  570.     return list;
  571.   if (n == 2)
  572.     {
  573.       if ((*cmp) (list, NEXTOF (list)) > 0)
  574.     {
  575.       ret = NEXTOF (list);
  576.       NEXTOF (ret) = list;
  577.       NEXTOF (list) = 0;
  578.       return ret;
  579.     }
  580.       return list;
  581.     }
  582.   alist = list;
  583.   alength = (n + 1) / 2;
  584.   blength = n / 2;
  585.   for (tptr = list, tmp = (n - 1) / 2; tmp; tptr = NEXTOF (tptr), tmp--)
  586.     ;
  587.   blist = NEXTOF (tptr);
  588.   NEXTOF (tptr) = 0;
  589.  
  590.   alist = merge_sort (alist, alength, off, cmp);
  591.   blist = merge_sort (blist, blength, off, cmp);
  592.   prev = &ret;
  593.   for (; alist && blist;)
  594.     {
  595.       if ((*cmp) (alist, blist) < 0)
  596.     {
  597.       tptr = NEXTOF (alist);
  598.       *prev = alist;
  599.       prev = &(NEXTOF (alist));
  600.       alist = tptr;
  601.     }
  602.       else
  603.     {
  604.       tptr = NEXTOF (blist);
  605.       *prev = blist;
  606.       prev = &(NEXTOF (blist));
  607.       blist = tptr;
  608.     }
  609.     }
  610.   if (alist)
  611.     *prev = alist;
  612.   else
  613.     *prev = blist;
  614.  
  615.   return ret;
  616. }
  617.  
  618. /*---.
  619. | ?  |
  620. `---*/
  621.  
  622. void
  623. ck_close (int fd)
  624. {
  625.   if (close (fd) < 0)
  626.     ERROR ((TAREXIT_FAILURE, errno, _("Cannot close a file #%d"), fd));
  627. }
  628.  
  629. #include <ctype.h>
  630.  
  631. /*-------------------------------------------------------------------------.
  632. | Quote_copy_string is like quote_string, but instead of modifying the       |
  633. | string in place, it malloc-s a copy of the string, and returns that.  If |
  634. | the string does not have to be quoted, it returns the NULL string.  The  |
  635. | allocated copy can, of course, be freed with free() after the caller is  |
  636. | done with it.                                   |
  637. `-------------------------------------------------------------------------*/
  638.  
  639. char *
  640. quote_copy_string (const char *string)
  641. {
  642.   const char *from_here;
  643.   char *to_there = NULL;
  644.   char *copy_buf = NULL;
  645.   int c;
  646.   int copying = 0;
  647.  
  648.   from_here = string;
  649.   while (*from_here)
  650.     {
  651.       c = (unsigned char) *from_here++;
  652.       if (c == '\\')
  653.     {
  654.       if (!copying)
  655.         {
  656.           int n;
  657.  
  658.           n = (from_here - string) - 1;
  659.           copying++;
  660.           copy_buf = (char *) xmalloc (n + 5 + strlen (from_here) * 4);
  661.           memcpy (copy_buf, string, (size_t) n);
  662.           to_there = copy_buf + n;
  663.         }
  664.       *to_there++ = '\\';
  665.       *to_there++ = '\\';
  666.     }
  667.       else if (ISPRINT (c))
  668.     {
  669.       if (copying)
  670.         *to_there++ = c;
  671.     }
  672.       else
  673.     {
  674.       if (!copying)
  675.         {
  676.           int n;
  677.  
  678.           n = (from_here - string) - 1;
  679.           copying++;
  680.           copy_buf = (char *) xmalloc (n + 5 + strlen (from_here) * 4);
  681.           memcpy (copy_buf, string, (size_t) n);
  682.           to_there = copy_buf + n;
  683.         }
  684.       *to_there++ = '\\';
  685.       if (c == '\n')
  686.         *to_there++ = 'n';
  687.       else if (c == '\t')
  688.         *to_there++ = 't';
  689.       else if (c == '\f')
  690.         *to_there++ = 'f';
  691.       else if (c == '\b')
  692.         *to_there++ = 'b';
  693.       else if (c == '\r')
  694.         *to_there++ = 'r';
  695.       else if (c == '\177')
  696.         *to_there++ = '?';
  697.       else
  698.         {
  699.           to_there[0] = (c >> 6) + '0';
  700.           to_there[1] = ((c >> 3) & 07) + '0';
  701.           to_there[2] = (c & 07) + '0';
  702.           to_there += 3;
  703.         }
  704.     }
  705.     }
  706.   if (copying)
  707.     {
  708.       *to_there = '\0';
  709.       return copy_buf;
  710.     }
  711.   return NULL;
  712. }
  713.  
  714. /*-----------------------------------------------------------------------.
  715. | Un_quote_string takes a quoted c-string (like those produced by     |
  716. | quote_string or quote_copy_string and turns it back into the un-quoted |
  717. | original.  This is done in place.                     |
  718. `-----------------------------------------------------------------------*/
  719.  
  720. /* There is no un-quote-copy-string.  Write it yourself */
  721.  
  722. char *
  723. un_quote_string (char *string)
  724. {
  725.   char *ret;
  726.   char *from_here;
  727.   char *to_there;
  728.   int tmp;
  729.  
  730.   ret = string;
  731.   to_there = string;
  732.   from_here = string;
  733.   while (*from_here)
  734.     {
  735.       if (*from_here != '\\')
  736.     {
  737.       if (from_here != to_there)
  738.         *to_there++ = *from_here++;
  739.       else
  740.         from_here++, to_there++;
  741.       continue;
  742.     }
  743.       switch (*++from_here)
  744.     {
  745.     case '\\':
  746.       *to_there++ = *from_here++;
  747.       break;
  748.     case 'n':
  749.       *to_there++ = '\n';
  750.       from_here++;
  751.       break;
  752.     case 't':
  753.       *to_there++ = '\t';
  754.       from_here++;
  755.       break;
  756.     case 'f':
  757.       *to_there++ = '\f';
  758.       from_here++;
  759.       break;
  760.     case 'b':
  761.       *to_there++ = '\b';
  762.       from_here++;
  763.       break;
  764.     case 'r':
  765.       *to_there++ = '\r';
  766.       from_here++;
  767.       break;
  768.     case '?':
  769.       *to_there++ = 0177;
  770.       from_here++;
  771.       break;
  772.     case '0':
  773.     case '1':
  774.     case '2':
  775.     case '3':
  776.     case '4':
  777.     case '5':
  778.     case '6':
  779.     case '7':
  780.       tmp = *from_here - '0';
  781.       from_here++;
  782.       if (*from_here < '0' || *from_here > '7')
  783.         {
  784.           *to_there++ = tmp;
  785.           break;
  786.         }
  787.       tmp = tmp * 8 + *from_here - '0';
  788.       from_here++;
  789.       if (*from_here < '0' || *from_here > '7')
  790.         {
  791.           *to_there++ = tmp;
  792.           break;
  793.         }
  794.       tmp = tmp * 8 + *from_here - '0';
  795.       from_here++;
  796.       *to_there++ = tmp;
  797.       break;
  798.     default:
  799.       ret = 0;
  800.       *to_there++ = '\\';
  801.       *to_there++ = *from_here++;
  802.       break;
  803.     }
  804.     }
  805.   if (*to_there)
  806.     *to_there++ = '\0';
  807.   return ret;
  808. }
  809.  
  810. #ifndef __MSDOS__
  811.  
  812. /*---.
  813. | ?  |
  814. `---*/
  815.  
  816. void
  817. ck_pipe (int *pipes)
  818. {
  819.   if (pipe (pipes) < 0)
  820.     ERROR ((TAREXIT_FAILURE, errno, _("Cannot open a pipe")));
  821. }
  822. #endif /* !__MSDOS__ */
  823.