715 lines
18 KiB
C
715 lines
18 KiB
C
/* $Source: /u/mark/src/pax/RCS/list.c,v $
|
|
*
|
|
* $Revision: 1.2 $
|
|
*
|
|
* list.c - List all files on an archive
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* These function are needed to support archive table of contents and
|
|
* verbose mode during extraction and creation of achives.
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
|
|
*
|
|
* Sponsored by The USENIX Association for public distribution.
|
|
*
|
|
* Copyright (c) 1989 Mark H. Colburn.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that the above copyright notice is duplicated in all such
|
|
* forms and that any documentation, advertising materials, and other
|
|
* materials related to such distribution and use acknowledge that the
|
|
* software was developed * by Mark H. Colburn and sponsored by The
|
|
* USENIX Association.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* $Log: list.c,v $
|
|
* Revision 1.2 89/02/12 10:04:43 mark
|
|
* 1.2 release fixes
|
|
*
|
|
* Revision 1.1 88/12/23 18:02:14 mark
|
|
* Initial revision
|
|
*
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char *ident = "$Id: list.c,v 1.2 89/02/12 10:04:43 mark Exp $";
|
|
static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
|
|
#endif /* ! lint */
|
|
|
|
|
|
/* Headers */
|
|
|
|
#include "pax.h"
|
|
|
|
|
|
/* Defines */
|
|
|
|
/*
|
|
* isodigit returns non zero iff argument is an octal digit, zero otherwise
|
|
*/
|
|
#define ISODIGIT(c) (((c) >= '0') && ((c) <= '7'))
|
|
|
|
|
|
/* Function Prototypes */
|
|
|
|
#ifdef __STDC__
|
|
|
|
static void cpio_entry(char *, Stat *);
|
|
static void tar_entry(char *, Stat *);
|
|
static void pax_entry(char *, Stat *);
|
|
static void print_mode(ushort);
|
|
static long from_oct(int digs, char *where);
|
|
|
|
#else /* !__STDC__ */
|
|
|
|
static void cpio_entry();
|
|
static void tar_entry();
|
|
static void pax_entry();
|
|
static void print_mode();
|
|
static long from_oct();
|
|
|
|
#endif /* __STDC__ */
|
|
|
|
|
|
/* Internal Identifiers */
|
|
|
|
static char *monnames[] = {
|
|
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
|
};
|
|
|
|
|
|
/* read_header - read a header record
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Read a record that's supposed to be a header record. Return its
|
|
* address in "head", and if it is good, the file's size in
|
|
* asb->sb_size. Decode things from a file header record into a "Stat".
|
|
* Also set "head_standard" to !=0 or ==0 depending whether header record
|
|
* is "Unix Standard" tar format or regular old tar format.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* char *name - pointer which will contain name of file
|
|
* Stat *asb - pointer which will contain stat info
|
|
*
|
|
* RETURNS
|
|
*
|
|
* Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
|
|
* record full of zeros (EOF marker).
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
int read_header(char *name, Stat *asb)
|
|
|
|
#else
|
|
|
|
int read_header(name, asb)
|
|
char *name;
|
|
Stat *asb;
|
|
|
|
#endif
|
|
{
|
|
int i;
|
|
long sum;
|
|
long recsum;
|
|
#if 0 /* Xn */
|
|
Link *link;
|
|
#endif /* Xn */
|
|
char *p;
|
|
char hdrbuf[BLOCKSIZE];
|
|
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: int read_header() in list.c\n");
|
|
#endif
|
|
memset((char *)asb, 0, sizeof(Stat));
|
|
/* read the header from the buffer */
|
|
if (buf_read(hdrbuf, BLOCKSIZE) != 0) {
|
|
return (EOF);
|
|
}
|
|
|
|
//XXX.mjb: this code doesn't seem to handle filename which are
|
|
//not null-terminated.
|
|
|
|
if ('\0' == hdrbuf[345]) {
|
|
// there's no prefix for the file
|
|
strcpy(name, &hdrbuf[0]);
|
|
} else {
|
|
strcpy(name, &hdrbuf[345]);
|
|
strcat(name, "/");
|
|
strcat(name, &hdrbuf[0]);
|
|
}
|
|
|
|
|
|
recsum = from_oct(8, &hdrbuf[148]);
|
|
sum = 0;
|
|
p = hdrbuf;
|
|
for (i = 0 ; i < 500; i++) {
|
|
|
|
/*
|
|
* We can't use unsigned char here because of old compilers, e.g. V7.
|
|
*/
|
|
sum += 0xFF & *p++;
|
|
}
|
|
|
|
/* Adjust checksum to count the "chksum" field as blanks. */
|
|
for (i = 0; i < 8; i++) {
|
|
sum -= 0xFF & hdrbuf[148 + i];
|
|
}
|
|
sum += ' ' * 8;
|
|
|
|
if (sum == 8 * ' ') {
|
|
|
|
/*
|
|
* This is a zeroed record...whole record is 0's except for the 8
|
|
* blanks we faked for the checksum field.
|
|
*/
|
|
return (2);
|
|
}
|
|
if (sum == recsum) {
|
|
/*
|
|
* Good record. Decode file size and return.
|
|
*/
|
|
if (hdrbuf[156] != LNKTYPE) {
|
|
asb->sb_size = from_oct(1 + 12, &hdrbuf[124]);
|
|
}
|
|
asb->sb_mtime = from_oct(1 + 12, &hdrbuf[136]);
|
|
asb->sb_mode = (from_oct(8, &hdrbuf[100]) & 0777);
|
|
|
|
if (strcmp(&hdrbuf[257], TMAGIC) == 0) {
|
|
/* Unix Standard tar archive */
|
|
head_standard = 1;
|
|
#ifdef NONAMES
|
|
asb->sb_uid = from_oct(8, &hdrbuf[108]);
|
|
asb->sb_gid = from_oct(8, &hdrbuf[116]);
|
|
#else
|
|
asb->sb_uid = finduid(&hdrbuf[265]);
|
|
asb->sb_gid = findgid(&hdrbuf[297]);
|
|
#endif
|
|
switch (hdrbuf[156]) {
|
|
case BLKTYPE:
|
|
case CHRTYPE:
|
|
#ifndef _POSIX_SOURCE
|
|
asb->sb_rdev = makedev(from_oct(8, &hdrbuf[329]),
|
|
from_oct(8, &hdrbuf[337]));
|
|
#endif
|
|
break;
|
|
default:
|
|
/* do nothing... */
|
|
break;
|
|
}
|
|
} else {
|
|
/* Old fashioned tar archive */
|
|
head_standard = 0;
|
|
asb->sb_uid = from_oct(8, &hdrbuf[108]);
|
|
asb->sb_gid = from_oct(8, &hdrbuf[116]);
|
|
}
|
|
|
|
switch (hdrbuf[156]) {
|
|
case REGTYPE:
|
|
case AREGTYPE:
|
|
/*
|
|
* Berkeley tar stores directories as regular files with a
|
|
* trailing /
|
|
*/
|
|
if (name[strlen(name) - 1] == '/') {
|
|
name[strlen(name) - 1] = '\0';
|
|
asb->sb_mode |= S_IFDIR;
|
|
} else {
|
|
asb->sb_mode |= S_IFREG;
|
|
}
|
|
break;
|
|
case LNKTYPE:
|
|
asb->sb_nlink = 2;
|
|
linkto(&hdrbuf[157], asb);
|
|
linkto(name, asb);
|
|
asb->sb_mode |= S_IFREG;
|
|
break;
|
|
case BLKTYPE:
|
|
asb->sb_mode |= S_IFBLK;
|
|
break;
|
|
case CHRTYPE:
|
|
asb->sb_mode |= S_IFCHR;
|
|
break;
|
|
case DIRTYPE:
|
|
asb->sb_mode |= S_IFDIR;
|
|
break;
|
|
#ifdef S_IFLNK
|
|
case SYMTYPE:
|
|
asb->sb_mode |= S_IFLNK;
|
|
strcpy(asb->sb_link, &hdrbuf[157]);
|
|
break;
|
|
#endif
|
|
#ifdef S_IFIFO
|
|
case FIFOTYPE:
|
|
asb->sb_mode |= S_IFIFO;
|
|
break;
|
|
#endif
|
|
#ifdef S_IFCTG
|
|
case CONTTYPE:
|
|
asb->sb_mode |= S_IFCTG;
|
|
break;
|
|
#endif
|
|
#ifdef S_IFSOCK /* Xn */
|
|
case SOCKTYPE: /* Xn */
|
|
asb->sb_mode |= S_IFSOCK; /* Xn */
|
|
break; /* Xn */
|
|
#endif /* Xn */
|
|
}
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/* print_entry - print a single table-of-contents entry
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Print_entry prints a single line of file information. The format
|
|
* of the line is the same as that used by the LS command. For some
|
|
* archive formats, various fields may not make any sense, such as
|
|
* the link count on tar archives. No error checking is done for bad
|
|
* or invalid data.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* char *name - pointer to name to print an entry for
|
|
* Stat *asb - pointer to the stat structure for the file
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
void print_entry(char *name, Stat *asb)
|
|
|
|
#else
|
|
|
|
void print_entry(name, asb)
|
|
char *name;
|
|
Stat *asb;
|
|
|
|
#endif
|
|
{
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: void print_entry() in list.c\n");
|
|
#endif
|
|
switch (ar_interface) {
|
|
case TAR:
|
|
tar_entry(name, asb);
|
|
break;
|
|
case CPIO:
|
|
cpio_entry(name, asb);
|
|
break;
|
|
case PAX:
|
|
pax_entry(name, asb);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* cpio_entry - print a verbose cpio-style entry
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Print_entry prints a single line of file information. The format
|
|
* of the line is the same as that used by the traditional cpio
|
|
* command. No error checking is done for bad or invalid data.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* char *name - pointer to name to print an entry for
|
|
* Stat *asb - pointer to the stat structure for the file
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
static void cpio_entry(char *name, Stat *asb)
|
|
|
|
#else
|
|
|
|
static void cpio_entry(name, asb)
|
|
char *name;
|
|
Stat *asb;
|
|
|
|
#endif
|
|
{
|
|
struct tm *atm;
|
|
Link *from;
|
|
struct passwd *pwp;
|
|
#if 0 /* Xn */
|
|
struct group *grp;
|
|
#endif /* Xn */
|
|
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: static void cpio_entry() in list.c\n");
|
|
#endif
|
|
if (f_list && f_verbose) {
|
|
fprintf(msgfile, "%-7o", asb->sb_mode);
|
|
atm = localtime(&asb->sb_mtime);
|
|
if (pwp = getpwuid((int) USH(asb->sb_uid))) {
|
|
fprintf(msgfile, "%-6s", pwp->pw_name);
|
|
} else {
|
|
fprintf(msgfile, "%-6u", USH(asb->sb_uid));
|
|
}
|
|
fprintf(msgfile,"%7ld %3s %2d %02d:%02d:%02d %4d ",
|
|
asb->sb_size, monnames[atm->tm_mon],
|
|
atm->tm_mday, atm->tm_hour, atm->tm_min,
|
|
atm->tm_sec, atm->tm_year + 1900);
|
|
}
|
|
fprintf(msgfile, "%s", name);
|
|
if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
|
|
fprintf(msgfile, " linked to %s", from->l_name);
|
|
}
|
|
#ifdef S_IFLNK
|
|
if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
|
|
fprintf(msgfile, " symbolic link to %s", asb->sb_link);
|
|
}
|
|
#endif /* S_IFLNK */
|
|
putc('\n', msgfile);
|
|
}
|
|
|
|
|
|
/* tar_entry - print a tar verbose mode entry
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Print_entry prints a single line of tar file information. The format
|
|
* of the line is the same as that produced by the traditional tar
|
|
* command. No error checking is done for bad or invalid data.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* char *name - pointer to name to print an entry for
|
|
* Stat *asb - pointer to the stat structure for the file
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
static void tar_entry(char *name, Stat *asb)
|
|
|
|
#else
|
|
|
|
static void tar_entry(name, asb)
|
|
char *name;
|
|
Stat *asb;
|
|
|
|
#endif
|
|
{
|
|
struct tm *atm;
|
|
int i;
|
|
int mode;
|
|
char *symnam = "NULL";
|
|
Link *link;
|
|
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: static void tar_entry() in list.c\n");
|
|
#endif
|
|
if ((mode = asb->sb_mode & S_IFMT) == S_IFDIR) {
|
|
return; /* don't print directories */
|
|
}
|
|
if (f_extract) {
|
|
switch (mode) {
|
|
#ifdef S_IFLNK
|
|
case S_IFLNK: /* This file is a symbolic link */
|
|
i = readlink(name, symnam, PATH_MAX - 1);
|
|
if (i < 0) { /* Could not find symbolic link */
|
|
warn("can't read symbolic link", strerror(errno)); /* Xn */
|
|
} else { /* Found symbolic link filename */
|
|
symnam[i] = '\0';
|
|
fprintf(msgfile, "x %s symbolic link to %s\n", name, symnam);
|
|
}
|
|
break;
|
|
#endif
|
|
case S_IFREG: /* It is a link or a file */
|
|
if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
|
|
fprintf(msgfile, "%s linked to %s\n", name, link->l_name);
|
|
} else {
|
|
fprintf(msgfile, "x %s, %ld bytes, %d tape blocks\n",
|
|
name, asb->sb_size, ROUNDUP(asb->sb_size,
|
|
BLOCKSIZE) / BLOCKSIZE);
|
|
}
|
|
}
|
|
} else if (f_append || f_create) {
|
|
switch (mode) {
|
|
#ifdef S_IFLNK
|
|
case S_IFLNK: /* This file is a symbolic link */
|
|
i = readlink(name, symnam, PATH_MAX - 1);
|
|
if (i < 0) { /* Could not find symbolic link */
|
|
warn("can't read symbolic link", strerror(errno)); /* Xn */
|
|
} else { /* Found symbolic link filename */
|
|
symnam[i] = '\0';
|
|
fprintf(msgfile, "a %s symbolic link to %s\n", name, symnam);
|
|
}
|
|
break;
|
|
#endif
|
|
case S_IFREG: /* It is a link or a file */
|
|
fprintf(msgfile, "a %s ", name);
|
|
if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
|
|
fprintf(msgfile, "link to %s\n", link->l_name);
|
|
} else {
|
|
fprintf(msgfile, "%ld Blocks\n",
|
|
ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
|
|
}
|
|
break;
|
|
}
|
|
} else if (f_list) {
|
|
if (f_verbose) {
|
|
atm = localtime(&asb->sb_mtime);
|
|
print_mode(asb->sb_mode);
|
|
fprintf(msgfile," %d/%d %6d %3s %2d %02d:%02d %4d %s",
|
|
asb->sb_uid, asb->sb_gid, asb->sb_size,
|
|
monnames[atm->tm_mon], atm->tm_mday, atm->tm_hour,
|
|
atm->tm_min, atm->tm_year + 1900, name);
|
|
} else {
|
|
fprintf(msgfile, "%s", name);
|
|
}
|
|
switch (mode) {
|
|
#ifdef S_IFLNK
|
|
case S_IFLNK: /* This file is a symbolic link */
|
|
i = readlink(name, symnam, PATH_MAX - 1);
|
|
if (i < 0) { /* Could not find symbolic link */
|
|
warn("can't read symbolic link", strerror(errno)); /* Xn */
|
|
} else { /* Found symbolic link filename */
|
|
symnam[i] = '\0';
|
|
fprintf(msgfile, " symbolic link to %s", symnam);
|
|
}
|
|
break;
|
|
#endif
|
|
case S_IFREG: /* It is a link or a file */
|
|
if ((asb->sb_nlink > 1) && (link = islink(name, asb))) {
|
|
fprintf(msgfile, " linked to %s", link->l_name);
|
|
}
|
|
break; /* Do not print out directories */
|
|
}
|
|
fputc('\n', msgfile);
|
|
} else {
|
|
fprintf(msgfile, "? %s %ld blocks\n", name,
|
|
ROUNDUP(asb->sb_size, BLOCKSIZE) / BLOCKSIZE);
|
|
}
|
|
}
|
|
|
|
|
|
/* pax_entry - print a verbose cpio-style entry
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Print_entry prints a single line of file information. The format
|
|
* of the line is the same as that used by the LS command.
|
|
* No error checking is done for bad or invalid data.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* char *name - pointer to name to print an entry for
|
|
* Stat *asb - pointer to the stat structure for the file
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
static void pax_entry(char *name, Stat *asb)
|
|
|
|
#else
|
|
|
|
static void pax_entry(name, asb)
|
|
char *name;
|
|
Stat *asb;
|
|
|
|
#endif
|
|
{
|
|
struct tm *atm;
|
|
Link *from;
|
|
struct passwd *pwp;
|
|
struct group *grp;
|
|
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: static void pax_entry() in list.c\n");
|
|
#endif
|
|
if (f_list && f_verbose) {
|
|
print_mode(asb->sb_mode);
|
|
fprintf(msgfile, " %2d", asb->sb_nlink);
|
|
atm = localtime(&asb->sb_mtime);
|
|
if (pwp = getpwuid((int) USH(asb->sb_uid))) {
|
|
fprintf(msgfile, " %-8s", pwp->pw_name);
|
|
} else {
|
|
fprintf(msgfile, " %-8u", USH(asb->sb_uid));
|
|
}
|
|
if (grp = getgrgid((int) USH(asb->sb_gid))) {
|
|
fprintf(msgfile, " %-8s", grp->gr_name);
|
|
} else {
|
|
fprintf(msgfile, " %-8u", USH(asb->sb_gid));
|
|
}
|
|
switch (asb->sb_mode & S_IFMT) {
|
|
case S_IFBLK:
|
|
case S_IFCHR:
|
|
#ifndef _POSIX_SOURCE
|
|
fprintf(msgfile, "\t%3d, %3d",
|
|
major(asb->sb_rdev), minor(asb->sb_rdev));
|
|
#endif
|
|
break;
|
|
case S_IFREG:
|
|
fprintf(msgfile, "\t%8ld", asb->sb_size);
|
|
break;
|
|
default:
|
|
fprintf(msgfile, "\t ");
|
|
}
|
|
fprintf(msgfile," %3s %2d %02d:%02d ",
|
|
monnames[atm->tm_mon], atm->tm_mday,
|
|
atm->tm_hour, atm->tm_min);
|
|
}
|
|
fprintf(msgfile, "%s", name);
|
|
if ((asb->sb_nlink > 1) && (from = islink(name, asb))) {
|
|
fprintf(msgfile, " == %s", from->l_name);
|
|
}
|
|
#ifdef S_IFLNK
|
|
if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
|
|
fprintf(msgfile, " -> %s", asb->sb_link);
|
|
}
|
|
#endif /* S_IFLNK */
|
|
putc('\n', msgfile);
|
|
}
|
|
|
|
|
|
/* print_mode - fancy file mode display
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Print_mode displays a numeric file mode in the standard unix
|
|
* representation, ala ls (-rwxrwxrwx). No error checking is done
|
|
* for bad mode combinations. FIFOS, sybmbolic links, sticky bits,
|
|
* block- and character-special devices are supported if supported
|
|
* by the hosting implementation.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* ushort mode - The integer representation of the mode to print.
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
static void print_mode(ushort mode)
|
|
|
|
#else
|
|
|
|
static void print_mode(mode)
|
|
ushort mode;
|
|
|
|
#endif
|
|
{
|
|
/* Tar does not print the leading identifier... */
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: static void print_mode() in list.c\n");
|
|
#endif
|
|
if (ar_interface != TAR) {
|
|
switch (mode & S_IFMT) {
|
|
case S_IFDIR:
|
|
putc('d', msgfile);
|
|
break;
|
|
#ifdef S_IFLNK
|
|
case S_IFLNK:
|
|
putc('l', msgfile);
|
|
break;
|
|
#endif /* S_IFLNK */
|
|
case S_IFBLK:
|
|
putc('b', msgfile);
|
|
break;
|
|
case S_IFCHR:
|
|
putc('c', msgfile);
|
|
break;
|
|
#ifdef S_IFIFO
|
|
case S_IFIFO:
|
|
putc('p', msgfile);
|
|
break;
|
|
#endif /* S_IFIFO */
|
|
case S_IFREG:
|
|
default:
|
|
putc('-', msgfile);
|
|
break;
|
|
}
|
|
}
|
|
putc(mode & 0400 ? 'r' : '-', msgfile);
|
|
putc(mode & 0200 ? 'w' : '-', msgfile);
|
|
putc(mode & 0100
|
|
? mode & 04000 ? 's' : 'x'
|
|
: mode & 04000 ? 'S' : '-', msgfile);
|
|
putc(mode & 0040 ? 'r' : '-', msgfile);
|
|
putc(mode & 0020 ? 'w' : '-', msgfile);
|
|
putc(mode & 0010
|
|
? mode & 02000 ? 's' : 'x'
|
|
: mode & 02000 ? 'S' : '-', msgfile);
|
|
putc(mode & 0004 ? 'r' : '-', msgfile);
|
|
putc(mode & 0002 ? 'w' : '-', msgfile);
|
|
putc(mode & 0001
|
|
? mode & 01000 ? 't' : 'x'
|
|
: mode & 01000 ? 'T' : '-', msgfile);
|
|
}
|
|
|
|
|
|
/* from_oct - quick and dirty octal conversion
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* From_oct will convert an ASCII representation of an octal number
|
|
* to the numeric representation. The number of characters to convert
|
|
* is given by the parameter "digs". If there are less numbers than
|
|
* specified by "digs", then the routine returns -1.
|
|
*
|
|
* PARAMETERS
|
|
*
|
|
* int digs - Number to of digits to convert
|
|
* char *where - Character representation of octal number
|
|
*
|
|
* RETURNS
|
|
*
|
|
* The value of the octal number represented by the first digs
|
|
* characters of the string where. Result is -1 if the field
|
|
* is invalid (all blank, or nonoctal).
|
|
*
|
|
* ERRORS
|
|
*
|
|
* If the field is all blank, then the value returned is -1.
|
|
*
|
|
*/
|
|
|
|
#ifdef __STDC__
|
|
|
|
static long from_oct(int digs, char *where)
|
|
|
|
#else
|
|
|
|
static long from_oct(digs, where)
|
|
int digs; /* number of characters to convert */
|
|
char *where; /* character representation of octal number */
|
|
|
|
#endif
|
|
{
|
|
long value;
|
|
|
|
#ifdef DF_TRACE_DEBUG
|
|
printf("DF_TRACE_DEBUG: static long from_oct() in list.c\n");
|
|
#endif
|
|
while (isspace(*where)) { /* Skip spaces */
|
|
where++;
|
|
if (--digs <= 0) {
|
|
return(-1); /* All blank field */
|
|
}
|
|
}
|
|
value = 0;
|
|
while (digs > 0 && ISODIGIT(*where)) { /* Scan til nonoctal */
|
|
value = (value << 3) | (*where++ - '0');
|
|
--digs;
|
|
}
|
|
|
|
if (digs > 0 && *where && !isspace(*where)) {
|
|
return(-1); /* Ended on non-space/nul */
|
|
}
|
|
return(value);
|
|
}
|