[alt.sources] ARC 5.20 w/Squashing, 6/9

hyc@umix.cc.umich.edu (Howard Chu) (04/14/88)

XX		i += HSIZE;
XX
XX	if (htab[i] == fcode) {
XX		ent = codetab[i];
XX		return;
XX	}
XX	if (htab[i] > 0)
XX		goto probe;
XX
XXnomatch:
XX	putcode(ent, t);
XX	ent = c;
XX	if (free_ent < maxcodemax) {
XX		codetab[i] = free_ent++;	/* code -> hashtable */
XX		htab[i] = fcode;
XX	}
XX	if (in_count >= checkpoint)
XX		cl_block(t);	/* check for adaptive reset */
XX}
XX
XXLONG
XXpred_cm(t)			/* finish compressing a file */
XX	FILE           *t;	/* where to put it */
XX{
XX	putcode(ent, t);	/* put out the final code */
XX	putcode(-1, t);		/* tell output we are done */
XX
XX	return bytes_out;	/* say how big it got */
XX}
XX
XX/*
XX * Decompress a file.  This routine adapts to the codes in the file building
XX * the string table on-the-fly; requiring no table to be stored in the
XX * compressed file.  The tables used herein are shared with those of the
XX * compress() routine.  See the definitions above.
XX */
XX
XXINT
XXdecomp(f, t)			/* decompress a file */
XX	FILE           *f;	/* file to read codes from */
XX	FILE           *t;	/* file to write text to */
XX{
XX	unsigned char  *stackp;
XX	INT             finchar;
XX	INT             code, oldcode, incode;
XX
XX	if ((code = getc_unp(f)) != BITS)
XX		abort("File packed with %d bits, I can only handle %d", code, BITS);
XX
XX	n_bits = INIT_BITS;	/* set starting code size */
XX	clear_flg = 0;
XX
XX	/*
XX	 * As above, initialize the first 256 entries in the table. 
XX	 */
XX	maxcode = MAXCODE(n_bits = INIT_BITS);
XX	setmem(prefix, 256 * sizeof(INT), 0);	/* reset decode string table */
XX	for (code = 255; code >= 0; code--)
XX		suffix[code] = (unsigned char) code;
XX
XX	free_ent = FIRST;
XX
XX	finchar = oldcode = getcode(f);
XX	if (oldcode == -1)	/* EOF already? */
XX		return;		/* Get out of here */
XX	putc_ncr((char) finchar, t);	/* first code must be 8 bits=char */
XX	stackp = stack;
XX
XX	while ((code = getcode(f)) > -1) {
XX		if (code == CLEAR) {	/* reset string table */
XX			setmem(prefix, 256 * sizeof(INT), 0);
XX			clear_flg = 1;
XX			free_ent = FIRST - 1;
XX			if ((code = getcode(f)) == -1)	/* O, untimely death! */
XX				break;
XX		}
XX		incode = code;
XX		/*
XX		 * Special case for KwKwK string. 
XX		 */
XX		if (code >= free_ent) {
XX			*stackp++ = finchar;
XX			code = oldcode;
XX		}
XX		/*
XX		 * Generate output characters in reverse order 
XX		 */
XX		while (code >= 256) {
XX			*stackp++ = suffix[code];
XX			code = prefix[code];
XX		}
XX		*stackp++ = finchar = suffix[code];
XX
XX		/*
XX		 * And put them out in forward order 
XX		 */
XX		do
XX			putc_ncr(*--stackp, t);
XX		while (stackp > stack);
XX
XX		/*
XX		 * Generate the new entry. 
XX		 */
XX		if ((code = free_ent) < maxcodemax) {
XX			prefix[code] = (unsigned short) oldcode;
XX			suffix[code] = finchar;
XX			free_ent = code + 1;
XX		}
XX		/*
XX		 * Remember previous code. 
XX		 */
XX		oldcode = incode;
XX	}
XX}
XX
XX
XX/*************************************************************************
XX * Please note how much trouble it can be to maintain upwards            *
XX * compatibility.  All that follows is for the sole purpose of unpacking *
XX * files which were packed using an older method.                        *
XX *************************************************************************/
XX
XX
XX/*
XX * The h() pointer points to the routine to use for calculating a hash value.
XX * It is set in the init routines to point to either of oldh() or newh().
XX * 
XX * oldh() calculates a hash value by taking the middle twelve bits of the square
XX * of the key.
XX * 
XX * newh() works somewhat differently, and was tried because it makes ARC about
XX * 23% faster.  This approach was abandoned because dynamic Lempel-Zev
XX * (above) works as well, and packs smaller also.  However, inadvertent
XX * release of a developmental copy forces us to leave this in.
XX */
XX
XXstatic unsigned INT(*h) ();	/* pointer to hash function */
XX
XXstatic unsigned INT
XXoldh(pred, foll)		/* old hash function */
XX	unsigned INT    pred;	/* code for preceeding string */
XX	unsigned char   foll;	/* value of following char */
XX{
XX	LONG            local;	/* local hash value */
XX
XX	local = ((pred + foll) | 0x0800) & 0xFFFF; /* create the hash key */
XX	local *= local;		/* square it */
XX	return (local >> 6) & 0x0FFF;	/* return the middle 12 bits */
XX}
XX
XXstatic unsigned INT
XXnewh(pred, foll)		/* new hash function */
XX	unsigned INT    pred;	/* code for preceeding string */
XX	unsigned char   foll;	/* value of following char */
XX{
XX	return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; /* faster hash */
XX}
XX
XX/*
XX * The eolist() function is used to trace down a list of entries with
XX * duplicate keys until the last duplicate is found.
XX */
XX
XXstatic unsigned INT
XXeolist(index)			/* find last duplicate */
XX	unsigned INT    index;
XX{
XX	INT             temp;
XX
XX	while (temp = string_tab[index].next)	/* while more duplicates */
XX		index = temp;
XX
XX	return index;
XX}
XX
XX/*
XX * The hash() routine is used to find a spot in the hash table for a new
XX * entry.  It performs a "hash and linear probe" lookup, using h() to
XX * calculate the starting hash value and eolist() to perform the linear
XX * probe.  This routine DOES NOT detect a table full condition.  That MUST be
XX * checked for elsewhere.
XX */
XX
XXstatic unsigned INT
XXhash(pred, foll)		/* find spot in the string table */
XX	unsigned INT    pred;	/* code for preceeding string */
XX	unsigned char   foll;	/* char following string */
XX{
XX	unsigned INT    local, tempnext;	/* scratch storage */
XX	struct entry   *ep;	/* allows faster table handling */
XX
XX	local = (*h) (pred, foll);	/* get initial hash value */
XX
XX	if (!string_tab[local].used)	/* if that spot is free */
XX		return local;	/* then that's all we need */
XX
XX	else {			/* else a collision has occured */
XX		local = eolist(local);	/* move to last duplicate */
XX
XX		/*
XX		 * We must find an empty spot. We start looking 101 places
XX		 * down the table from the last duplicate. 
XX		 */
XX
XX		tempnext = (local + 101) & 0x0FFF;
XX		ep = &string_tab[tempnext];	/* initialize pointer */
XX
XX		while (ep->used) {	/* while empty spot not found */
XX			if (++tempnext == TABSIZE) {	/* if we are at the end */
XX				tempnext = 0;	/* wrap to beginning of table */
XX				ep = string_tab;
XX			} else
XX				++ep;	/* point to next element in table */
XX		}
XX
XX		/*
XX		 * local still has the pointer to the last duplicate, while
XX		 * tempnext has the pointer to the spot we found.  We use
XX		 * this to maintain the chain of pointers to duplicates. 
XX		 */
XX
XX		string_tab[local].next = tempnext;
XX
XX		return tempnext;
XX	}
XX}
XX
XX/*
XX * The unhash() function is used to search the hash table for a given key.
XX * Like hash(), it performs a hash and linear probe search.  It returns
XX * either the number of the entry (if found) or NOT_FND (if not found).
XX */
XX
XXstatic unsigned INT
XXunhash(pred, foll)		/* search string table for a key */
XX	unsigned INT    pred;	/* code of preceeding string */
XX	unsigned char   foll;	/* character following string */
XX{
XX	unsigned INT    local, offset;	/* scratch storage */
XX	struct entry   *ep;	/* this speeds up access */
XX
XX	local = (*h) (pred, foll);	/* initial hash */
XX
XX	while (1) {
XX		ep = &string_tab[local];	/* speed up table access */
XX
XX		if ((ep->predecessor == pred) && (ep->follower == foll))
XX			return local;	/* we have a match */
XX
XX		if (!ep->next)	/* if no more duplicates */
XX			return NOT_FND;	/* then key is not listed */
XX
XX		local = ep->next;	/* move on to next duplicate */
XX	}
XX}
XX
XX/*
XX * The init_tab() routine is used to initialize our hash table. You realize,
XX * of course, that "initialize" is a complete misnomer.
XX */
XX
XXstatic          INT
XXinit_tab()
XX{				/* set ground state in hash table */
XX	unsigned INT    i;	/* table index */
XX
XX	setmem((char *) string_tab, sizeof(string_tab), 0);
XX
XX	for (i = 0; i < 256; i++)	/* list all single byte strings */
XX		upd_tab(NO_PRED, i);
XX
XX	inbuf = EMPTY;		/* nothing is in our buffer */
XX}
XX
XX/*
XX * The upd_tab routine is used to add a new entry to the string table. As
XX * previously stated, no checks are made to ensure that the table has any
XX * room.  This must be done elsewhere.
XX */
XX
XXINT
XXupd_tab(pred, foll)		/* add an entry to the table */
XX	unsigned INT    pred;	/* code for preceeding string */
XX	unsigned INT    foll;	/* character which follows string */
XX{
XX	struct entry   *ep;	/* pointer to current entry */
XX
XX	/* calculate offset just once */
XX
XX	ep = &string_tab[hash(pred, foll)];
XX
XX	ep->used = TRUE;	/* this spot is now in use */
XX	ep->next = 0;		/* no duplicates after this yet */
XX	ep->predecessor = pred;	/* note code of preceeding string */
XX	ep->follower = foll;	/* note char after string */
XX}
XX
XX/*
XX * This algorithm encoded a file into twelve bit strings (three nybbles). The
XX * gocode() routine is used to read these strings a byte (or two) at a time.
XX */
XX
XXstatic          INT
XXgocode(fd)			/* read in a twelve bit code */
XX	FILE           *fd;	/* file to get code from */
XX{
XX	unsigned INT    localbuf, returnval;
XX	INT             temp;
XX
XX	if (inbuf == EMPTY) {	/* if on a code boundary */
XX		if ((temp = getc_unp(fd)) == EOF)	/* get start of next
XX							 * code */
XX			return EOF;	/* pass back end of file status */
XX		localbuf = temp & 0xFF;	/* mask down to true byte value */
XX		if ((temp = getc_unp(fd)) == EOF)
XX			/* get end of code, * start of next */
XX			return EOF;	/* this should never happen */
XX		inbuf = temp & 0xFF;	/* mask down to true byte value */
XX
XX		returnval = ((localbuf << 4) & 0xFF0) + ((inbuf >> 4) & 0x00F);
XX		inbuf &= 0x000F;/* leave partial code pending */
XX	} else {		/* buffer contains first nybble */
XX		if ((temp = getc_unp(fd)) == EOF)
XX			return EOF;
XX		localbuf = temp & 0xFF;
XX
XX		returnval = localbuf + ((inbuf << 8) & 0xF00);
XX		inbuf = EMPTY;	/* note no hanging nybbles */
XX	}
XX	return returnval;	/* pass back assembled code */
XX}
XX
XXstatic          INT
XXpush(c)				/* push char onto stack */
XX	INT             c;	/* character to push */
XX{
XX	stack[sp] = ((char) c);	/* coerce integer into a char */
XX
XX	if (++sp >= TABSIZE)
XX		abort("Stack overflow\n");
XX}
XX
XXstatic          INT
XXpop()
XX{				/* pop character from stack */
XX	if (sp > 0)
XX		return ((int) stack[--sp]);	/* leave ptr at next empty
XX						 * slot */
XX
XX	else
XX		return EMPTY;
XX}
XX
XX/***** LEMPEL-ZEV DECOMPRESSION *****/
XX
XXstatic INT      code_count;	/* needed to detect table full */
XXstatic unsigned INT code;	/* where we are so far */
XXstatic INT      firstc;		/* true only on first character */
XX
XXINT
XXinit_ucr(new)			/* get set for uncrunching */
XX	INT             new;	/* true to use new hash function */
XX{
XX	if (new)		/* set proper hash function */
XX		h = newh;
XX	else
XX		h = oldh;
XX
XX	sp = 0;			/* clear out the stack */
XX	init_tab();		/* set up atomic code definitions */
XX	code_count = TABSIZE - 256;	/* note space left in table */
XX	firstc = 1;		/* true only on first code */
XX}
XX
XXINT
XXgetc_ucr(f)			/* get next uncrunched byte */
XX	FILE           *f;	/* file containing crunched data */
XX{
XX	unsigned INT    c;	/* a character of input */
XX	INT             code, newcode;
XX	static INT      oldcode, finchar;
XX	struct entry   *ep;	/* allows faster table handling */
XX
XX	if (firstc) {		/* first code is always known */
XX		firstc = FALSE;	/* but next will not be first */
XX		oldcode = gocode(f);
XX		return finchar = string_tab[oldcode].follower;
XX	}
XX	if (!sp) {		/* if stack is empty */
XX		if ((code = newcode = gocode(f)) == EOF)
XX			return EOF;
XX
XX		ep = &string_tab[code];	/* initialize pointer */
XX
XX		if (!ep->used) {/* if code isn't known */
XX			code = oldcode;
XX			ep = &string_tab[code];	/* re-initialize pointer */
XX			push(finchar);
XX		}
XX		while (ep->predecessor != NO_PRED) {
XX			push(ep->follower);	/* decode string backwards */
XX			code = ep->predecessor;
XX			ep = &string_tab[code];
XX		}
XX
XX		push(finchar = ep->follower);	/* save first character also */
XX
XX		/*
XX		 * The above loop will terminate, one way or another, with
XX		 * string_tab[code].follower equal to the first character in
XX		 * the string. 
XX		 */
XX
XX		if (code_count) {	/* if room left in string table */
XX			upd_tab(oldcode, finchar);
XX			--code_count;
XX		}
XX		oldcode = newcode;
XX	}
XX	return pop();		/* return saved character */
XX}
SHAR_EOF
if test 23276 -ne "`wc -c arclzw.c`"
then
echo shar: error transmitting arclzw.c '(should have been 23276 characters)'
fi
echo shar: extracting arcmatch.c '(3403 characters)'
sed 's/^XX//' << \SHAR_EOF > arcmatch.c
XX/*
XX * $Log:	arcmatch.c,v $
XX * Revision 1.2  88/04/11  18:20:43  hyc
XX * fixup pattern matching for BSD...
XX * 
XX * Revision 1.1  88/04/11  18:12:56  hyc
XX * Initial revision
XX * 
XX * Revision 1.2  87/12/19  04:39:35  hyc
XX * Don't convert names to upper case for BSD...
XX * 
XX * Revision 1.1  87/12/19  04:39:06  hyc
XX * Initial revision
XX * 
XX * Revision 1.3  87/08/13  17:05:01  hyc
XX * Run thru indent, fixed some signed vs. unsigned problems
XX * with bp <-> buf, and inbuf and localbuf...
XX *  Revision 1.2  87/07/21  08:48:16  hyc ***
XX * empty log message ***
XX * 
XX */
XX
XX/*
XX * ARC - Archive utility - ARCMATCH
XX * 
XX * Version 2.17, created on 12/17/85 at 20:32:18
XX * 
XX * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
XX * 
XX * By:  Thom Henderson
XX * 
XX * Description: This file contains service routines needed to maintain an
XX * archive.
XX * 
XX * Language: Computer Innovations Optimizing C86
XX */
XX#include <stdio.h>
XX#include "arc.h"
XX
XXINT
XXmatch(n, t)			/* test name against template */
XX	char           *n;	/* name to test */
XX	char           *t;	/* template to test against */
XX{
XX#ifdef MTS
XX	fortran         patbuild(), patmatch(), patfree();
XX	static int      patlen = (-1);
XX	static int      patwork = 0;
XX	static int      patswch = 0;
XX	char            patccid[4];
XX	static char     patchar[2] = "?";
XX	static char     oldtemp[16] = 0;
XX	int             namlen, RETCODE;
XX
XX	if (strcmp(t, oldtemp)) {
XX		if (patwork)
XX			patfree(&patwork);
XX		strcpy(oldtemp, t);
XX		patlen = strlen(oldtemp);
XX		patbuild(oldtemp, &patlen, &patwork, &patswch, patccid, patchar, _retcode RETCODE);
XX		if (RETCODE > 8) {
XX			printf("MTS: patbuild returned %d\n", RETCODE);
XX			abort("bad wildcard in filename");
XX		}
XX	}
XX	namlen = strlen(n);
XX	patmatch(n, &namlen, &patwork, _retcode RETCODE);
XX	switch (RETCODE) {
XX	case 0:
XX		return (1);
XX	case 4:
XX		return (0);
XX	default:
XX		abort("wildcard pattern match failed");
XX	}
XX}
XX
XX#else
XX#ifndef	BSD
XX	upper(n);
XX	upper(t);		/* avoid case problems */
XX
XX	/* first match name part */
XX
XX	while ((*n && *n != '.') || (*t && *t != '.')) {
XX		if (*n != *t && *t != '?') {	/* match fail? */
XX			if (*t != '*')	/* wildcard fail? */
XX				return 0;	/* then no match */
XX			else {	/* else jump over wildcard */
XX				while (*n && *n != '.')
XX					n++;
XX				while (*t && *t != '.')
XX					t++;
XX				break;	/* name part matches wildcard */
XX			}
XX		} else {	/* match good for this char */
XX			n++;	/* advance to next char */
XX			t++;
XX		}
XX	}
XX
XX	if (*n && *n == '.')
XX		n++;		/* skip extension delimiters */
XX	if (*t && *t == '.')
XX		t++;
XX
XX#endif	/* BSD */
XX
XX	/* now match name part */
XX
XX	while (*n || *t) {
XX		if (*n != *t && *t != '?') {	/* match fail? */
XX			if (*t != '*')	/* wildcard fail? */
XX				return 0;	/* then no match */
XX			else
XX				return 1;	/* else good enough */
XX		} else {	/* match good for this char */
XX			n++;	/* advance to next char */
XX			t++;
XX		}
XX	}
XX
XX	return 1;		/* match worked */
XX}
XX#endif
XX
XXINT
XXrempath(nargs, arg)		/* remove paths from filenames */
XX	INT             nargs;	/* number of names */
XX	char           *arg[];	/* pointers to names */
XX{
XX	char           *i, *rindex();	/* string index, reverse indexer */
XX	INT             n;	/* index */
XX
XX	for (n = 0; n < nargs; n++) {	/* for each supplied name */
XX		if (!(i = rindex(arg[n], '\\')))	/* search for end of
XX							 * path */
XX			if (!(i = rindex(arg[n], '/')))
XX				i = rindex(arg[n], ':');
XX		if (i)		/* if path was found */
XX			arg[n] = i + 1;	/* then skip it */
XX	}
XX}
SHAR_EOF
if test 3403 -ne "`wc -c arcmatch.c`"
then
echo shar: error transmitting arcmatch.c '(should have been 3403 characters)'
fi
echo shar: extracting arcmisc.c '(11060 characters)'
sed 's/^XX//' << \SHAR_EOF > arcmisc.c
XX#include <stdio.h>
XX#include <ctype.h>
XX#include "arc.h"
XX#ifdef MSDOS
XX#include <dir.h>
XX#endif
XX#ifdef BSD
XX#include <sys/types.h>
XX#include <sys/dir.h>
XX#endif
XX
XX/* Miscellaneous routines to get ARC running on BSD 4.2... */
XX
XX
XXchar           *
XXsetmem(dest, size, c)
XX	char           *dest;
XX	unsigned INT	size;
XX	char		c;
XX{
XX	unsigned INT	i;
XX
XX	for (i = 0; i < size; dest[i] = c, i++);
XX	return (&dest[0]);
XX}
XX
XX#ifdef MTS
XX#define CUTOFF sepchr[0]
XX#endif
XX#ifdef MSDOS
XX#define CUTOFF '\\'
XX#endif
XX#ifdef BSD
XX#define CUTOFF '/'
XX#endif
XX
XXstatic          INT
XX_makefn(source, dest)
XX	unsigned char  *source;
XX	unsigned char  *dest;
XX{
XX	INT             j;
XX
XX	setmem(dest, 17, 0);	/* clear result field */
XX	for (j = 0; *source && *source != '.'; ++source)
XX		if (j < 8)
XX			dest[j++] = *source;
XX	for (j = 9; *source; ++source)
XX		if (j < 13)
XX			dest[j++] = *source;
XX}
XX/*
XX * make a file name using a template
XX */
XX
XXchar           *
XXmakefnam(rawfn, template, result)
XX	unsigned char  *rawfn;	/* the original file name */
XX	unsigned char  *template;	/* the template data */
XX	unsigned char  *result;	/* where to place the result */
XX{
XX	unsigned char   et[17], er[17], rawbuf[100], *i, *rindex();
XX
XX	*rawbuf = 0;
XX	strcpy(rawbuf, rawfn);
XX#ifdef MTS
XX	i = rawbuf;
XX	if (rawbuf[0] == tmpchr[0]) {
XX		i++;
XX		strcpy(rawfn, i);
XX	} else
XX#endif
XX	if ((i = rindex(rawbuf, CUTOFF))) {
XX		i++;
XX		strcpy(rawfn, i);
XX	}
XX#ifdef MSDOS
XX	else if ((i = rindex(rawbuf, ':'))) {
XX		i++;
XX		strcpy(rawfn, i);
XX	}
XX#endif
XX	if (i)
XX		*i = 0;
XX	else
XX		*rawbuf = 0;
XX
XX	_makefn(template, et);
XX	_makefn(rawfn, er);
XX	*result = 0;		/* assure no data */
XX	strcat(result, rawbuf);
XX	strcat(result, er[0] ? er : et);
XX	strcat(result, er[9] ? er + 9 : et + 9);
XX	return ((char *) &result[0]);
XX}
XX
XX#if MSDOS
XX
XXINT
XXalphasort(dirptr1, dirptr2)
XX	struct direct **dirptr1, **dirptr2;
XX{
XX	return (strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
XX}
XX
XX#endif
XX
XXINT
XXupper(string)
XX	char           *string;
XX{
XX	char           *p;
XX
XX	for (p = string; *p != NULL; p++)
XX		if (islower(*p))
XX			*p = toupper(*p);
XX}
XXINT
XXabort(s, arg1, arg2, arg3)
XX	char           *s;
XX{
XX	fprintf(stderr, "ARC: ");
XX	fprintf(stderr, s, arg1, arg2, arg3);
XX	fprintf(stderr, "\n");
XX#ifdef BSD
XX	perror("BSD");
XX#endif
XX	exit(1);
XX}
XX
XX#ifndef MTS
XX
XXchar           *
XXgcdir(dirname)
XX	char           *dirname;
XX
XX{
XX	if (dirname == NULL || strlen(dirname) == 0)
XX		dirname = (char *) malloc(1024);
XX
XX	getwd(dirname);
XX}
XX
XXchar           *pattern;	/* global so that fmatch can use them */
XXINT             filemode;
XX
XXchar           *
XXdir(filename, mode)		/* get files, one by one */
XX	char           *filename;	/* template, or NULL */
XX	INT             mode;	/* search mode bits */
XX{
XX	static struct direct **namelist;
XX	static char   **NameList;
XX#ifdef BSD
XX	int             alphasort();
XX	int             scandir();
XX#endif	/* BSD */
XX	int             fmatch();
XX	static INT      Nnum = 0, ii;
XX	char           *result = NULL;
XX
XX	pattern = filename;
XX	filemode = mode;	/* set up globals for fmatch */
XX	if (Nnum == 0) {	/* first call */
XX		Nnum = scandir(".", &namelist, fmatch, alphasort);
XX		NameList = (char **) malloc(Nnum * sizeof(char *));
XX		for (ii = 0; ii < Nnum; ii++) {
XX			(NameList)[ii] = (char *) malloc(namelist[ii]->d_namlen + 1);
XX			strcpy((NameList)[ii], namelist[ii]->d_name);
XX		}
XX		ii = 0;
XX	}
XX	if (ii >= Nnum) {	/* all out of files */
XX		if (Nnum) {	/* there were some files found */
XX			for (ii = 0; ii < Nnum; ii++)
XX				free(namelist[ii]);
XX			free(namelist);
XX		}
XX		Nnum = 0;
XX		return (NULL);
XX	} else {
XX		return ((NameList)[ii++]);
XX	}
XX}
XX
XX
XX#define ASTERISK '*'		/* The '*' metacharacter */
XX#define QUESTION '?'		/* The '?' metacharacter */
XX#define LEFT_BRACKET '['	/* The '[' metacharacter */
XX#define RIGHT_BRACKET ']'	/* The ']' metacharacter */
XX
XX#define IS_OCTAL(ch) (ch >= '0' && ch <= '7')
XX
XXtypedef INT     BOOLEAN;
XX#define VOID short
XX#define TRUE 1
XX#define FALSE 0
XX#define EOS '\000'
XX
XXstatic BOOLEAN  do_list();
XXstatic char     nextch();
XXstatic VOID     list_parse();
XX
XX
XX
XX/*
XX * FUNCTION
XX * 
XX * do_list    process a list and following substring
XX * 
XX * SYNOPSIS
XX * 
XX * static BOOLEAN do_list (string, pattern) register char *string; register char
XX * *pattern;
XX * 
XX * DESCRIPTION
XX * 
XX * Called when a list is found in the pattern.  Returns TRUE if the current
XX * character matches the list and the remaining substring matches the
XX * remaining pattern.
XX * 
XX * Returns FALSE if either the current character fails to match the list or the
XX * list matches but the remaining substring and subpattern's don't.
XX * 
XX * RESTRICTIONS
XX * 
XX * The mechanism used to match characters in an inclusive pair (I.E. [a-d]) may
XX * not be portable to machines in which the native character set is not
XX * ASCII.
XX * 
XX * The rules implemented here are:
XX * 
XX * (1)  The backslash character may be used to quote any special character.
XX * I.E.  "\]" and "\-" anywhere in list, or "\!" at start of list.
XX * 
XX * (2)  The sequence \nnn becomes the character given by nnn (in octal).
XX * 
XX * (3)  Any non-escaped ']' marks the end of list.
XX * 
XX * (4)  A list beginning with the special character '!' matches any character
XX * NOT in list. The '!' character is only special if it is the first
XX * character in the list.
XX * 
XX */
XX
XX
XX
XX/*
XX * PSEUDO CODE
XX * 
XX * Begin do_list Default result is no match Skip over the opening left bracket
XX * If the next pattern character is a '!' then List match gives FALSE Skip
XX * over the '!' character Else List match gives TRUE End if While not at
XX * closing bracket or EOS Get lower and upper bounds If character in bounds
XX * then Result is same as sense flag. Skip over rest of list End if End while
XX * If match found then If not at end of pattern then Call match with rest of
XX * pattern End if End if Return match result End do_list
XX * 
XX */
XX
XXstatic          BOOLEAN
XXdo_list(string, pattern)
XX	register char  *string;
XX	char           *pattern;
XX{
XX	register BOOLEAN ismatch;
XX	register BOOLEAN if_found;
XX	register BOOLEAN if_not_found;
XX	auto char       lower;
XX	auto char       upper;
XX
XX	pattern++;
XX	if (*pattern == '!') {
XX		if_found = FALSE;
XX		if_not_found = TRUE;
XX		pattern++;
XX	} else {
XX		if_found = TRUE;
XX		if_not_found = FALSE;
XX	}
XX	ismatch = if_not_found;
XX	while (*pattern != ']' && *pattern != EOS) {
XX		list_parse(&pattern, &lower, &upper);
XX		if (*string >= lower && *string <= upper) {
XX			ismatch = if_found;
XX			while (*pattern != ']' && *pattern != EOS) {
XX				pattern++;
XX			}
XX		}
XX	}
XX	if (*pattern++ != ']') {
XX		fprintf(stderr, "warning - character class error\n");
XX	} else {
XX		if (ismatch) {
XX			ismatch = match(++string, pattern);
XX		}
XX	}
XX	return (ismatch);
XX}
XX
XX
XX
XX/*
XX * FUNCTION
XX * 
XX * list_parse    parse part of list into lower and upper bounds
XX * 
XX * SYNOPSIS
XX * 
XX * static VOID list_parse (patp, lowp, highp) char **patp; char *lowp; char
XX * *highp;
XX * 
XX * DESCRIPTION
XX * 
XX * Given pointer to a pattern pointer (patp), pointer to a place to store lower
XX * bound (lowp), and pointer to a place to store upper bound (highp), parses
XX * part of the list, updating the pattern pointer in the process.
XX * 
XX * For list characters which are not part of a range, the lower and upper bounds
XX * are set to that character.
XX * 
XX */
XX
XXstatic          VOID
XXlist_parse(patp, lowp, highp)
XX	char          **patp;
XX	char           *lowp;
XX	char           *highp;
XX{
XX	*lowp = nextch(patp);
XX	if (**patp == '-') {
XX		(*patp)++;
XX		*highp = nextch(patp);
XX	} else {
XX		*highp = *lowp;
XX	}
XX}
XX
XX
XX
XX/*
XX * FUNCTION
XX * 
XX * nextch    determine next character in a pattern
XX * 
XX * SYNOPSIS
XX * 
XX * static char nextch (patp) char **patp;
XX * 
XX * DESCRIPTION
XX * 
XX * Given pointer to a pointer to a pattern, uses the pattern pointer to
XX * determine the next character in the pattern, subject to translation of
XX * backslash-char and backslash-octal sequences.
XX * 
XX * The character pointer is updated to point at the next pattern character to be
XX * processed.
XX * 
XX */
XX
XXstatic char
XXnextch(patp)
XX	char          **patp;
XX{
XX	register char   ch;
XX	register char   chsum;
XX	register INT    count;
XX
XX	ch = *(*patp)++;
XX	if (ch == '\\') {
XX		ch = *(*patp)++;
XX		if (IS_OCTAL(ch)) {
XX			chsum = 0;
XX			for (count = 0; count < 3 && IS_OCTAL(ch); count++) {
XX				chsum *= 8;
XX				chsum += ch - '0';
XX				ch = *(*patp)++;
XX			}
XX			(*patp)--;
XX			ch = chsum;
XX		}
XX	}
XX	return (ch);
XX}
XX
XX/*
XX * Filename match - here, * matches everything
XX */
XX
XXint
XXfmatch(direntry)
XX	struct direct  *direntry;
XX{
XX	char           *ptr, *string;
XX
XX	string = direntry->d_name;
XX
XX	if (!strcmp(pattern, "") || !strcmp(pattern, "*.*") || !strcmp(pattern, "*"))
XX		return (1);
XX	return (match(string, pattern));
XX}
XX#else
XX/* dir code for MTS under Bell Labs C... */
XX
XXchar           *
XXdir(filepattern, junk)
XX	char           *filepattern;	/* template or NULL */
XX	INT             junk;	/* unused on MTS */
XX{
XX	char           *malloc(), *index();
XX#ifdef USECATSCAN
XX	fortran         catscan(), fileinfo();
XX
XX	struct catname {
XX		short           len;
XX		char            name[257];
XX	}               pattern;
XX
XX	struct catval {
XX		int             maxlen;
XX		int             actlen;
XX		char            name[257];