home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / PAX20.ZIP / LIST.C < prev    next >
C/C++ Source or Header  |  1990-11-12  |  18KB  |  738 lines

  1. /* $Source: /u/mark/src/pax/RCS/list.c,v $
  2.  *
  3.  * $Revision: 2.0.0.5 $
  4.  *
  5.  * list.c - List all files on an archive
  6.  *
  7.  * DESCRIPTION
  8.  *
  9.  *    These function are needed to support archive table of contents and
  10.  *    verbose mode during extraction and creation of achives.
  11.  *
  12.  * AUTHOR
  13.  *
  14.  *    Mark H. Colburn, Open Systems Architects, Inc. (mark@minnetech.mn.org)
  15.  *
  16.  * COPYRIGHT
  17.  *
  18.  *    Copyright (c) 1989 Mark H. Colburn.  All rights reserved.
  19.  *
  20.  *    Redistribution and use in source and binary forms are permitted
  21.  *    provided that the above copyright notice and this paragraph are
  22.  *    duplicated in all such forms and that any documentation,
  23.  *    advertising materials, and other materials related to such
  24.  *    distribution and use acknowledge that the software was developed
  25.  *    by Mark H. Colburn.
  26.  *
  27.  *    THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  28.  *    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  29.  *    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  30.  *
  31.  * $Log:    list.c,v $
  32.  * Revision 2.0.0.5  89/10/30  19:52:57  mark
  33.  * patch1: Added some additional support for MS-DOS
  34.  *
  35.  * Revision 2.0.0.4  89/10/30  07:01:45  mark
  36.  * Added declaration of symnam
  37.  *
  38.  * Revision 2.0.0.3  89/10/13  02:35:13  mark
  39.  * Beta Test Freeze
  40.  *
  41.  */
  42.  
  43. #ifndef lint
  44. static char        *ident = "$Id: list.c,v 2.0.0.5 89/10/30 19:52:57 mark Exp Locker: mark $";
  45. static char        *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  46. #endif /* ! lint */
  47.  
  48.  
  49. /* Headers */
  50.  
  51. #include "pax.h"
  52.  
  53.  
  54. /* Defines */
  55.  
  56. /*
  57.  * isodigit returns non zero iff argument is an octal digit, zero otherwise
  58.  */
  59. #define    ISODIGIT(c)    (((c) >= '0') && ((c) <= '7'))
  60.  
  61.  
  62. /* Function Prototypes */
  63.  
  64. #ifdef __STDC__
  65.  
  66. static void         cpio_entry(char *, Stat *);
  67. static void         tar_entry(char *, Stat *);
  68. static void         pax_entry(char *, Stat *);
  69. static void         pr_mode(ushort);
  70. static long         from_oct(int digs, char *where);
  71.  
  72. #else                /* !__STDC__ */
  73.  
  74. static void             cpio_entry();
  75. static void             tar_entry();
  76. static void             pax_entry();
  77. static void             pr_mode();
  78. static long             from_oct();
  79.  
  80. #endif                /* __STDC__ */
  81.  
  82.  
  83. /* Internal Identifiers */
  84.  
  85. static char        *monnames[] = {
  86.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  87.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  88. };
  89.  
  90.  
  91. /* read_header - read a header record
  92.  *
  93.  * DESCRIPTION
  94.  *
  95.  *     Read a record that's supposed to be a header record. Return its
  96.  *    address in "head", and if it is good, the file's size in
  97.  *    asb->sb_size.  Decode things from a file header record into a "Stat".
  98.  *    Also set "head_standard" to !=0 or ==0 depending whether header record
  99.  *    is "Unix Standard" tar format or regular old tar format.
  100.  *
  101.  * PARAMETERS
  102.  *
  103.  *    char   *name        - pointer which will contain name of file
  104.  *    Stat   *asb        - pointer which will contain stat info
  105.  *
  106.  * RETURNS
  107.  *
  108.  *     Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
  109.  *     record full of zeros (EOF marker).
  110.  */
  111.  
  112. #ifdef __STDC__
  113.  
  114. int
  115. read_header(char *name, Stat * asb)
  116.  
  117. #else
  118.  
  119. int
  120. read_header(name, asb)
  121.     char               *name;
  122.     Stat               *asb;
  123.  
  124. #endif
  125. {
  126.     int                 i;
  127.     long                sum;
  128.     long                recsum;
  129.     char               *p;
  130.     char                hdrbuf[BLOCKSIZE];
  131.  
  132.     DBUG_ENTER("read_header");
  133.     memset((char *) asb, 0, sizeof(Stat));
  134.     /* read the header from the buffer */
  135.     if (buf_read(hdrbuf, BLOCKSIZE) != 0) {
  136.     DBUG_RETURN(EOF);
  137.     }
  138.     strcpy(name, hdrbuf);
  139.  
  140.     recsum = from_oct(8, &hdrbuf[148]);
  141.     sum = 0;
  142.     p = hdrbuf;
  143.     for (i = 0; i < 500; i++) {
  144.  
  145.     /*
  146.      * We can't use unsigned char here because of old compilers, e.g. V7.
  147.      */
  148.     sum += 0xFF & *p++;
  149.     }
  150.  
  151.     /* Adjust checksum to count the "chksum" field as blanks. */
  152.     for (i = 0; i < 8; i++) {
  153.     sum -= 0xFF & hdrbuf[148 + i];
  154.     }
  155.     sum += ' ' * 8;
  156.  
  157.     if (sum == 8 * ' ') {
  158.  
  159.     /*
  160.      * This is a zeroed record...whole record is 0's except for the 8
  161.      * blanks we faked for the checksum field.
  162.      */
  163.     DBUG_RETURN(2);
  164.     }
  165.     if (sum == recsum) {
  166.     /*
  167.      * Good record.  Decode file size and return.
  168.      */
  169.     if (hdrbuf[156] != LNKTYPE) {
  170.         asb->sb_size = from_oct(1 + 12, &hdrbuf[124]);
  171.     }
  172.     asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]);
  173.     asb->sb_mode = from_oct(8, &hdrbuf[100]);
  174.  
  175.     if (strcmp(&hdrbuf[257], TMAGIC) == 0) {
  176.         /* Unix Standard tar archive */
  177.         head_standard = 1;
  178.         asb->sb_uid = finduid(&hdrbuf[265]);
  179.         asb->sb_gid = findgid(&hdrbuf[297]);
  180.         switch (hdrbuf[156]) {
  181.         case BLKTYPE:
  182.         case CHRTYPE:
  183.         asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]),
  184.                        from_oct(8, &hdrbuf[337]));
  185.         break;
  186.         default:
  187.         /* do nothing... */
  188.         break;
  189.         }
  190.     } else {
  191.         /* Old fashioned tar archive */
  192.         head_standard = 0;
  193.         asb->sb_uid = from_oct(8, &hdrbuf[108]);
  194.         asb->sb_gid = from_oct(8, &hdrbuf[116]);
  195.     }
  196.  
  197.     switch (hdrbuf[156]) {
  198.  
  199.     case REGTYPE:
  200.     case AREGTYPE:
  201.         /*
  202.          * Berkeley tar stores directories as regular files with a
  203.          * trailing slash
  204.          */
  205.         if (name[strlen(name) - 1] == '/') {
  206.         name[strlen(name) - 1] = '\0';
  207.         asb->sb_mode |= S_IFDIR;
  208.         } else {
  209.         asb->sb_mode |= S_IFREG;
  210.         }
  211.         break;
  212.  
  213.     case LNKTYPE:
  214.         asb->sb_nlink = 2;
  215.         linkto(&hdrbuf[157], asb);
  216.         linkto(name, asb);
  217.         asb->sb_mode |= S_IFREG;
  218.         break;
  219.  
  220. #ifdef S_IFBLK
  221.     case BLKTYPE:
  222.         asb->sb_mode |= S_IFBLK;
  223.         break;
  224. #endif /* S_IFBLK */
  225.  
  226. #ifdef S_IFCHR
  227.     case CHRTYPE:
  228.         asb->sb_mode |= S_IFCHR;
  229.         break;
  230. #endif /* S_IFCHR */
  231.  
  232.     case DIRTYPE:
  233.         asb->sb_mode |= S_IFDIR;
  234.         break;
  235.  
  236. #ifdef S_IFLNK
  237.     case SYMTYPE:
  238.         asb->sb_mode |= S_IFLNK;
  239.         strcpy(asb->sb_link, &hdrbuf[157]);
  240.         break;
  241. #endif /* S_IFLNK */
  242.  
  243. #ifdef S_IFIFO
  244.     case FIFOTYPE:
  245.         asb->sb_mode |= S_IFIFO;
  246.         break;
  247. #endif /* S_IFIFO */
  248.  
  249. #ifdef S_IFCTG
  250.     case CONTTYPE:
  251.         asb->sb_mode |= S_IFCTG;
  252.         break;
  253. #endif
  254.     }
  255.     DBUG_RETURN(1);
  256.     }
  257.     DBUG_RETURN(0);
  258. }
  259.  
  260.  
  261. /* print_entry - print a single table-of-contents entry
  262.  *
  263.  * DESCRIPTION
  264.  *
  265.  *    Print_entry prints a single line of file information.  The format
  266.  *    of the line is the same as that used by the LS command.  For some
  267.  *    archive formats, various fields may not make any sense, such as
  268.  *    the link count on tar archives.  No error checking is done for bad
  269.  *    or invalid data.
  270.  *
  271.  * PARAMETERS
  272.  *
  273.  *    char   *name        - pointer to name to print an entry for
  274.  *    Stat   *asb        - pointer to the stat structure for the file
  275.  */
  276.  
  277. #ifdef __STDC__
  278.  
  279. void
  280. print_entry(char *name, Stat * asb)
  281.  
  282. #else
  283.  
  284. void
  285. print_entry(name, asb)
  286.     char               *name;
  287.     Stat               *asb;
  288.  
  289. #endif
  290. {
  291.     DBUG_ENTER("print_entry");
  292.     switch (ar_interface) {
  293.  
  294.     case TAR:
  295.     tar_entry(name, asb);
  296.     break;
  297.  
  298.     case CPIO:
  299.     cpio_entry(name, asb);
  300.     break;
  301.  
  302.     case PAX:
  303.     pax_entry(name, asb);
  304.     break;
  305.     }
  306.     DBUG_VOID_RETURN;
  307. }
  308.  
  309.  
  310. /* cpio_entry - print a verbose cpio-style entry
  311.  *
  312.  * DESCRIPTION
  313.  *
  314.  *    Print_entry prints a single line of file information.  The format
  315.  *    of the line is the same as that used by the traditional cpio
  316.  *    command.  No error checking is done for bad or invalid data.
  317.  *
  318.  * PARAMETERS
  319.  *
  320.  *    char   *name        - pointer to name to print an entry for
  321.  *    Stat   *asb        - pointer to the stat structure for the file
  322.  */
  323.  
  324. #ifdef __STDC__
  325.  
  326. static void
  327. cpio_entry(char *name, Stat * asb)
  328.  
  329. #else
  330.  
  331. static void
  332. cpio_entry(name, asb)
  333.     char               *name;
  334.     Stat               *asb;
  335.  
  336. #endif
  337. {
  338.     struct tm          *atm;
  339.     Link               *from;
  340.     struct passwd      *pwp;
  341.  
  342.     DBUG_ENTER("cpio_entry");
  343.     if (f_list && f_verbose) {
  344.     fprintf(msgfile, "%-7o", asb->sb_mode);
  345.     atm = localtime(&asb->sb_mtime);
  346.     if (pwp = getpwuid((UIDTYPE) USH(asb->sb_uid))) {
  347.         fprintf(msgfile, "%-6s", pwp->pw_name);
  348.     } else {
  349.         fprintf(msgfile, "%-6u", USH(asb->sb_uid));
  350.     }
  351.     fprintf(msgfile, "%7ld  %3s %2d %02d:%02d:%02d %4d  ",
  352.         asb->sb_size, monnames[atm->tm_mon],
  353.         atm->tm_mday, atm->tm_hour, atm->tm_min,
  354.         atm->tm_sec, atm->tm_year + 1900);
  355.     }
  356.     fprintf(msgfile, "%s", name);
  357.     if ((asb->sb_nlink > 1) && (from = linkfrom(name, asb)) != (Link *)NULL) {
  358.     fprintf(msgfile, " linked to %s", from->l_name);
  359.     }
  360. #ifdef    S_IFLNK
  361.     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
  362.     fprintf(msgfile, " symbolic link to %s", asb->sb_link);
  363.     }
  364. #endif                /* S_IFLNK */
  365.     putc('\n', msgfile);
  366.     DBUG_VOID_RETURN;
  367. }
  368.  
  369.  
  370. /* tar_entry - print a tar verbose mode entry
  371.  *
  372.  * DESCRIPTION
  373.  *
  374.  *    Print_entry prints a single line of tar file information.  The format
  375.  *    of the line is the same as that produced by the traditional tar
  376.  *    command.  No error checking is done for bad or invalid data.
  377.  *
  378.  * PARAMETERS
  379.  *
  380.  *    char   *name        - pointer to name to print an entry for
  381.  *    Stat   *asb        - pointer to the stat structure for the file
  382.  */
  383.  
  384. #ifdef __STDC__
  385.  
  386. static void
  387. tar_entry(char *name, Stat * asb)
  388.  
  389. #else
  390.  
  391. static void
  392. tar_entry(name, asb)
  393.     char               *name;
  394.     Stat               *asb;
  395.  
  396. #endif
  397. {
  398.     struct tm          *atm;
  399.     int            i;
  400.     Link               *link;
  401.     int                 mode;
  402. #ifdef S_IFLNK
  403.     char                symnam[PATH_MAX];
  404. #endif
  405.  
  406.     DBUG_ENTER("tar_entry");
  407.     if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) {
  408.     DBUG_VOID_RETURN;    /* don't print directories */
  409.     }
  410.     if (f_extract) {
  411.     switch (mode) {
  412.  
  413. #ifdef S_IFLNK
  414.     case S_IFLNK:        /* This file is a symbolic link */
  415.         i = readlink(name, symnam, PATH_MAX - 1);
  416.         if (i < 0) {    /* Could not find symbolic link */
  417.         warn("can't read symbolic link", strerror());
  418.         } else {        /* Found symbolic link filename */
  419.         symnam[i] = '\0';
  420.         fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam);
  421.         }
  422.         break;
  423. #endif
  424.  
  425.     case S_IFREG:        /* It is a link or a file */
  426.         if ((asb->sb_nlink > 1) &&
  427.         (link = linkfrom(name, asb)) != (Link *)NULL) {
  428.         fprintf(msgfile, "%s linked to %s\n", name, link->l_name);
  429.         } else {
  430.         fprintf(msgfile, "x %s, %ld bytes, %ld tape blocks\n",
  431.             name, asb->sb_size,
  432.             ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
  433.         }
  434.     }
  435.     } else if (f_append || f_create) {
  436.     switch (mode) {
  437.  
  438. #ifdef S_IFLNK
  439.     case S_IFLNK:        /* This file is a symbolic link */
  440.         i = readlink(name, symnam, PATH_MAX - 1);
  441.         if (i < 0) {    /* Could not find symbolic link */
  442.         warn("can't read symbolic link", strerror());
  443.         } else {        /* Found symbolic link filename */
  444.         symnam[i] = '\0';
  445.         fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam);
  446.         }
  447.         break;
  448. #endif
  449.  
  450.     case S_IFREG:        /* It is a link or a file */
  451.         fprintf(msgfile, "a %s ", name);
  452.         if ((asb->sb_nlink > 1) && (link = linkfrom(name, asb))) {
  453.         fprintf(msgfile, "link to %s\n", link->l_name);
  454.         } else {
  455.         fprintf(msgfile, "%ld Blocks\n",
  456.             ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
  457.         }
  458.         break;
  459.     }
  460.  
  461.     } else if (f_list) {
  462.     if (f_verbose) {
  463.         atm = localtime(&asb->sb_mtime);
  464.         pr_mode(asb->sb_mode);
  465.             fprintf(msgfile, " %3d/%-3d %6ld %3s %2d %02d:%02d %4d %s",
  466.             asb->sb_uid, asb->sb_gid, asb->sb_size,
  467.             monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour,
  468.             atm->tm_min, atm->tm_year + 1900, name);
  469.     } else {
  470.         fprintf(msgfile, "%s", name);
  471.     }
  472.     switch (mode) {
  473.  
  474. #ifdef S_IFLNK
  475.     case S_IFLNK:        /* This file is a symbolic link */
  476.         i = readlink(name, symnam, PATH_MAX - 1);
  477.         if (i < 0) {    /* Could not find symbolic link */
  478.         warn("can't read symbolic link", strerror());
  479.         } else {        /* Found symbolic link filename */
  480.         symnam[i] = '\0';
  481.         fprintf(msgfile, " symbolic link to %s", symnam);
  482.         }
  483.         break;
  484. #endif
  485.  
  486.     case S_IFREG:        /* It is a link or a file */
  487.         if ((asb->sb_nlink > 1) &&
  488.         (link = linkfrom(name, asb)) != (Link *) NULL) {
  489.         fprintf(msgfile, " linked to %s", link->l_name);
  490.         }
  491.         break;        /* Do not print out directories */
  492.     }
  493.  
  494.     fputc('\n', msgfile);
  495.     } else {
  496.     fprintf(msgfile, "? %s %ld blocks\n", name,
  497.         ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
  498.     }
  499.     DBUG_VOID_RETURN;
  500. }
  501.  
  502.  
  503. /* pax_entry - print a verbose cpio-style entry
  504.  *
  505.  * DESCRIPTION
  506.  *
  507.  *    Print_entry prints a single line of file information.  The format
  508.  *    of the line is the same as that used by the LS command.
  509.  *    No error checking is done for bad or invalid data.
  510.  *
  511.  * PARAMETERS
  512.  *
  513.  *    char   *name        - pointer to name to print an entry for
  514.  *    Stat   *asb        - pointer to the stat structure for the file
  515.  */
  516.  
  517. #ifdef __STDC__
  518.  
  519. static void
  520. pax_entry(char *name, Stat * asb)
  521.  
  522. #else
  523.  
  524. static void
  525. pax_entry(name, asb)
  526.     char               *name;
  527.     Stat               *asb;
  528.  
  529. #endif
  530. {
  531.     struct tm          *atm;
  532.     Link               *from;
  533.     struct passwd      *pwp;
  534.     struct group       *grp;
  535.  
  536.     DBUG_ENTER("pax_entry");
  537.     if (f_list && f_verbose) {
  538.     pr_mode(asb->sb_mode);
  539.     fprintf(msgfile, " %3d", asb->sb_nlink);
  540.         atm = localtime(&asb->sb_mtime);
  541. #ifndef MSDOS
  542.     if (pwp = getpwuid((UIDTYPE) USH(asb->sb_uid))) {
  543.         fprintf(msgfile, " %-8s", pwp->pw_name);
  544.     } else {
  545.         fprintf(msgfile, " %-8u", USH(asb->sb_uid));
  546.     }
  547.     if (grp = getgrgid((GIDTYPE) USH(asb->sb_gid))) {
  548.         fprintf(msgfile, " %-8s", grp->gr_name);
  549.     } else {
  550.         fprintf(msgfile, " %-8u", USH(asb->sb_gid));
  551.         }
  552. #endif
  553.     switch (asb->sb_mode & S_IFMT) {
  554.  
  555. #ifdef S_IFBLK
  556.     case S_IFBLK:
  557. #endif /* S_IFBLK */
  558.  
  559. #ifdef S_IFCHR
  560.     case S_IFCHR:
  561.         fprintf(msgfile, "\t%3d, %3d",
  562.             major(asb->sb_rdev), minor(asb->sb_rdev));
  563.         break;
  564. #endif /* S_IFCHR */
  565.  
  566.     case S_IFREG:
  567.         fprintf(msgfile, "\t%8ld", asb->sb_size);
  568.         break;
  569.  
  570.     default:
  571.         fprintf(msgfile, "\t        ");
  572.     }
  573.     fprintf(msgfile, " %3s %2d %02d:%02d ",
  574.         monnames[atm->tm_mon], atm->tm_mday,
  575.         atm->tm_hour, atm->tm_min);
  576.     }
  577.     fprintf(msgfile, "%s", name);
  578.     if ((asb->sb_nlink > 1) && (from = linkfrom(name, asb))) {
  579.     fprintf(msgfile, " == %s", from->l_name);
  580.     }
  581. #ifdef    S_IFLNK
  582.     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
  583.     fprintf(msgfile, " -> %s", asb->sb_link);
  584.     }
  585. #endif                /* S_IFLNK */
  586.     putc('\n', msgfile);
  587.     DBUG_VOID_RETURN;
  588. }
  589.  
  590.  
  591. /* pr_mode - fancy file mode display
  592.  *
  593.  * DESCRIPTION
  594.  *
  595.  *    Pr_mode displays a numeric file mode in the standard unix
  596.  *    representation, ala ls (-rwxrwxrwx).  No error checking is done
  597.  *    for bad mode combinations.  FIFOS, sybmbolic links, sticky bits,
  598.  *    block- and character-special devices are supported if supported
  599.  *    by the hosting implementation.
  600.  *
  601.  * PARAMETERS
  602.  *
  603.  *    ushort    mode    - The integer representation of the mode to print.
  604.  */
  605.  
  606. #ifdef __STDC__
  607.  
  608. static void
  609. pr_mode(ushort mode)
  610.  
  611. #else
  612.  
  613. static void
  614. pr_mode(mode)
  615.     ushort              mode;
  616.  
  617. #endif
  618. {
  619.     DBUG_ENTER("pr_mode");
  620.     /* Tar does not print the leading identifier... */
  621.     if (ar_interface != TAR) {
  622.     switch (mode & S_IFMT) {
  623.  
  624.     case S_IFDIR:
  625.         putc('d', msgfile);
  626.         break;
  627.  
  628. #ifdef    S_IFLNK
  629.     case S_IFLNK:
  630.         putc('l', msgfile);
  631.         break;
  632. #endif /* S_IFLNK */
  633.  
  634.  
  635. #ifdef    S_IFBLK
  636.     case S_IFBLK:
  637.         putc('b', msgfile);
  638.         break;
  639. #endif /* S_IFBLK */
  640.  
  641. #ifdef    S_IFCHR
  642.     case S_IFCHR:
  643.         putc('c', msgfile);
  644.         break;
  645. #endif /* S_IFCHR */
  646.  
  647. #ifdef    S_IFIFO
  648.     case S_IFIFO:
  649.         putc('p', msgfile);
  650.         break;
  651. #endif /* S_IFIFO */
  652.  
  653.     case S_IFREG:
  654.     default:
  655.         putc('-', msgfile);
  656.         break;
  657.     }
  658.     }
  659.     putc(mode & 0400 ? 'r' : '-', msgfile);
  660.     putc(mode & 0200 ? 'w' : '-', msgfile);
  661.     putc(mode & 0100
  662.      ? mode & 04000 ? 's' : 'x'
  663.      : mode & 04000 ? 'S' : '-', msgfile);
  664.     putc(mode & 0040 ? 'r' : '-', msgfile);
  665.     putc(mode & 0020 ? 'w' : '-', msgfile);
  666.     putc(mode & 0010
  667.      ? mode & 02000 ? 's' : 'x'
  668.      : mode & 02000 ? 'S' : '-', msgfile);
  669.     putc(mode & 0004 ? 'r' : '-', msgfile);
  670.     putc(mode & 0002 ? 'w' : '-', msgfile);
  671.     putc(mode & 0001
  672.      ? mode & 01000 ? 't' : 'x'
  673.      : mode & 01000 ? 'T' : '-', msgfile);
  674.     DBUG_VOID_RETURN;
  675. }
  676.  
  677.  
  678. /* from_oct - quick and dirty octal conversion
  679.  *
  680.  * DESCRIPTION
  681.  *
  682.  *    From_oct will convert an ASCII representation of an octal number
  683.  *    to the numeric representation.  The number of characters to convert
  684.  *    is given by the parameter "digs".  If there are less numbers than
  685.  *    specified by "digs", then the routine returns -1.
  686.  *
  687.  * PARAMETERS
  688.  *
  689.  *    int digs    - Number to of digits to convert
  690.  *    char *where    - Character representation of octal number
  691.  *
  692.  * RETURNS
  693.  *
  694.  *    The value of the octal number represented by the first digs
  695.  *    characters of the string where.  Result is -1 if the field
  696.  *    is invalid (all blank, or nonoctal).
  697.  *
  698.  * ERRORS
  699.  *
  700.  *    If the field is all blank, then the value returned is -1.
  701.  *
  702.  */
  703.  
  704. #ifdef __STDC__
  705.  
  706. static long
  707. from_oct(int digs, char *where)
  708.  
  709. #else
  710.  
  711. static long
  712. from_oct(digs, where)
  713.     int                 digs;    /* number of characters to convert */
  714.     char               *where;    /* character representation of octal number */
  715.  
  716. #endif
  717. {
  718.     long                value;
  719.  
  720.     DBUG_ENTER("from_oct");
  721.     while (isspace(*where)) {    /* Skip spaces */
  722.     where++;
  723.     if (--digs <= 0) {
  724.         DBUG_RETURN(-1);    /* All blank field */
  725.     }
  726.     }
  727.     value = 0;
  728.     while (digs > 0 && ISODIGIT(*where)) {    /* Scan til nonoctal */
  729.     value = (value << 3) | (*where++ - '0');
  730.     --digs;
  731.     }
  732.  
  733.     if (digs > 0 && *where && !isspace(*where)) {
  734.     DBUG_RETURN(-1);    /* Ended on non-space/nul */
  735.     }
  736.     DBUG_RETURN(value);
  737. }
  738.