[comp.sources.unix] v11i012: File archive program, Part03/07

rs@uunet.UU.NET (Rich Salz) (08/18/87)

Submitted-by: iuvax!bsu-cs!dhesi@seismo.CSS.GOV (Rahul Dhesi)
Posting-number: Volume 11, Issue 12
Archive-name: zoo/Part03

#! /bin/sh
#
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	needed.c
#	nextfile.c
#	nixtime.i
#	options.c
#	options.h
#	parse.c
#	parse.h
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'needed.c'
then
	echo shar: "will not over-write existing file 'needed.c'"
else
sed 's/^X//' << \SHAR_EOF > 'needed.c'
X#ifndef LINT
Xstatic char sccsid[]="@(#) needed.c 1.6 87/05/29 12:54:43";
X#endif /* LINT */
X
X/*
XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
X*/
X#include "options.h"
X/* Accepts a filename from an archive and returns 1 if a command-line
X   argument filename matches it.  Otherwise returns 0. Returns
X   1 if no arguments were supplied (so by default, all files will
X   be extracted */
X
X#include "zoo.h"
X
X#ifdef NEEDCTYP
X#include <ctype.h>              /* for tolower() */
X#endif
X
X#include <stdio.h>               /* solely to define NULL */
X#include "various.h"
X#include "zoofns.h"
X#include "debug.h"
X
Xextern int next_arg;          /* filenames start at this position */
Xextern int arg_count;         /* count of arguments supplied to program */
Xextern char **arg_vector;     /* vector of arguments supplied to program */
X/* Uses FIRST_ARG in zoo.h, so must be recompiled when switching
X   between Ooz and Zoo */
X
Xint needed(pathname)
Xchar *pathname;
X{
X   register int i;
X   register char *arg;
X   char *justname;
X
X   if (arg_count <= FIRST_ARG)         /* if no filenames supplied */
X      return (1);                   	/* .. then all files are needed */
X	justname = nameptr(pathname);			/* filename without any pathname */
X
X   /* count backwards and stop if '+' is encountered */
X   for (i = arg_count-1;  i >= next_arg; i--) {
X      arg = arg_vector[i];
X#ifdef FOLD
X      strlwr(pathname); strlwr(arg);
X#endif
X      if (strcmp(arg,"+") == 0)
X         return (0);
X
X      /* If the argument contains a slash, the match fails if the
X         path prefixes don't match */
X      if (strchr(arg, *PATH_CH) != NULL) {      /* found slash */
X         char *p;
X         char arg_prefix[PATHSIZE];
X         char path_prefix[PATHSIZE];
X         strcpy(arg_prefix,arg);
X         strcpy(path_prefix,pathname);
X         p = findlast(arg_prefix, PATH_CH);
X         if (p != NULL)
X            *p = '\0';
X         p = findlast(path_prefix, PATH_CH);
X         if (p != NULL)
X            *p = '\0';
X         if (!match_half(path_prefix, arg_prefix)) {
X            continue;                     /* no match this time in loop */
X         }
X      }
X
X      /*
X      We reach here either if the pattern had no slashes, or if it
X      had a slash but the path prefixes matched.  Now we test to see 
X      if the filename parts match.
X      */
X      if (match_half (justname, nameptr(arg)))
X         return (1);
X
X      /* try for a character range */
X      if (match_half (arg, "?-?")) { 			/* character range given */
X         if (arg[0] <= *justname && arg[2] >= *justname)
X            return (1);
X      }
X   }
X   return (0);
X
X} /* needed */
X
X/***********************/
X/*
Xmatch_half() compares a pattern with a string.  Wildcards accepted in
Xthe pattern are:  "*" for zero or more arbitrary characters;  "?"
Xfor any one characters.  Unlike the MS-DOS wildcard match, "*" is
Xcorrectly handled even if it isn't at the end of the pattern. ".'
Xis not special.
X
XOriginally written by Jeff Damens of Columbia University Center for
XComputing Activities.  Taken from the source code for C-Kermit version
X4C.
X*/
X
Xint match_half (string, pattern) 
Xregister char *string, *pattern;
X{
X   char *psave,*ssave;        /* back up pointers for failure */
X   psave = ssave = NULL;
X   while (1) {
X#ifdef IGNORECASE
X      for (; 
X         tolower(*pattern) == tolower(*string); 
X         pattern++,string++                        )  /* skip first */
X#else
X      for (; *pattern == *string; pattern++,string++)  /* skip first */
X#endif /* IGNORECASE */
X
X         if (*string == '\0') 
X            return(1);                          /* end of strings, succeed */
X      if (*string != '\0' && *pattern == '?') {
X         pattern++;                             /* '?', let it match */
X         string++;
X      } else if (*pattern == '*') {             /* '*' ... */
X         psave = ++pattern;                     /* remember where we saw it */
X         ssave = string;                        /* let it match 0 chars */
X      } else if (ssave != NULL && *ssave != '\0') {   /* if not at end  */
X         /* ...have seen a star */
X         string = ++ssave;                      /* skip 1 char from string */
X         pattern = psave;                       /* and back up pattern */
X      } else 
X         return(0);                             /* otherwise just fail */
X   }
X}
X
SHAR_EOF
fi
if test -f 'nextfile.c'
then
	echo shar: "will not over-write existing file 'nextfile.c'"
else
sed 's/^X//' << \SHAR_EOF > 'nextfile.c'
X#ifndef LINT
Xstatic char sccsid[]="@(#) nextfile.c 1.4 87/05/29 12:54:55";
X#endif /* LINT */
X
X#include "options.h"
X/*
XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
X*/
X/*
XFunctions to collect filenames from command line etc.  Nextfile() is
Xused by both Atoz and Zoo.  Wildcard expansion by nextfile() is specific to 
XMS-DOS and this implementation is specific to Microsoft C.  If the symbol 
XPORTABLE is defined, nextfile() becomes effectively a no-op that will return
Xthe original filespec the first time and NULL subsequently.
X*/
X
X#define  FMAX  3        /* Number of different filename patterns */
X
X#include <stdio.h>      /* solely to define NULL */
X#include "various.h"
X#include "zoo.h"        /* solely to define PATHSIZE */
X
X#ifdef PORTABLE
X#ifndef SPECNEXT
X/* If portable version, nextfile() is effectively a no-op and any wildcard
Xexpansion must be done by the runtime system before the command line
Xis received by this program
X*/
Xchar *nextfile (what, filespec, fileset)
Xint what;                        /* whether to initialize or match      */
Xregister char *filespec;         /* filespec to match if initializing   */
Xregister int fileset;            /* which set of files                  */
X{
X   static int first_time [FMAX+1];
X   static char saved_fspec [FMAX+1][PATHSIZE];  /* our own copy of filespec */
X
X   if (what == 0) {
X      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
X      first_time[fileset] = 1;
X      return (NULL);
X   }
X
X   if (first_time[fileset]) {
X      first_time[fileset] = 0;
X      return (saved_fspec[fileset]);
X   } else {
X      return (NULL);
X   }
X}
X#endif /* SPECNEXT */
X#else
X/* if not PORTABLE  then */
X
X#include "intdos.h"     /* registers for MS-DOS interrupts              */
X#include "dta.h"        /* format of MS-DOS disk transfer area (dta)    */
X#include "assert.h"     /* macro definition:  assert() macro            */
X
Xvoid setdta (struct dta_t *);
Xvoid fcbpath (struct dta_t *, char *, char *);
X
X
X/*******************/
X/*
Xnextfile() returns the name of the next source file matching a filespec.
X
XINPUT
X   what: A flag specifying what to do.  If "what" is 0, nextfile() 
X      initializes itself.  If "what" is 1, nextfile() returns the next 
X      matching filename.  
X   filespec:  The filespec, usually containing wildcard characters, that 
X      specifies which files are needed.  If "what" is 0, filespec must be 
X      the filespec for which matching filenames are needed.  If "what" is 1, 
X      nextfile() does not use "filespec" and "filespec" should be NULL to 
X      avoid an assertion error during debugging.
X   fileset:  nextfile() can keep track of more than one set of filespecs.
X      The fileset specifies which filespec is being matched and therefore
X      which set of files is being considered.  "fileset" can be in the
X      range 0:FMAX.  Initialization of one fileset does not affect the
X      other filesets.
X
XOUTPUT
X   IF what == 0 THEN
X      return value is NULL
X   ELSE IF what == 1 THEN
X      IF a matching filename is found THEN
X         return value is pointer to matching filename including supplied path
X      ELSE
X         IF at least one file matched previously but no more match THEN
X            return value is NULL
X         ELSE IF supplied filespec never matched any filename THEN
X            IF this is the first call with what == 1 THEN
X               return value is pointer to original filespec
X            ELSE
X               return value is NULL
X            END IF
X         END IF
X      END IF
X   END IF
X
XNOTE
X
X   Initialization done when "what"=0 is not dependent on the correctness
X   of the supplied filespec but simply initializes internal variables
X   and makes a local copy of the supplied filespec.  If the supplied
X   filespec was illegal, the only effect is that the first time that
X   nextfile() is called with "what"=1, it will return the original 
X   filespec instead of a matching filename.  That the filespec was
X   illegal will become obvious when the caller attempts to open the
X   returned filename for input/output and the open attempt fails.
X
XUSAGE HINTS
X
Xnextfile() can be used in the following manner:
X
X      char *filespec;                  -- will point to filespec
X      char *this_file;                 -- will point to matching filename
X      filespec = parse_command_line(); -- may contain wildcards
X      FILE *stream;
X   
X      nextfile (0, filespec, 0);          -- initialize fileset 0
X      while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) {
X         stream = fopen (this_file, "whatever");
X         if (stream == NULL)
X            printf ("could not open %s\n", this_file);
X         else
X            perform_operations (stream);
X      }
X*/             
X               
Xchar *nextfile (what, filespec, fileset)
Xint what;                        /* whether to initialize or match      */
Xregister char *filespec;         /* filespec to match if initializing   */
Xregister int fileset;            /* which set of files                  */
X{
X   static struct dta_t new_dta [FMAX+1];     /* our own private dta        */
X   static int first_time [FMAX+1];
X   static char pathholder [FMAX+1][PATHSIZE]; /* holds a pathname to return */
X   static char saved_fspec [FMAX+1][PATHSIZE];/* our own copy of filespec   */
X   union REGS regs;
X
X   assert(fileset >= 0 && fileset <= FMAX);
X   if (what == 0) {
X      assert(filespec != NULL);
X      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
X      first_time[fileset] = 1;
X      return (NULL);
X   }
X
X   setdta (&new_dta[fileset]);   /* set new dta -- our very own */      
X   assert(what == 1);
X   assert(filespec == NULL);
X   assert(first_time[fileset] == 0 || first_time[fileset] == 1);
X
X   if (first_time[fileset]) {             /* first time -- initialize etc. */
X      /* find first matching file */
X      regs.h.ah = 0x4e;                   /* FindFirst DOS call      */
X      regs.x.dx = (unsigned int) saved_fspec[fileset]; /* filespec to match */
X      regs.x.cx = 0;                      /* search attributes       */
X      intdos (&regs, &regs);
X   } else {
X      /* find next matching file */
X      regs.h.ah = 0x4f;                   /* FindNext DOS call       */
X      intdos (&regs, &regs);
X   }
X
X   if (regs.x.carry != 0) {            /* if error status                  */
X      if (first_time[fileset]) {       /*   if file never matched then     */
X         first_time[fileset] = 0;
X         return (saved_fspec[fileset]);/*      return original filespec    */
X      } else {                         /*   else                           */
X         first_time[fileset] = 0;      /*                                  */
X         return (NULL);                /*      return (NULL) for no more   */
X      }
X   } else {                                        /* a file matched */
X      first_time[fileset] = 0;         
X      /* add path info  */
X      fcbpath (&new_dta[fileset], saved_fspec[fileset], pathholder[fileset]); 
X      return (pathholder[fileset]);                /* matching path  */
X   }
X} /* nextfile */
X
X/*******************/
X/* This function sets the dta to a new dta */
Xvoid setdta (dta)
Xstruct dta_t *dta;
X{
X   union REGS regs;
X   regs.h.ah = 0x1a;                /* SetDTA Call       */
X   regs.x.dx = (unsigned int) dta;  /* new DTA address   */
X   intdos (&regs, &regs);
X}
X
X/*******************/
X/* 
Xfcbpath() accepts a pointer to the Disk Transfer Area (the DTA format is
Xdescribed on page 131 of Tandy-1000 programmers reference manual), a
Xcharacter pointer to a pathname that may contain wildcards, and a character
Xpointer to a buffer.  Copies into buffer the path prefix from the pathname
Xand the filename prefix from the DTA so that it forms a complete path
X*/
X
Xvoid fcbpath (dta, old_path, new_path)
Xstruct dta_t *dta;
Xchar *old_path;
Xregister char *new_path;
X{
X   register int i;
X   int length, start_pos;
X      
X   strcpy(new_path, old_path);               /* copy the whole thing first */
X   length = strlen(new_path);
X   i = length - 1;                           /* i points to end of path */
X   while (i >= 0 && new_path[i] != '/' && new_path[i] != '\\' && new_path[i] != ':')
X      i--;
X   /* either we found a "/", "\", or ":", or we reached the beginning of
X      the name.  In any case, i points to the last character of the
X      path part. */
X   start_pos = i + 1;
X   for (i = 0; i < 13; i++)
X      new_path[start_pos+i] = dta->fname[i];
X   new_path[start_pos+13] = '\0';
X}
X#endif /* PORTABLE */
X
SHAR_EOF
fi
if test -f 'nixtime.i'
then
	echo shar: "will not over-write existing file 'nixtime.i'"
else
sed 's/^X//' << \SHAR_EOF > 'nixtime.i'
X#ifndef LINT
Xstatic char nixtimeid[]="@(#) nixtime.i 1.2 87/05/03 16:00:16";
X#endif /* LINT */
X
X/*
XTime handling routines for UNIX systems.  These are included by the file
Xmachine.c as needed.
X
XThe contents of this file are hereby released to the public domain.
X
X                                    -- Rahul Dhesi  1986/12/31
X*/
X
Xstruct tm *localtime();
X
X/*****************
XFunction gettime() gets the date and time of the file handle supplied.
XDate and time is in MSDOS format.
X*/
Xgettime(handle,date,time)
Xint handle, *date, *time;
X{
X   struct stat buf;           /* buffer to hold file information */
X   struct tm *tm;             /* will hold year/month/day etc. */
X   if (fstat (handle, &buf) == -1) {
X      prterror ('w', "Could not get file time\n");
X      *date = *time = 0;
X   } else {
X      tm = localtime (&buf.st_mtime); /* get info about file mod time */
X      *date = tm->tm_mday + ((tm->tm_mon + 1) << 5) + 
X         ((tm->tm_year - 80) << 9);
X      *time = tm->tm_sec / 2 + (tm->tm_min << 5) +
X         (tm->tm_hour << 11);
X   }
X
X}
X
X/*****************
XFunction setutime() sets the date and time of the filename supplied.
XDate and time is in MSDOS format.  It assumes the existence of a function
Xgettz() that returns the the difference (localtime - gmt) in seconds.
X*/
Xint setutime(path,date,time)
Xchar *path;
Xunsigned int date, time;
X{
X   int year, month, day, hour, min, sec, daycount;
X   long longtime; 
X   /* no. of days to beginning of month for each month */
X   static int dsboy[12] = { 0, 31, 59, 90, 120, 151, 181, 212,
X                              243, 273, 304, 334};
X
X   /* part of following code is common to zoolist.c -- if memory 
X   space is tight, try to share the code */
X   year  =  (((unsigned int) date >> 9) & 0x7f) + 1980;
X   month =  ((unsigned int) date >> 5) & 0x0f;
X   day   =  date        & 0x1f;
X
X   hour =  ((unsigned int) time >> 11)& 0x1f;
X   min   =  ((unsigned int) time >> 5) & 0x3f;
X   sec   =  ((unsigned int) time & 0x1f) * 2;
X
X#ifdef DEBUG
X   printf (setutime:  "year=%d  month=%d  day=%d  hour=%d  min=%d  sec=%d\n",
X           year, month, day, hour, min, sec);
X#endif
X
X   /* Calculate days since 1970/01/01 */
X   daycount = 365 * (year - 1970) +    /* days due to whole years */
X               (year - 1970) / 4 +     /* days due to leap years */
X               dsboy[month-1] +        /* days since beginning of this year */
X               day-1;                  /* days since beginning of month */
X
X   if (year % 4 == 0 && 
X       year % 400 != 0 && month >= 3)  /* if this is a leap year and month */
X      daycount++;                      /* is March or later, add a day */
X
X   /* Knowing the days, we can find seconds */
X   longtime = daycount * 24L * 60L * 60L    +
X          hour * 60L * 60L   +   min * 60   +    sec;
X
X   longtime = longtime + gettz();      /* adjust for timezone */
X
X   /* special case:  if MSDOS format date and time were zero, then we set
X   time to be zero here too. */
X   if (date == 0 && time == 0)
X      longtime = 0;
X
X   /* longtime is now the time of the file, in seconds, since
X   1970/01/01 00:00:00.  Now we set both access and modification times */
X   {
X      long utimbuf[2];
X      utimbuf[0] = utimbuf[1] = longtime;
X      return (utime (path, utimbuf));
X   }
X}
SHAR_EOF
fi
if test -f 'options.c'
then
	echo shar: "will not over-write existing file 'options.c'"
else
sed 's/^X//' << \SHAR_EOF > 'options.c'
X#ifndef LINT
Xstatic char sccsid[]="@(#) options.c 1.2 87/05/03 16:00:21";
X#endif /* LINT */
X
X/*
XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
X*/
X/*
XHere we define routines specific to only a few systems.  Routines are
Xselected based on defined symbols.  Routines specific to only one
Xsystem are in machine.c for the appropriate system.
X*/
X
X#include "options.h"
X#include <stdio.h>
X#include "various.h"
X#include "zoo.h"
X#include "zoofns.h"
X#include "errors.i"
X
X#ifdef REN_LINK         
X/* rename using link() followed by unlink() */
X/* 
XThe following code assumes that if unlink() returns nonzero, then the
Xattempt to unlink failed.  If unlink() ever returns nonzero after actually
Xunlinking the file, then the file being renamed will be lost!!!  Test this 
Xthoroughly.  It is assumed that link() and unlink() return zero if no
Xerror else nonzero.
X*/
Xint chname (newname, oldname)
Xchar *newname, *oldname;
X{
X   int status;
X   if (link (oldname, newname) == 0) { /* if we can create new name */
X      status = unlink (oldname);          /*   unlink old one */
X      if (status != 0) {                  /*   if unlink of old name failed */
X         unlink (newname);                /*     cancel new link */
X         return (-1);                     /*     return error */
X      } else
X         return (0);
X   }
X   else                    /* couldn't create new link */
X      return (-1);
X}
X#else
X/* else not REN_LINK */
X
Xint chname (newname, oldname)
Xchar *newname, *oldname;
X{
X#ifdef REN_NORM
X   if (rename(newname, oldname) != 0)     /* normal order */
X#else
X   if (rename(oldname, newname) != 0)     /* reverse order */
X#endif
X      return (-1);
X   else
X      return (0);
X}
X#endif /* end of not REN_LINK */
X
SHAR_EOF
fi
if test -f 'options.h'
then
	echo shar: "will not over-write existing file 'options.h'"
else
sed 's/^X//' << \SHAR_EOF > 'options.h'
X/* @(#) options.h 1.16 87/05/03 16:00:25 */
X
X/*
XThe contents of this file are hereby released to the public domain.
X
X                           -- Rahul Dhesi 1986/11/14
X*/
X
X/* 
XThis file defines various symbols and macros that are needed to ensure
Xsystem-independence.  The basic philosophy is to use a distinct symbol for
Xeach attribute that varies from machine to machine.  Then, for each new
Xsystem, we define symbols corresponding to its attributes.  Thus, ideally,
Xthe only place in Zoo code that we actually use the name of a machine is in
Xthis file, portable.h, and possibly in machine.h and options.c.  Everywhere
Xelse in the code we only use names of attributes.  If you need to define a
Xnew machine name, please refer first to the guidelines in the implementor's 
Xdocumentation.
X
XMachine names:
X
XMSC      	Microsoft C under MS-DOS
XDLC		Datalight C under MS-DOS
XSYS_V    	UNIX System V release 2.1
XVMS      	VAX/VMS 4.4
XBSD4_3    	4.3BSD
XMCH_AMIGA 	AmigaDOS with Aztec/Manx C compiler
X
XAttributes of systems:
X
XCHEKDIR
X   Test each supplied filename and if it is a directory or other special
X   type of file, do not try to add it to an archive.  If CHEKDIR is
X   defined, then machine.c must also include function isadir() that
X   tests a supplied handle and returns 1 if it corresponds to a
X   directory or other special type of file.
XCHEKUDIR
X   Like CHEKDIR but use function isuadir() that tests a pathname, not
X   a handle.  Only one of CHEKDIR, CHEKUDIR may be defined.
XDISK_CH
X	If defined, must hold the value of a character that separates a
X   disk name from the rest of the pathname.  All characters up to and
X   including this character will be removed from a pathname before it
X   is stored in an archive.  Usually a colon (':').
XEXISTS
X	If defined, is assumed to be a macro that accepts a filename and
X	returns an int value of 1 if the file exists and 0 if it doesn't.
X   If not defined, existence of files is tested by attempting to open
X   them for read or write access.
XLINT_ARGS
X   Use ANSI-style function argument lists in declarations
XLINT
X   If defined, SCCS identifier strings will not be included in the
X   generated code.  This will make the code smaller and will also
X   avoid complaints from lint about unused variables.  This symbol
X   should be defined in the Makefile, NOT in `options.h', otherwise
X   it will not be fully effective.
XFLAT
X   include files are all in one place (no sys/anything)
XFOLD
X   fold filenames to lowercase.  Define this for case-insensitive filesystems
XFPUTCHAR
X	If defined, a library function fputchar() is assumed available
X	that is like fput() but is a function, not a macro, to save
X	space.  If not defined Zoo uses its own fputchar() functio.
XPORTABLE
X   use portable functions --- define for every system except MS-DOS
XPURIFY
X   When filenames are being read from standard input, ignore all
X   characters begining with the first blank or tab encountered.
X   This will allow filenames to be fed from a program that produces
X   lines containing filenames followed by other information that
X   should be ignored.  Should be defined for most non-**IX systems.
XDONT_SORT
X   don't sort filename arguments -- files will be stored in the
X   exact order in which names are supplied on the command line
XNOENUM
X   compiler does not support enumerations
XDUMB_ASS
X   dumb assertions must be used because the preprocessor doesn't define 
X   the symbols __FILE__ and __LINE__  (which hold the name of the current
X   file and the number of the current line)
XFNLIMIT
X   Pathname length limit for this system
XNEEDCTYP
X   the header file ctype.h is needed because functions such as tolower() are
X   defined only as macros
XNIXTIME
X   If defined, a function setutime() must be defined that will set the
X   date and time of a file whose pathname is supplied.  If not defined,
X   a function settime() must be defined that will do the same for
X   a file handle.
XGETUTIME
X   If defined, a function getutime() must be defined that will return
X   the MS-DOS format date and time of the specified filename.  If this
X   symbol is not defined, then a function gettime() must be defined
X   that will do the same for a supplied handle instead of a filename.
XNOFCNTL
X   if defined, system expects "file.h" to be included rather than "fcntl.h"
XNOSIGNAL
X   don't use signals because library doesn't support them
XPATH_CH
X   the character that should separate the directory name from the filename
X   in the listing of the contents of an archive.  String value.
XPATH_SEP 
X   the set of characters that may separate preceding directory/device 
X   information from the filename.  String value.
XEXT_SEP is the union of PATH_SEP and the set of characters separating a 
X   filename extension from the rest of the filename.  String value.
XEXT_CH
X   character that separates base part of filename from extension.  Char value.
XMEMSET
X	If defined, a library function memset() is assumed available that 
X	conforms to that available under System V.  If not defined, Zoo uses 
X	its own memset() function.
XEXT_DFLT
X   default extension for archives.  String.  Usually ".zoo"
XNIXFNAME
X   if defined, PATH_CH, PATH_SEP, EXT_SEP, EXT_CH, and EXT_DFLT get defined 
X   to conform to UNIX conventions and should not be separately defined
XFORCESLASH
X   if defined any backslashes in names of files will be converted to
X   slashes before the files are added to an archive.  This is useful
X   for MSDOS-like systems that accept both slashes and backslashes,
X   since the standard archive format allows only slashes as directory
X   separators.
XREN_LINK
X   rename a file by using link() followed by unlink() (e.g. Xenix, System V)
XREN_NORM
X   use normal rename function:  "int rename(new, old)" (e.g. Microsoft C)
XREN_REV
X   use reverse rename function:  "int rename(old, new)" (e.g. 4.3BSD)
X   Note:  define exactly one of REN_LINK, REN_NORM, and REN_REV.
XSETMODE
X   change mode of standard output to binary when piping output, then change
X   it back to text.  Macros MODE_BIN(handle) and MODE_TEXT(handle) must also
X   be defined.
XSETBUF
X   Standard output should be set to be unbuffered so output shows up
X   quickly.  Currently used only in Fiz, not in Zoo.
XSPECNEXT
X   If defined, a machine-dependent function nextfile() must be defined that
X   will expand wildcards in a supplied pathname. If not defined, any 
X   wildcard expansion must have been done before the command line parameters 
X   are supplied to the program.
XSTRLWR
X	If defined, a library function strlwr() is assumed available that converts
X	a supplied string to lowercase and returns a pointer it.  If not
X	defined, Zoo uses its own strlwr() function.
XTELL
X	If defined, a library function tell() is assumed available that returns
X	the current file pointer position for a file handle.  If not
X	defined, Zoo uses its own tell() function.
X*/
X
X/* ZOO is always defined currently */
X#define ZOO
X
X#ifdef SYS_V
X#define EXISTS(f)		(access(f, 00) == 0)
X#define MEMSET
X#define FNLIMIT 14
X#define CHEKDIR
X#define NIXTIME
X#define NIXFNAME
X#define NEEDCTYP
X#define NOENUM
X#define PORTABLE
X#define REN_LINK
X#define SETBUF
X#endif
X
X#ifdef MSC
X/* #define STRDUP */
X/* #define FPUTCHAR */
X/* #define TELL */
X/* #define EXISTS(f)   (access(f, 00) == 0)  made code size bigger */
X/* #define MEMSET */
X/* #define STRLWR */
X#define PURIFY
X#define DISK_CH ':'
X#define IGNORECASE
X#define WILDCARD "*.*"
X#define FOLD
X#define FORCESLASH
X#define FNLIMIT 12
X#define NEEDCTYP
X#define CUR_DIR "."
X#define PATH_CH "/"
X#define PATH_SEP ":/\\"
X#define EXT_CH '.'
X#define EXT_SEP  ":/\\."
X#define EXT_DFLT ".zoo"
X#define SETMODE
X#define MODE_BIN(handle)      setmode(handle, O_BINARY)
X#define MODE_TEXT(handle)     setmode(handle, O_TEXT)
X#define LINT_ARGS
X#define REN_NORM
X
X#ifdef  PORTABLE
X#define SPECNEXT
X#define NIXTIME
X#endif
X
X#endif  /* MSC */
X
X#ifdef DLC
X#define STRDUP
X#define STRLWR
X/* #define EXISTS */
X#define NOSIGNAL
X#define PURIFY
X#define DISK_CH ':'
X#define IGNORECASE
X/* #define WILDCARD "*.*" */
X#define FOLD
X#define FORCESLASH
X#define FNLIMIT 12
X#define NEEDCTYP
X#define CUR_DIR "."
X#define PATH_CH "/"
X#define PATH_SEP ":/\\"
X#define EXT_CH '.'
X#define EXT_SEP  ":/\\."
X#define EXT_DFLT ".zoo"
X#define SETMODE
X/* #define LINT_ARGS */
X#define REN_REV
X#define SPECNEXT
X#define NIXTIME
X#endif	/* DLC */
X
X#ifdef BSD4_3
X#define EXISTS(f)		(access(f, 00) == 0)
X#define FNLIMIT 1023
X#define CHEKDIR
X#define NIXTIME
X#define NIXFNAME
X#define NEEDCTYP
X#define PORTABLE
X#define NOENUM
X#define REN_REV
X#define SETBUF
X#endif
X
X#ifdef VMS
X#define FNLIMIT 78
X#define PATH_SEP ":]"
X#define EXT_CH '.'
X#define EXT_SEP ":]."
X#define EXT_DFLT ".zoo"
X#define NOENUM
X#define FLAT
X#define PORTABLE
X#define DUMB_ASS
X#define NOFCNTL
X#endif
X
X#ifdef MCH_AMIGA
X#define PURIFY
X#define DISK_CH ':'
X#define SPECNEXT
X#define WILDCARD "*"
X#define IGNORECASE
X#define FNLIMIT 30
X#define NEEDCTYP
X#define CUR_DIR "."
X#define PATH_CH "/"
X#define PATH_SEP ":/"
X#define EXT_CH   '.'
X#define EXT_SEP  ":/."
X#define EXT_DFLT ".zoo"
X#define PORTABLE
X#define NOSIGNAL
X#define REN_REV
X#define NOENUM
X#define SETBUF
X#define CHEKUDIR
X#define GETUTIME
X#define NIXTIME
X#endif
X
X#ifdef NIXFNAME
X#define CUR_DIR "."
X#define PATH_CH "/"
X#define PATH_SEP "/"
X#define EXT_CH '.'
X#define EXT_SEP  "/."
X#define EXT_DFLT ".zoo"
X#endif
X
X#ifdef GENERIC
X/* #define SPECNEXT */
X#define IGNORECASE
X#define FNLIMIT 11
X#define NEEDCTYP
X#define CUR_DIR "."
X#define PATH_CH "/"
X#define PATH_SEP ":/"
X#define EXT_CH   '.'
X#define EXT_SEP  ":/."
X#define EXT_DFLT ".zoo"
X#define PORTABLE
X#define NOSIGNAL
X/* REN_LINK is UNIX-specific.  Can't find a generic rename() function */
X#define REN_LINK
X/* #define FLAT */
X#define NOENUM
X#define SETBUF
X#define CHEKUDIR
X#define GETUTIME
X#define NIXTIME
X#endif
SHAR_EOF
fi
if test -f 'parse.c'
then
	echo shar: "will not over-write existing file 'parse.c'"
else
sed 's/^X//' << \SHAR_EOF > 'parse.c'
X#ifndef LINT
Xstatic char sccsid[]="@(#) parse.c 1.10 87/05/29 12:55:08";
X#endif /* LINT */
X
X/*
XThe contents of this file are hereby released to the public domain.
X
X                                 -- Rahul Dhesi 1986/11/14
X
X*/
X
X#include "options.h"
X#include "zoo.h"
X#include <stdio.h>
X#include "various.h"
X#include "zoofns.h"
X
X#include "parse.h"
X#include "assert.h"
X
X/*
Xparse() accepts a filename and return its component parts in a structure.
XThe component parts are:  disk drive, path prefix, root name of filename, 
Xand extension.  
X
XIf DISK_CH is not defined, it is assumed that filenames may be
Xpreceded with a disk prefix terminated by the character DISK_CH.
XThe first character of the disk prefix, followed by DISK_CH,
Xis returned in the drive field.
X
XIf the symbol DISK_CH is defined, a null string is returned in the
Xdisk field.
X*/
Xvoid parse (path_st, fname)
Xregister struct path_st *path_st;
Xchar *fname;
X{
X   char tempname[LFNAMESIZE];       /* working copy of supplied fname */
X   char *namep;                   /* points to relevant part of tempname */
X
X   char *p;
X   strcpy (tempname, fname);
X
X#ifdef DEBUG
Xprintf ("parse:  supplied name is [%s].\n", tempname);
X#endif
X
X#ifndef DISK_CH
X   path_st->drive[0] = '\0';
X   namep = tempname;           /* points to pathname+filename */
X#else
X   path_st->drive[0] = '\0';
X   p = strchr (tempname, DISK_CH);      /* point to first ':' */
X
X   if (p != NULL) {
X      path_st->drive[0] = *tempname;/* use only first char of drive name */
X      path_st->drive[1] = DISK_CH;
X      path_st->drive[2] = '\0';
X      namep = ++p;                /* point to pathname+filename */
X   } else {
X      path_st->drive[0] = '\0';
X      namep = tempname;           /* points to pathname+filename */
X   }
X#endif /* end of not DISK_CH */
X   
X   /* Note:  findlast() finds last occurrence in the subject string of 
X      any one of a set of chars */
X
X   /* save the long filename */
X   p = findlast (namep, PATH_SEP);
X
X   /* if path separator found, copy next char onwards; else entire string */
X   strncpy (path_st->lfname,
X               (p != NULL) ? p+1 : namep,
X               LFNAMESIZE);
X   path_st->lfname[LFNAMESIZE-1] = '\0';     /* force null termination */
X
X#ifdef DEBUG
Xprintf ("parse:  path = [%s] long filename = [%s]\n", 
X         namep, path_st->lfname);
X#endif
X
X/* Separate out the extension */
Xp = findlast (namep, EXT_SEP);						/* look for . or /		*/
Xif (p != NULL && *p != EXT_CH)						/* found .?					*/
X	p = NULL;												/* ... if not, ignore / */
X
X#ifdef DEBUG
Xif (p == NULL)
X   printf ("parse:  no extension found for [%s]\n", namep);
Xelse
X   printf ("parse:  extension for [%s] is [%s]\n", namep, p);
X#endif
X   
X   path_st->ext[0] = '\0';                      /* assume no extension  */
X   if (p != NULL) {                             /* found extension      */
X      strncpy (path_st->ext, (p+1), EXTLEN);    /* save extension       */
X      path_st->ext[EXTLEN] = '\0';              /* force termination    */
X      *p = '\0';                                /* null out extension   */
X   }
X
X   /* separate out root of filename if any */
X   p = findlast (namep, PATH_SEP);
X
X   if (p != NULL) {
X      ++p;
X      strncpy (path_st->fname, p, ROOTSIZE);  /* save filename        */
X      *p = '\0';               /* null out filename */
X   } else {
X      strncpy (path_st->fname, namep, ROOTSIZE);
X      *namep = '\0';                   /* null out filename    */
X   }
X   path_st->fname[ROOTSIZE] = '\0';           /* force termination    */
X
X   /* what remains, whether null or not, is the path prefix */
X   path_st->dir[0] = '\0';             /* in case *namep is '\0' */
X
X   strncpy (path_st->dir, namep, PATHSIZE);
X
X   /* remove trailing path-separater from directory name, but don't
X      remove it if it is also the leading separater */
X   { 
X      int n;
X      n = strlen(path_st->dir);
X      if (n != 1)
X         path_st->dir[n-1] = '\0';
X   }
X
X#ifdef DEBUG
Xprintf ("parse:  path prefix = [%s].\n", namep);
X#endif
X   /* if extension is null, and if long filename contains more than
X      ROOTSIZE  characters, transfer some of them to extension */
X   if (path_st->ext[0] == '\0' && strlen(path_st->lfname) > ROOTSIZE) {
X      strncpy(path_st->ext, &path_st->lfname[ROOTSIZE], EXTLEN);
X      path_st->ext[3] = '\0';
X   }
X}
X
X/*******************/
X/* 
Xfindlast() finds last occurrence in provided string of any of the characters
Xexcept the null character in the provided set.
X
XIf found, return value is pointer to character found, else it is NULL.
X*/
X
Xchar *findlast (str, set)
Xregister char *str;        /* subject string     */
Xchar *set;                 /* set of characters to look for */
X
X{
X   register char *p;
X
X   if (str == NULL || set == NULL || *str == '\0' || *set == '\0')
X      return (NULL);
X
X   p = lastptr (str);   /* pointer to last char of string */
X   assert(p != NULL);
X
X   while (p != str && strchr (set, *p) == NULL) {
X      --p;
X   }                 
X
X   /* either p == str or we found a character or both */
X   if (strchr (set, *p) == NULL)
X      return (NULL);
X   else
X      return (p);
X}
X
X/*******************/
X/*
Xlastptr() returns a pointer to the last non-null character in the string, if
Xany.  If the string is null it returns NULL
X*/
X
Xchar *lastptr (str)
Xregister char *str;                 /* string in which to find last char */
X{
X   register char *p;
X   if (str == NULL)
X      prterror ('f', "lastptr:  received null pointer\n");
X   if (*str == '\0')
X      return (NULL);
X   p = str;
X   while (*p != '\0')            /* find trailing null char */
X      ++p;
X   --p;                          /* point to just before it */
X   return (p);
X}
SHAR_EOF
fi
if test -f 'parse.h'
then
	echo shar: "will not over-write existing file 'parse.h'"
else
sed 's/^X//' << \SHAR_EOF > 'parse.h'
X/* @(#) parse.h 1.2 87/05/03 16:01:02 */
X
X/*
XThe contents of this file are hereby released to the public domain.
X
X                           -- Rahul Dhesi 1986/11/14
X*/
X
X/*
Xdefines structure used in call to parse()
X*/
X#define XTRA  2         /* extra space to avoid off-by-one errors */
X
X
Xstruct path_st {
X   char drive[2+1+XTRA];            /* drive name            */
X   char dir[PATHSIZE+1+XTRA];       /* path prefix           */
X   char fname[8+1+XTRA];            /* root name of filename */
X   char lfname[LFNAMESIZE+1+XTRA];  /* long filename    */
X   char ext[EXTLEN+1+XTRA];         /* extension        */
X};
X
X#ifdef LINT_ARGS
Xvoid parse (struct path_st *, char *);
X#else
Xvoid parse();
X#endif
X
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi

-- 

Rich $alz
Cronus Project, BBN Labs			rsalz@bbn.com
Moderator, comp.sources.unix			sources@uunet.uuwedwe