[comp.sources.unix] v11i080: C cross-reference database system, Part03/03

rsalz@uunet.UU.NET (Rich Salz) (09/26/87)

Submitted-by: sun!suneast!kumquat!gmcgary (Greg Mcgary - Sun ECD Software)
Posting-number: Volume 11, Issue 80
Archive-name: id/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 the files:
#	mkid.c
#	numtst.c
#	opensrc.c
#	paths.c
#	scan-asm.c
#	scan-c.c
#	stoi.c
#	tty.c
#	uerror.c
#	wmatch.c
export PATH; PATH=/bin:$PATH
echo shar: extracting "'mkid.c'" '(17095 characters)'
sed 's/^X//' << \SHAR_EOF > 'mkid.c'
Xstatic char copyright[] = "@(#)Copyright (c) 1986, Greg McGary";
Xstatic char sccsid[] = "@(#)mkid.c	1.4 86/11/06";
X
X#include	<bool.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<stdio.h>
X#include	<string.h>
X#include	<ctype.h>
X#include	<id.h>
X#include	<bitops.h>
X#include	<errno.h>
X#include	<extern.h>
X
Xint idnHashCmp();
Xint idnQsortCmp();
Xint round2();
Xstruct idname *newIdName();
Xvoid extractId();
Xvoid fileIdArgs();
Xvoid initHashTable();
Xvoid oldIdArgs();
Xvoid rehash();
Xvoid updateID();
Xvoid writeID();
X
Xlong	NameCount;		/* Count of names in database */
Xlong	NumberCount;		/* Count of numbers in database */
Xlong	StringCount;		/* Count of strings in database */
Xlong	SoloCount;		/* Count of identifiers that occur only once */
X
Xlong	HashSize;		/* Total Slots in hash table */
Xlong	HashMaxLoad;		/* Maximum loading of hash table */
Xlong	HashFill;		/* Number of keys inserted in table */
Xlong	HashProbes;		/* Total number of probes */
Xlong	HashSearches;		/* Total number of searches */
Xstruct idname	**HashTable;	/* Vector of idname pointers */
X
Xbool	Verbose = FALSE;
X
Xint	ArgsCount = 0;		/* Count of args to save */
Xint	ScanCount = 0;		/* Count of files to scan */
Xint	PathCount = 0;		/* Count of files covered in database */
Xint	BitArraySize;		/* Size of bit array slice (per name) */
X
X
Xchar	*MyName;
Xstatic void
Xusage()
X{
X	fprintf(stderr, "Usage: %s [-f<idfile>] [-s<dir>] [-r<dir>] [(+|-)l[<lang>]] [-v] [(+|-)S<scanarg>] [-a<argfile>] [-] [-u] [files...]\n", MyName);
X	exit(1);
X}
Xmain(argc, argv)
X	int		argc;
X	char		**argv;
X{
X	char		*arg;
X	int		op;
X	FILE		*argFILE = NULL;
X	char		*idFile = IDFILE;
X	char		*rcsDir = NULL;
X	char		*sccsDir = NULL;
X	struct idarg	*idArgs, *idArgHead;
X	bool		keepLang = FALSE;
X	int		argsFrom = 0;
X#define	AF_CMDLINE	0x1	/* file args came on command line */
X#define	AF_FILE		0x2	/* file args came from a file (-f<file>) */
X#define	AF_IDFILE	0x4	/* file args came from an old ID file (-u) */
X#define	AF_QUERY	0x8	/* no file args necessary: usage query */
X
X	MyName = basename(GETARG(argc, argv));
X#ifdef ERRLINEBUF
X	setlinebuf(stderr);
X#endif
X
X	idArgs = idArgHead = NEW(struct idarg);
X
X	/*
X		Process some arguments, and snarf-up some
X		others for processing later.
X	*/
X	while (argc) {
X		arg = GETARG(argc, argv);
X		if (*arg != '-' && *arg != '+') {
X			argsFrom |= AF_CMDLINE;
X			idArgs->ida_arg = arg;
X			idArgs->ida_flags = IDA_SCAN|IDA_PATH;
X			idArgs->ida_index = postIncr(&PathCount);
X			ScanCount++;
X			idArgs = (idArgs->ida_next = NEW(struct idarg));
X			continue;
X		}
X		op = *arg++;
X		switch (*arg++)
X		{
X		case 'u':
X			argsFrom |= AF_IDFILE;
X			oldIdArgs(idFile, &idArgs);
X			break;
X		case '\0':
X			argsFrom |= AF_FILE;
X			fileIdArgs(stdin, &idArgs);
X			break;
X		case 'a':
X			if ((argFILE = fopen(arg, "r")) == NULL) {
X				filerr("open", arg);
X				exit(1);
X			}
X			argsFrom |= AF_FILE;
X			fileIdArgs(argFILE, &idArgs);
X			break;
X		case 'f':
X			idFile = arg;
X			break;
X		case 'v':
X			Verbose = TRUE;
X			break;
X		case 'S':
X			if (strchr(&arg[-2], '?')) {
X				setScanArgs(op, arg);
X				argsFrom |= AF_QUERY;
X			}
X			/*FALLTHROUGH*/
X		case 'l':
X		case 's':
X		case 'r':
X			idArgs->ida_arg = &arg[-2];
X			idArgs->ida_index = -1;
X			idArgs->ida_flags = IDA_ARG;
X			idArgs = (idArgs->ida_next = NEW(struct idarg));
X			ArgsCount++;
X			break;
X		default:
X			usage();
X		}
X	}
X
X	if (argsFrom & AF_QUERY)
X		exit(0);
X	/*
X		File args should only come from one place.  Ding the
X		user if arguments came from multiple places, or if none
X		were supplied at all.
X	*/
X	switch (argsFrom)
X	{
X	case AF_CMDLINE:
X	case AF_FILE:
X	case AF_IDFILE:
X		if (PathCount > 0)
X			break;
X		/*FALLTHROUGH*/
X	case 0:
X		fprintf(stderr, "%s: Use -u, -f<file>, or cmd-line for file args!\n", MyName);
X		usage();
X	default:
X		fprintf(stderr, "%s: Use only one of: -u, -f<file>, or cmd-line for file args!\n", MyName);
X		usage();
X	}
X
X	if (ScanCount == 0)
X		exit(0);
X
X	BitArraySize = (PathCount + 7) >> 3;
X	initHashTable(ScanCount);
X
X	if (access(idFile, 06) < 0
X	&& (errno != ENOENT || access(dirname(idFile), 06) < 0)) {
X		filerr("modify", idFile);
X		exit(1);
X	}
X
X	for (idArgs = idArgHead; idArgs->ida_next; idArgs = idArgs->ida_next) {
X		char		*(*scanner)();
X		FILE		*srcFILE;
X		char		*arg, *lang, *suff;
X
X		arg = idArgs->ida_arg;
X		if (idArgs->ida_flags & IDA_ARG) {
X			op = *arg++;
X			switch (*arg++)
X			{
X			case 'l':
X				if (*arg == '\0') {
X					keepLang = FALSE;
X					lang = NULL;
X					break;
X				}
X				if (op == '+')
X					keepLang = TRUE;
X				lang = arg;
X				break;
X			case 's':
X				sccsDir = arg;
X				break;
X			case 'r':
X				rcsDir = arg;
X				break;
X			case 'S':
X				setScanArgs(op, strsav(arg));
X				break;
X			default:
X				usage();
X			}
X			continue;
X		}
X		if (!(idArgs->ida_flags & IDA_SCAN))
X			goto skip;
X		if (lang == NULL) {
X			if ((suff = strrchr(arg, '.')) == NULL)
X				suff = "";
X			if ((lang = getLanguage(suff)) == NULL) {
X				fprintf(stderr, "%s: No language assigned to suffix: `%s'\n", MyName, suff);
X				goto skip;
X			}
X		}
X		if ((scanner = getScanner(lang)) == NULL) {
X			fprintf(stderr, "%s: No scanner for language: `%s'\n", MyName, lang);
X			goto skip;
X		}
X		if ((srcFILE = openSrcFILE(arg, sccsDir, rcsDir)) == NULL)
X			goto skip;
X		if (Verbose)
X			fprintf(stderr, "%s: %s\n", lang, arg);
X		extractId(scanner, srcFILE, idArgs->ida_index);
X		fclose(srcFILE);
X	skip:
X		if (!keepLang)
X			lang = NULL;
X	}
X
X	if (HashFill == 0)
X		exit(0);
X
X	if (Verbose)
X		fprintf(stderr, "Compressing Hash Table...\n");
X	hashCompress(HashTable, HashSize);
X	if (Verbose)
X		fprintf(stderr, "Sorting Hash Table...\n");
X	qsort(HashTable, HashFill, sizeof(struct idname *), idnQsortCmp);
X
X	if (argsFrom == AF_IDFILE) {
X		if (Verbose)
X			fprintf(stderr, "Merging Tables...\n");
X		updateID(idFile, idArgHead);
X	}
X
X	if (Verbose)
X		fprintf(stderr, "Writing `%s'...\n", idFile);
X	writeID(idFile, idArgHead);
X
X	if (Verbose) {
X		float loadFactor = (float)HashFill / (float)HashSize;
X		float aveProbes = (float)HashProbes / (float)HashSearches;
X		float aveOccur = (float)HashSearches / (float)HashFill;
X		fprintf(stderr, "Names: %ld, ", NameCount);
X		fprintf(stderr, "Numbers: %ld, ", NumberCount);
X		fprintf(stderr, "Strings: %ld, ", StringCount);
X		fprintf(stderr, "Solo: %ld, ", SoloCount);
X		fprintf(stderr, "Total: %ld\n", HashFill);
X		fprintf(stderr, "Occurances: %.2f, ", aveOccur);
X		fprintf(stderr, "Load: %.2f, ", loadFactor);
X		fprintf(stderr, "Probes: %.2f\n", aveProbes);
X	}
X	exit(0);
X}
X
Xvoid
XextractId(getId, srcFILE, index)
X	register char	*(*getId)();
X	register FILE	*srcFILE;
X	int		index;
X{
X	register struct idname	**slot;
X	register char	*key;
X	int		flags;
X
X	while ((key = (*getId)(srcFILE, &flags)) != NULL) {
X		slot = (struct idname **)hashSearch(key, HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
X		HashSearches++;
X		if (*slot != NULL) {
X			(*slot)->idn_flags |= flags;
X			BITSET((*slot)->idn_bitv, index);
X			continue;
X		}
X		*slot = newIdName(key);
X		(*slot)->idn_flags = IDN_SOLO|flags;
X		BITSET((*slot)->idn_bitv, index);
X		if (HashFill++ >= HashMaxLoad)
X			rehash();
X	}
X}
X
Xvoid
XwriteID(idFile, idArgs)
X	char		*idFile;
X	struct idarg	*idArgs;
X{
X	register struct idname	**idnp;
X	register struct idname	*idn;
X	register int	i;
X	char		*vecBuf;
X	FILE		*idFILE;
X	int		count;
X	int		lasti;
X	long		before, after;
X	int		length, longest;
X	struct idhead	idh;
X
X	if ((idFILE = fopen(idFile, "w+")) == NULL) {
X		filerr("create", idFile);
X		exit(1);
X	}
X	fseek(idFILE, (long)sizeof(struct idhead), 0);
X
X	/* write out the list of pathnames */
X	idh.idh_argo = ftell(idFILE);
X	for (i = lasti = 0; idArgs->ida_next; idArgs = idArgs->ida_next) {
X		if (idArgs->ida_index > 0)
X			while (++lasti < idArgs->ida_index)
X				i++, putc('\0', idFILE);
X		fputs(idArgs->ida_arg, idFILE);
X		i++, putc('\0', idFILE);
X	}
X	idh.idh_argc = i;
X	idh.idh_pthc = PathCount;
X
X	/* write out the list of identifiers */
X	i = 1;
X	if (idh.idh_pthc >= 0x000000ff)
X		i++;
X	if (idh.idh_pthc >= 0x0000ffff)
X		i++;
X	if (idh.idh_pthc >= 0x00ffffff)
X		i++;
X	idh.idh_vecc = i;
X
X	vecBuf = malloc((idh.idh_pthc + 1) * idh.idh_vecc);
X
X	putc('\377', idFILE);
X	before = idh.idh_namo = ftell(idFILE);
X	longest = 0;
X	for (idnp = HashTable, i = 0; i < HashFill; i++, idnp++) {
X		idn = *idnp;
X		if (idn->idn_name[0] == '\0') {
X			HashFill--; i--;
X			continue;
X		}
X		if (idn->idn_flags & IDN_SOLO)
X			SoloCount++;
X		if (idn->idn_flags & IDN_NUMBER)
X			NumberCount++;
X		if (idn->idn_flags & IDN_NAME)
X			NameCount++;
X		if (idn->idn_flags & IDN_STRING)
X			StringCount++;
X
X		putc((*idnp)->idn_flags, idFILE);
X		fputs(idn->idn_name, idFILE);
X		putc('\0', idFILE);
X
X		count = bitsToVec(vecBuf, (*idnp)->idn_bitv, idh.idh_pthc, idh.idh_vecc);
X		fwrite(vecBuf, idh.idh_vecc, count, idFILE);
X		putc('\377', idFILE);
X		after = ftell(idFILE);
X		
X		if ((length = (after - before)) > longest)
X			longest = length;
X		before = after;
X	}
X	idh.idh_namc = i;
X	putc('\377', idFILE);
X	idh.idh_endo = ftell(idFILE);
X	idh.idh_bsiz = longest;
X
X	/* write out the header */
X	strncpy(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic));
X	idh.idh_vers = IDH_VERS;
X	fseek(idFILE, 0L, 0);
X	fwrite(&idh, sizeof(struct idhead), 1, idFILE);
X
X	fclose(idFILE);
X}
X
X/*
X	Build an idarg vector from pathnames contained in an existing
X	id file.  Only include pathnames for files whose modification
X	time is later than that of the id file itself.
X*/
Xvoid
XoldIdArgs(idFile, idArgsP)
X	char		*idFile;
X	struct idarg	**idArgsP;
X{
X	struct stat	statBuf;
X	struct idhead	idh;
X	FILE		*idFILE;
X	register int	i;
X	register char	*strings;
X	time_t		idModTime;
X
X	if ((idFILE = fopen(idFile, "r")) == NULL) {
X		filerr("open", idFile);
X		usage();
X	}
X	/*
X	*  Open the id file, get its mod-time, and read its header.
X	*/
X	if (fstat(fileno(idFILE), &statBuf) < 0) {
X		filerr("stat", idFile);
X		usage();
X	}
X	idModTime = statBuf.st_mtime;
X	fread(&idh, sizeof(struct idhead), 1, idFILE);
X	if (!strnequ(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic))) {
X		fprintf(stderr, "%s: Not an id file: `%s'\n", MyName, idFile);
X		exit(1);
X	}
X	if (idh.idh_vers != IDH_VERS) {
X		fprintf(stderr, "%s: ID version mismatch (%ld,%ld)\n", MyName, idh.idh_vers, IDH_VERS);
X		exit(1);
X	}
X
X	/*
X	*  Read in the id pathnames, compare their mod-times with
X	*  the id file, and incorporate the pathnames of recently modified 
X	*  files in the idarg vector.  Also, construct a mask of
X	*  bit array positions we want to turn off when we build the
X	*  initial hash-table.
X	*/
X	fseek(idFILE, idh.idh_argo, 0);
X	strings = malloc(i = idh.idh_namo - idh.idh_argo);
X	fread(strings, i, 1, idFILE);
X	ScanCount = 0;
X	for (i = 0; i < idh.idh_argc; i++) {
X		(*idArgsP)->ida_arg = strings;
X		if (*strings == '+' || *strings == '-') {
X			(*idArgsP)->ida_flags = IDA_ARG;
X			(*idArgsP)->ida_index = -1;
X		} else {
X			(*idArgsP)->ida_flags = IDA_PATH;
X			(*idArgsP)->ida_index = postIncr(&PathCount);
X			if (stat(strings, &statBuf) < 0) {
X				filerr("stat", strings);
X			} else if (statBuf.st_mtime >= idModTime) {
X				(*idArgsP)->ida_flags |= IDA_SCAN;
X				ScanCount++;
X			}
X		}
X		(*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
X		while (*strings++)
X			;
X	}
X	if (ScanCount == 0) {
X		fclose(idFILE);
X		exit(0);
X	}
X	fclose(idFILE);
X}
X
Xvoid
XupdateID(idFile, idArgs)
X	char		*idFile;
X	struct idarg	*idArgs;
X{
X	struct idname	*idn;
X	struct idhead	idh;
X	register char	*bitArray;
X	char		*entry;
X	register int	i;
X	FILE		*idFILE;
X	int		cmp, count, size;
X	char		*bitsOff;
X	struct idname	**newTable, **mergeTable;
X	struct idname	**t1, **t2, **tm;
X
X	if ((idFILE = fopen(idFile, "r")) == NULL)
X		filerr("open", idFile);
X	fread(&idh, sizeof(struct idhead), 1, idFILE);
X
X	entry = malloc(idh.idh_bsiz);
X
X	bitsOff = malloc(BitArraySize);
X	bzero(bitsOff, BitArraySize);
X	for (i = 0; idArgs->ida_next; idArgs = idArgs->ida_next)
X		if (idArgs->ida_flags & IDA_SCAN)
X			BITSET(bitsOff, idArgs->ida_index);
X
X	bitArray = malloc(BitArraySize);
X	bzero(bitArray, BitArraySize);
X	t2 = newTable = (struct idname **)malloc((idh.idh_namc + 1) * sizeof(struct idname *));
X	fseek(idFILE, idh.idh_namo, 0);
X	count = 0;
X	for (i = 0; i < idh.idh_namc; i++) {
X		size = 1 + fgets0(entry, idh.idh_bsiz, idFILE);
X		getsFF(&entry[size], idFILE);
X		vecToBits(bitArray, &entry[size], idh.idh_vecc);
X		bitsclr(bitArray, bitsOff, BitArraySize);
X		if (!bitsany(bitArray, BitArraySize))
X			continue;
X		*t2 = newIdName(ID_STRING(entry));
X		bitsset((*t2)->idn_bitv, bitArray, BitArraySize);
X		(*t2)->idn_flags = ID_FLAGS(entry);
X		bzero(bitArray, BitArraySize);
X		t2++; count++;
X	}
X	*t2 = NULL;
X
X	t1 = HashTable;
X	t2 = newTable;
X	tm = mergeTable = (struct idname **)calloc(HashFill + count + 1, sizeof(struct idname *));
X	while (*t1 && *t2) {
X		cmp = strcmp((*t1)->idn_name, (*t2)->idn_name);
X		if (cmp < 0)
X			*tm++ = *t1++;
X		else if (cmp > 0)
X			*tm++ = *t2++;
X		else {
X			(*t1)->idn_flags |= (*t2)->idn_flags;
X			(*t1)->idn_flags &= ~IDN_SOLO;
X			bitsset((*t1)->idn_bitv, (*t2)->idn_bitv, BitArraySize);
X			*tm++ = *t1;
X			t1++, t2++;
X		}
X	}
X	while (*t1)
X		*tm++ = *t1++;
X	while (*t2)
X		*tm++ = *t2++;
X	*tm = NULL;
X	HashTable = mergeTable;
X	HashFill = tm - mergeTable;
X}
X
X/*
X	Cons up a list of idArgs as supplied in a file.
X*/
Xvoid
XfileIdArgs(argFILE, idArgsP)
X	FILE		*argFILE;
X	struct idarg	**idArgsP;
X{
X	int		fileCount;
X	char		buf[BUFSIZ];
X	char		*arg;
X
X	fileCount = 0;
X	while (fgets(buf, sizeof(buf), argFILE)) {
X		(*idArgsP)->ida_arg = arg = strnsav(buf, strlen(buf)-1);
X		if (*arg == '+' || *arg == '-') {
X			(*idArgsP)->ida_flags = IDA_ARG;
X			(*idArgsP)->ida_index = -1;
X		} else {
X			(*idArgsP)->ida_flags = IDA_SCAN|IDA_PATH;
X			(*idArgsP)->ida_index = postIncr(&PathCount);
X			ScanCount++;
X		}
X		(*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
X	}
X}
X
Xvoid
XinitHashTable(pathCount)
X	int		pathCount;
X{
X	if ((HashSize = round2((pathCount << 6) + 511)) > 0x8000)
X		HashSize = 0x8000;
X	HashMaxLoad = HashSize - (HashSize >> 4);	/* about 94% */
X	HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
X}
X
X/*
X	Double the size of the hash table in the
X	event of overflow...
X*/
Xvoid
Xrehash()
X{
X	long		oldHashSize = HashSize;
X	struct idname	**oldHashTable = HashTable;
X	register struct idname	**htp;
X	register struct idname	**slot;
X
X	HashSize *= 2;
X	if (Verbose)
X		fprintf(stderr, "Rehashing... (doubling size to %ld)\n", HashSize);
X	HashMaxLoad = HashSize - (HashSize >> 4);
X	HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
X
X	HashFill = 0;
X	for (htp = oldHashTable; htp < &oldHashTable[oldHashSize]; htp++) {
X		if (*htp == NULL)
X			continue;
X		slot = (struct idname **)hashSearch((*htp)->idn_name, (char *)HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
X		if (*slot) {
X			fprintf(stderr, "%s: Duplicate hash entry!\n");
X			exit(1);
X		}
X		*slot = *htp;
X		HashSearches++;
X		HashFill++;
X	}
X	free(oldHashTable);
X}
X
X/*
X	Round a given number up to the nearest power of 2.
X*/
Xint
Xround2(rough)
X	int		rough;
X{
X	int		round;
X
X	round = 1;
X	while (rough) {
X		round <<= 1;
X		rough >>= 1;
X	}
X	return round;
X}
X
X/*
X	`compar' function for hashSearch()
X*/
Xint
XidnHashCmp(key, idn)
X	char		*key;
X	struct idname	**idn;
X{
X	int		collate;
X
X	if (*idn == NULL)
X		return 0;
X	
X	if ((collate = strcmp(key, (*idn)->idn_name)) == 0)
X		(*idn)->idn_flags &= ~IDN_SOLO;	/* we found another occurance */
X
X	return collate;
X}
X
X/*
X	`compar' function for qsort().
X*/
Xint
XidnQsortCmp(idn1, idn2)
X	struct idname	**idn1;
X	struct idname	**idn2;
X{
X	if (*idn1 == *idn2)
X		return 0;
X	if (*idn1 == NULL)
X		return 1;
X	if (*idn2 == NULL)
X		return -1;
X
X	return strcmp((*idn1)->idn_name, (*idn2)->idn_name);
X}
X
X/*
X	Allocate a new idname struct and fill in the name field.
X	We allocate memory in large chunks to avoid frequent
X	calls to malloc() which is a major pig.
X*/
Xstruct idname *
XnewIdName(name)
X	char		*name;
X{
X	register struct idname	*idn;
X	register char	*allocp;
X	register int	allocsiz;
X	static char	*allocBuf = NULL;
X	static char	*allocEnd = NULL;
X#define	ALLOCSIZ	(8*1024)
X
X	allocsiz = sizeof(struct idname) + strlen(name) + 1 + BitArraySize;
X	allocsiz += (sizeof(long) - 1);
X	allocsiz &= ~(sizeof(long) - 1);
X
X	allocp = allocBuf;
X	allocBuf += allocsiz;
X	if (allocBuf > allocEnd) {
X		allocBuf = malloc(ALLOCSIZ);
X		allocEnd = &allocBuf[ALLOCSIZ];
X		allocp = allocBuf;
X		allocBuf += allocsiz;
X	}
X
X	idn = (struct idname *)allocp;
X	allocp += sizeof(struct idname);
X	idn->idn_bitv = allocp;
X	for (allocsiz = BitArraySize; allocsiz--; allocp++)
X		*allocp = '\0';
X	idn->idn_name = strcpy(allocp, name);
X
X	return idn;
X}
X
Xint
XpostIncr(ip)
X	int		*ip;
X{
X	register int	i;
X	int		save;
X
X	save = *ip;
X	i = save + 1;
X	if ((i & 0x00ff) == 0x00ff)
X		i++;
X	if ((i & 0xff00) == 0xff00)	/* This isn't bloody likely */
X		i += 0x100;
X	*ip = i;
X
X	return save;
X}
X
X/*
X	Move all non-NULL table entries to the front of the table.
X	return the number of non-NULL elements in the table.
X*/
Xint
XhashCompress(table, size)
X	char		**table;
X	int		size;
X{
X	register char	**front;
X	register char	**back;
X
X	front = &table[-1];
X	back = &table[size];
X
X	for (;;) {
X		while (*--back == NULL)
X			;
X		if (back < front)
X			break;
X		while (*++front != NULL)
X			;
X		if (back < front)
X			break;
X		*front = *back;
X	}
X
X	return (back - table + 1);
X}
SHAR_EOF
if test 17095 -ne "`wc -c < 'mkid.c'`"
then
	echo shar: error transmitting "'mkid.c'" '(should have been 17095 characters)'
fi
echo shar: extracting "'numtst.c'" '(60 characters)'
sed 's/^X//' << \SHAR_EOF > 'numtst.c'
X000004
X00010
X012
X020
X04
X0x00004
X0x00010
X0x00a
X0XA
X10
X16
X4
X8
SHAR_EOF
if test 60 -ne "`wc -c < 'numtst.c'`"
then
	echo shar: error transmitting "'numtst.c'" '(should have been 60 characters)'
fi
echo shar: extracting "'opensrc.c'" '(2172 characters)'
sed 's/^X//' << \SHAR_EOF > 'opensrc.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)opensrc.c	1.1 86/10/09";
X
X#include	<stdio.h>
X#include	<string.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X
XFILE *openSrcFILE();
Xchar *getSCCS();
Xchar *coRCS();
X
XFILE *
XopenSrcFILE(path, sccsDir, rcsDir)
X	char		*path;
X	char		*sccsDir;
X	char		*rcsDir;
X{
X	char		*command = NULL;
X	char		*what = NULL;
X	char		*get = "get SCCS file";
X	char		*checkout = "checkout RCS file";
X	char		*dirName;
X	char		*baseName;
X	FILE		*srcFILE;
X
X	if ((srcFILE = fopen(path, "r")) != NULL)
X		return srcFILE;
X
X	if ((baseName = strrchr(path, '/')) == NULL) {
X		dirName = ".";
X		baseName = path;
X	} else {
X		dirName = path;
X		*baseName++ = '\0';
X	}
X
X	if (rcsDir && (command = coRCS(dirName, baseName, rcsDir)))
X		what = checkout;
X	else if (sccsDir && (command = getSCCS(dirName, baseName, sccsDir)))
X		what = get;
X	else if ((command = coRCS(dirName, baseName, "RCS"))
X	     ||  (command = coRCS(dirName, baseName, ".")))
X		what = checkout;
X	else if ((command = getSCCS(dirName, baseName, "SCCS"))
X	     ||  (command = getSCCS(dirName, baseName, "sccs"))
X	     ||  (command = getSCCS(dirName, baseName, ".")))
X		what = get;
X
X	if (dirName == path)
X		*--baseName = '/';
X
X	if (!command) {
X		filerr("open", path);
X		return NULL;
X	}
X
X	system(command);
X	if ((srcFILE = fopen(path, "r")) == NULL) {
X		filerr("open", path);
X		return NULL;
X	}
X
X	fprintf(stderr, "%s\n", command);
X	return srcFILE;
X}
X
Xchar *
XgetSCCS(dir, base, sccsDir)
X	char		*dir;
X	char		*base;
X	char		*sccsDir;
X{
X	static char	cmdBuf[BUFSIZ];
X	char		fileBuf[BUFSIZ];
X	struct stat	statBuf;
X
X	if (!*sccsDir)
X		sccsDir = ".";
X
X	sprintf(fileBuf, "%s/%s/s.%s", dir, sccsDir, base);
X	if (stat(fileBuf, &statBuf) < 0)
X		return NULL;
X	sprintf(cmdBuf, "cd %s; get -s %s/s.%s", dir, sccsDir, base);
X
X	return cmdBuf;
X}
X
Xchar *
XcoRCS(dir, base, rcsDir)
X	char		*dir;
X	char		*base;
X	char		*rcsDir;
X{
X	static char	cmdBuf[BUFSIZ];
X	char		fileBuf[BUFSIZ];
X	struct stat	statBuf;
X
X	if (!*rcsDir)
X		rcsDir = ".";
X
X	sprintf(fileBuf, "%s/%s/%s,v", dir, rcsDir, base);
X	if (stat(fileBuf, &statBuf) < 0)
X		return NULL;
X	sprintf(cmdBuf, "cd %s; co -q %s/%s,v", dir, rcsDir, base);
X
X	return cmdBuf;
X}
SHAR_EOF
if test 2172 -ne "`wc -c < 'opensrc.c'`"
then
	echo shar: error transmitting "'opensrc.c'" '(should have been 2172 characters)'
fi
echo shar: extracting "'paths.c'" '(3629 characters)'
sed 's/^X//' << \SHAR_EOF > 'paths.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)paths.c	1.1 86/10/09";
X
X#include	<bool.h>
X#include	<stdio.h>
X#include	<string.h>
X
Xbool canCrunch();
Xchar *getDirToName();
Xchar *rootName();
Xchar *skipJunk();
Xchar *spanPath();
Xchar *suffName();
X
Xchar *
XspanPath(dir, arg)
X	char		*dir;
X	char		*arg;
X{
X	static char	pathBuf[BUFSIZ];
X	char		*path;
X	char		*argTail;
X	char		*dirTail;
X	int		argLength;
X	int		dirLength;
X
X	for (dirTail = &dir[strlen(dir)-1]; *dirTail == '/'; dirTail--)
X		*dirTail = '\0';
X	for (;;) {
X		dir = skipJunk(dir);
X		if ((dirTail = strchr(dir, '/')) == NULL)
X			dirTail = &dir[strlen(dir)];
X		dirLength = dirTail - dir;
X
X		arg = skipJunk(arg);
X		if ((argTail = strchr(arg, '/')) == NULL)
X			break;
X		argLength = argTail - arg;
X
X		if (argLength != dirLength)
X			break;
X		if (!strnequ(arg, dir, argLength))
X			break;
X		arg = argTail;
X		dir = dirTail;
X	}
X
X	(path = pathBuf)[0] = '\0';
X	for (; dir && *dir; dir = skipJunk(strchr(dir, '/'))) {
X		strcpy(path, "../");
X		path += 3;
X	}
X	strcat(path, arg);
X	return pathBuf;
X}
X
Xchar *
XskipJunk(path)
X	char		*path;
X{
X	if (path == NULL)
X		return NULL;
X	while (*path == '/')
X		path++;
X	while (path[0] == '.' && path[1] == '/') {
X		path += 2;
X		while (*path == '/')
X			path++;
X	}
X	if (strequ(path, "."))
X		path++;
X	
X	return path;
X}
X
Xchar *
XrootName(path)
X	char		*path;
X{
X	static char	pathBuf[BUFSIZ];
X	char		*root;
X	char		*dot;
X
X	if ((root = strrchr(path, '/')) == NULL)
X		root = path;
X	else
X		root++;
X	
X	if ((dot = strrchr(root, '.')) == NULL)
X		strcpy(pathBuf, root);
X	else {
X		strncpy(pathBuf, root, dot - root);
X		pathBuf[dot - root] = '\0';
X	}
X	return pathBuf;
X}
X
Xchar *
XsuffName(path)
X	char		*path;
X{
X	char		*dot;
X
X	if ((dot = strrchr(path, '.')) == NULL)
X		return "";
X	return dot;
X}
X
Xbool
XcanCrunch(path1, path2)
X	char		*path1;
X	char		*path2;
X{
X	char		*slash1;
X	char		*slash2;
X
X	slash1 = strrchr(path1, '/');
X	slash2 = strrchr(path2, '/');
X
X	if (slash1 == NULL && slash2 == NULL)
X		return strequ(suffName(path1), suffName(path2));
X	if ((slash1 - path1) != (slash2 - path2))
X		return FALSE;
X	if (!strnequ(path1, path2, slash1 - path1))
X		return FALSE;
X	return strequ(suffName(slash1), suffName(slash2));
X}
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#ifdef NDIR
X#include	<ndir.h>
X#else
X#include	<sys/dir.h>
X#endif
X
Xstatic char	dot[]	 = ".";
Xstatic char	dotdot[] = "..";
X
X/*
X	Return our directory name relative to the first parent dir
X	that contains a file with a name that matches `topName'.
X	Fail if we hit the root, or if any dir in our way is unreadable.
X*/
Xchar *
XgetDirToName(topName)
X	char		*topName;
X{
X	register struct direct	*dirp;
X	register DIR	*dirdp;
X	static char	nameBuf[BUFSIZ];
X	char		*name;
X	struct	stat	dStat;
X	struct	stat	ddStat;
X
X	name = &nameBuf[sizeof(nameBuf)-1];
X	*name = '\0';
X	for (;;) {
X		if (stat(topName, &dStat) == 0) {
X			if (!*name)
X				name = dot;
X			else
X				chdir(name);
X			return name;
X		} if (stat(dot, &dStat) < 0)
X			return NULL;
X		if ((dirdp = opendir(dotdot)) == NULL)
X			return NULL;
X		if (fstat(dirdp->dd_fd, &ddStat) < 0)
X			return NULL;
X		if (chdir(dotdot) < 0)
X			return NULL;
X		if (dStat.st_dev == ddStat.st_dev) {
X			if (dStat.st_ino == ddStat.st_ino)
X				return NULL;
X			do {
X				if ((dirp = readdir(dirdp)) == NULL)
X					return NULL;
X			} while (dirp->d_ino != dStat.st_ino);
X		} else {
X			do {
X				if ((dirp = readdir(dirdp)) == NULL)
X					return NULL;
X				stat(dirp->d_name, &ddStat);
X			} while (ddStat.st_ino != dStat.st_ino || ddStat.st_dev != dStat.st_dev);
X		}
X		closedir(dirdp);
X	
X		if (*name != '\0')
X			*--name = '/';
X		name -= dirp->d_namlen;
X		strncpy(name, dirp->d_name, dirp->d_namlen);
X	}
X}
SHAR_EOF
if test 3629 -ne "`wc -c < 'paths.c'`"
then
	echo shar: error transmitting "'paths.c'" '(should have been 3629 characters)'
fi
echo shar: extracting "'scan-asm.c'" '(6157 characters)'
sed 's/^X//' << \SHAR_EOF > 'scan-asm.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)scan-asm.c	1.2 86/11/06";
X
X#include	<bool.h>
X#include	<stdio.h>
X#include	<string.h>
X#include	<ctype.h>
X#include	<id.h>
X
Xchar *getAsmId();
Xvoid setAsmArgs();
X
Xstatic void clrCtype();
Xstatic void setCtype();
X
X#define	I1	0x01	/* 1st char of an identifier [a-zA-Z_] */
X#define	NM	0x02	/* digit [0-9a-fA-FxX] */
X#define	NL	0x04	/* newline: \n */
X#define	CM	0x08	/* assembler comment char: usually # or | */
X#define	IG	0x10	/* ignore `identifiers' with these chars in them */
X#define	C1	0x20	/* C comment introduction char: / */
X#define	C2	0x40	/* C comment termination  char: * */
X#define	EF	0x80	/* EOF */
X
X/* Assembly Language character classes */
X#define	ISID1ST(c)	((rct)[c]&(I1))
X#define	ISIDREST(c)	((rct)[c]&(I1|NM))
X#define	ISNUMBER(c)	((rct)[c]&(NM))
X#define	ISEOF(c)	((rct)[c]&(EF))
X#define	ISCOMMENT(c)	((rct)[c]&(CM))
X#define	ISBORING(c)	(!((rct)[c]&(EF|NL|I1|NM|CM|C1)))
X#define	ISCBORING(c)	(!((rct)[c]&(EF|NL)))
X#define	ISCCBORING(c)	(!((rct)[c]&(EF|C2)))
X#define	ISIGNORE(c)	((rct)[c]&(IG))
X
Xstatic char idctype[] = {
X
X	EF,
X
X	/*      0       1       2       3       4       5       6       7   */
X	/*    -----   -----   -----   -----   -----   -----   -----   ----- */
X
X	/*000*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*010*/	0,	0,	NL,	0,	0,	0,	0,	0,
X	/*020*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*030*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*040*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*050*/	0,	0,	C2,	0,	0,	0,	0,	C1,
X	/*060*/	NM,	NM,	NM,	NM,	NM,	NM,	NM,	NM,	
X	/*070*/	NM,	NM,	0,	0,	0,	0,	0,	0,
X	/*100*/	0,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1,
X	/*110*/	I1,	I1,	I1,	I1,	I1|NM,	I1,	I1,	I1,
X	/*120*/	I1,	I1,	I1,	I1,	I1,	I1,	I1,	I1,
X	/*130*/	I1|NM,	I1,	I1,	0,	0,	0,	0,	I1,
X	/*140*/	0,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1,
X	/*150*/	I1,	I1,	I1,	I1,	I1|NM,	I1,	I1,	I1,
X	/*160*/	I1,	I1,	I1,	I1,	I1,	I1,	I1,	I1,
X	/*170*/	I1|NM,	I1,	I1,	0,	0,	0,	0,	0,
X
X	/*200*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*210*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*220*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*230*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*240*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*250*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*260*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*270*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*300*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*310*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*320*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*330*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*340*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*350*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*360*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*370*/	0,	0,	0,	0,	0,	0,	0,	0,
X
X};
X
Xstatic bool eatUnder = TRUE;
Xstatic bool preProcess = TRUE;
X
X/*
X	Grab the next identifier the assembly language
X	source file opened with the handle `inFILE'.
X	This state machine is built for speed, not elegance.
X*/
Xchar *
XgetAsmId(inFILE, flagP)
X	FILE		*inFILE;
X	int		*flagP;
X{
X	static char	idBuf[BUFSIZ];
X	register char	*rct = &idctype[1];
X	register int	c;
X	register char	*id = idBuf;
X	static bool	newLine = TRUE;
X
Xtop:
X	c = getc(inFILE);
X	if (preProcess > 0 && newLine) {
X		newLine = FALSE;
X		if (c != '#')
X			goto next;
X		while (ISBORING(c))
X			c = getc(inFILE);
X		if (!ISID1ST(c))
X			goto next;
X		id = idBuf;
X		*id++ = c;
X		while (ISIDREST(c = getc(inFILE)))
X			*id++ = c;
X		*id = '\0';
X		if (strequ(idBuf, "include")) {
X			while (c != '"' && c != '<')
X				c = getc(inFILE);
X			id = idBuf;
X			*id++ = c = getc(inFILE);
X			while ((c = getc(inFILE)) != '"' && c != '>')
X				*id++ = c;
X			*id = '\0';
X			*flagP = IDN_STRING;
X			return idBuf;
X		}
X		if (strnequ(idBuf, "if", 2)
X		|| strequ(idBuf, "define")
X		|| strequ(idBuf, "undef"))
X			goto next;
X		while (c != '\n')
X			c = getc(inFILE);
X		newLine = TRUE;
X		goto top;
X	}
X
Xnext:
X	while (ISBORING(c))
X		c = getc(inFILE);
X
X	if (ISCOMMENT(c)) {
X		while (ISCBORING(c))
X			c = getc(inFILE);
X		newLine = TRUE;
X	}
X
X	if (ISEOF(c)) {
X		newLine = TRUE;
X		return NULL;
X	}
X
X	if (c == '\n') {
X		newLine = TRUE;
X		goto top;
X	}
X
X	if (c == '/') {
X		if ((c = getc(inFILE)) != '*')
X			goto next;
X		c = getc(inFILE);
X		for (;;) {
X			while (ISCCBORING(c))
X				c = getc(inFILE);
X			if ((c = getc(inFILE)) == '/') {
X				c = getc(inFILE);
X				break;
X			} else if (ISEOF(c)) {
X				newLine = TRUE;
X				return NULL;
X			}
X		}
X		goto next;
X	}
X
X	id = idBuf;
X	if (eatUnder && c == '_' && !ISID1ST(c = getc(inFILE))) {
X		ungetc(c, inFILE);
X		return "_";
X	}
X	*id++ = c;
X	if (ISID1ST(c)) {
X		*flagP = IDN_NAME;
X		while (ISIDREST(c = getc(inFILE)))
X			*id++ = c;
X	} else if (ISNUMBER(c)) {
X		*flagP = IDN_NUMBER;
X		while (ISNUMBER(c = getc(inFILE)))
X			*id++ = c;
X	} else {
X		if (isprint(c))
X			fprintf(stderr, "junk: `%c'", c);
X		else
X			fprintf(stderr, "junk: `\\%03o'", c);
X		goto next;
X	}
X
X	*id = '\0';
X	for (id = idBuf; *id; id++)
X		if (ISIGNORE(*id))
X			goto next;
X	ungetc(c, inFILE);
X	*flagP |= IDN_LITERAL;
X	return idBuf;
X}
X
Xstatic void
XsetCtype(chars, type)
X	char		*chars;
X	int		type;
X{
X	char		*rct = &idctype[1];
X
X	while (*chars)
X		rct[*chars++] |= type;
X}
Xstatic void
XclrCtype(chars, type)
X	char		*chars;
X	int		type;
X{
X	char		*rct = &idctype[1];
X
X	while (*chars)
X		rct[*chars++] &= ~type;
X}
X
Xextern char	*MyName;
Xstatic void
Xusage(lang)
X	char		*lang;
X{
X	fprintf(stderr, "Usage: %s -S%s([-c<cc>] [-u] [(+|-)a<cc>] [(+|-)p] [(+|-)C])\n", MyName, lang);
X	exit(1);
X}
Xstatic char *asmDocument[] =
X{
X"The Assembler scanner arguments take the form -Sasm<arg>, where",
X"<arg> is one of the following: (<cc> denotes one or more characters)",
X"  -c<cc> . . . . <cc> introduce(s) a comment until end-of-line.",
X"  (+|-)u . . . . (Do|Don't) strip a leading `_' from ids.",
X"  (+|-)a<cc> . . Allow <cc> in ids, and (keep|ignore) those ids.",
X"  (+|-)p . . . . (Do|Don't) handle C-preprocessor directives.",
X"  (+|-)C . . . . (Do|Don't) handle C-style comments. (/* */)",
XNULL
X};
Xvoid
XsetAsmArgs(lang, op, arg)
X	char		*lang;
X	int		op;
X	char		*arg;
X{
X	if (op == '?') {
X		document(asmDocument);
X		return;
X	}
X	switch (*arg++)
X	{
X	case 'a':
X		setCtype(arg, I1|((op == '-') ? IG : 0));
X		break;
X	case 'c':
X		setCtype(arg, CM);
X		break;
X	case 'u':
X		eatUnder = (op == '+');
X		break;
X	case 'p':
X		preProcess = (op == '+');
X		break;
X	case 'C':
X		if (op == '+') {
X			setCtype("/", C1);
X			setCtype("*", C2);
X		} else {
X			clrCtype("/", C1);
X			clrCtype("*", C2);
X		}
X		break;
X	default:
X		if (lang)
X			usage(lang);
X		break;
X	}
X}
SHAR_EOF
if test 6157 -ne "`wc -c < 'scan-asm.c'`"
then
	echo shar: error transmitting "'scan-asm.c'" '(should have been 6157 characters)'
fi
echo shar: extracting "'scan-c.c'" '(6502 characters)'
sed 's/^X//' << \SHAR_EOF > 'scan-c.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)scan-c.c	1.1 86/10/09";
X
X#include	<bool.h>
X#include	<stdio.h>
X#include	<string.h>
X#include	<id.h>
X
Xchar *getCId();
Xvoid setCArgs();
X
Xstatic void clrCtype();
Xstatic void setCtype();
X
X#define	I1	0x0001	/* 1st char of an identifier [a-zA-Z_] */
X#define	DG	0x0002	/* decimal digit [0-9] */
X#define	NM	0x0004	/* extra chars in a hex or long number [a-fA-FxXlL] */
X#define	C1	0x0008	/* C comment introduction char: / */
X#define	C2	0x0010	/* C comment termination  char: * */
X#define	Q1	0x0020	/* single quote: ' */
X#define	Q2	0x0040	/* double quote: " */
X#define	ES	0x0080	/* escape char: \ */
X#define	NL	0x0100	/* newline: \n */
X#define	EF	0x0200	/* EOF */
X#define	SK	0x0400	/* Make these chars valid for names within strings */
X
X/*
X	character class membership macros:
X*/
X#define	ISDIGIT(c)	((rct)[c]&(DG))		/* digit */
X#define	ISNUMBER(c)	((rct)[c]&(DG|NM))	/* legal in a number */
X#define	ISEOF(c)	((rct)[c]&(EF))		/* EOF */
X#define	ISID1ST(c)	((rct)[c]&(I1))		/* 1st char of an identifier */
X#define	ISIDREST(c)	((rct)[c]&(I1|DG))	/* rest of an identifier */
X#define	ISSTRKEEP(c)	((rct)[c]&(I1|DG|SK))	/* keep contents of string */
X/*
X	The `BORING' classes should be skipped over
X	until something interesting comes along...
X*/
X#define	ISBORING(c)	(!((rct)[c]&(EF|NL|I1|DG|Q1|Q2|C1)))	/* fluff */
X#define	ISCBORING(c)	(!((rct)[c]&(EF|C2)))	/* comment fluff */
X#define	ISQ1BORING(c)	(!((rct)[c]&(EF|NL|Q1|ES)))	/* char const fluff */
X#define	ISQ2BORING(c)	(!((rct)[c]&(EF|NL|Q2|ES)))	/* quoted str fluff */
X
Xstatic short idctype[] = {
X
X	EF,
X
X	/*      0       1       2       3       4       5       6       7   */
X	/*    -----   -----   -----   -----   -----   -----   -----   ----- */
X
X	/*000*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*010*/	0,	0,	NL,	0,	0,	0,	0,	0,
X	/*020*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*030*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*040*/	0,	0,	Q2,	0,	0,	0,	0,	Q1,
X	/*050*/	0,	0,	C2,	0,	0,	0,	0,	C1,
X	/*060*/	DG,	DG,	DG,	DG,	DG,	DG,	DG,	DG,	
X	/*070*/	DG,	DG,	0,	0,	0,	0,	0,	0,
X	/*100*/	0,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1,
X	/*110*/	I1,	I1,	I1,	I1,	I1|NM,	I1,	I1,	I1,
X	/*120*/	I1,	I1,	I1,	I1,	I1,	I1,	I1,	I1,
X	/*130*/	I1|NM,	I1,	I1,	0,	ES,	0,	0,	I1,
X	/*140*/	0,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1|NM,	I1,
X	/*150*/	I1,	I1,	I1,	I1,	I1|NM,	I1,	I1,	I1,
X	/*160*/	I1,	I1,	I1,	I1,	I1,	I1,	I1,	I1,
X	/*170*/	I1|NM,	I1,	I1,	0,	0,	0,	0,	0,
X
X	/*200*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*210*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*220*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*230*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*240*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*250*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*260*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*270*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*300*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*310*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*320*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*330*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*340*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*350*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*360*/	0,	0,	0,	0,	0,	0,	0,	0,
X	/*370*/	0,	0,	0,	0,	0,	0,	0,	0,
X
X};
X
Xstatic bool eatUnder = TRUE;
X
X/*
X	Grab the next identifier the C source
X	file opened with the handle `inFILE'.
X	This state machine is built for speed, not elegance.
X*/
Xchar *
XgetCId(inFILE, flagP)
X	FILE		*inFILE;
X	int		*flagP;
X{
X	static char	idBuf[BUFSIZ];
X	static bool	newLine = TRUE;
X	register short	*rct = &idctype[1];
X	register int	c;
X	register char	*id = idBuf;
X
Xtop:
X	c = getc(inFILE);
X	if (newLine) {
X		newLine = FALSE;
X		if (c != '#')
X			goto next;
X		while (ISBORING(c))
X			c = getc(inFILE);
X		if (!ISID1ST(c))
X			goto next;
X		id = idBuf;
X		*id++ = c;
X		while (ISIDREST(c = getc(inFILE)))
X			*id++ = c;
X		*id = '\0';
X		if (strequ(idBuf, "include")) {
X			while (c != '"' && c != '<')
X				c = getc(inFILE);
X			id = idBuf;
X			*id++ = c = getc(inFILE);
X			while ((c = getc(inFILE)) != '"' && c != '>')
X				*id++ = c;
X			*id = '\0';
X			*flagP = IDN_STRING;
X			return idBuf;
X		}
X		if (strnequ(idBuf, "if", 2)
X		|| strequ(idBuf, "define")
X		|| strequ(idBuf, "undef"))
X			goto next;
X		while (c != '\n')
X			c = getc(inFILE);
X		newLine = TRUE;
X		goto top;
X	}
X
Xnext:
X	while (ISBORING(c))
X		c = getc(inFILE);
X
X	switch (c)
X	{
X	case '"':
X		id = idBuf;
X		*id++ = c = getc(inFILE);
X		for (;;) {
X			while (ISQ2BORING(c))
X				*id++ = c = getc(inFILE);
X			if (c == '\\') {
X				*id++ = c = getc(inFILE);
X				continue;
X			} else if (c != '"')
X				goto next;
X			break;
X		}
X		*--id = '\0';
X		id = idBuf;
X		while (ISSTRKEEP(*id))
X			id++;
X		if (*id || id == idBuf) {
X			c = getc(inFILE);
X			goto next;
X		}
X		*flagP = IDN_STRING;
X		if (eatUnder && idBuf[0] == '_' && idBuf[1])
X			return &idBuf[1];
X		else
X			return idBuf;
X		
X	case '\'':
X		c = getc(inFILE);
X		for (;;) {
X			while (ISQ1BORING(c))
X				c = getc(inFILE);
X			if (c == '\\') {
X				c = getc(inFILE);
X				continue;
X			} else if (c == '\'')
X				c = getc(inFILE);
X			goto next;
X		}
X
X	case '/':
X		if ((c = getc(inFILE)) != '*')
X			goto next;
X		c = getc(inFILE);
X		for (;;) {
X			while (ISCBORING(c))
X				c = getc(inFILE);
X			if ((c = getc(inFILE)) == '/') {
X				c = getc(inFILE);
X				goto next;
X			} else if (ISEOF(c)) {
X				newLine = TRUE;
X				return NULL;
X			}
X		}
X
X	case '\n':
X		newLine = TRUE;
X		goto top;
X
X	default:
X		if (ISEOF(c)) {
X			newLine = TRUE;
X			return NULL;
X		}
X	name:
X		id = idBuf;
X		*id++ = c;
X		if (ISID1ST(c)) {
X			*flagP = IDN_NAME;
X			while (ISIDREST(c = getc(inFILE)))
X				*id++ = c;
X		} else if (ISDIGIT(c)) {
X			*flagP = IDN_NUMBER;
X			while (ISNUMBER(c = getc(inFILE)))
X				*id++ = c;
X		} else
X			fprintf(stderr, "junk: `\\%3o'", c);
X		ungetc(c, inFILE);
X		*id = '\0';
X		*flagP |= IDN_LITERAL;
X		return idBuf;
X	}
X}
X
Xstatic void
XsetCtype(chars, type)
X	char		*chars;
X	int		type;
X{
X	short		*rct = &idctype[1];
X
X	while (*chars)
X		rct[*chars++] |= type;
X}
Xstatic void
XclrCtype(chars, type)
X	char		*chars;
X	int		type;
X{
X	short		*rct = &idctype[1];
X
X	while (*chars)
X		rct[*chars++] &= ~type;
X}
X
Xextern char	*MyName;
Xstatic void
Xusage(lang)
X	char		*lang;
X{
X	fprintf(stderr, "Usage: %s does not accept %s scanner arguments\n", MyName, lang);
X	exit(1);
X}
Xstatic char *cDocument[] =
X{
X"The C scanner arguments take the form -Sc<arg>, where <arg>",
X"is one of the following: (<cc> denotes one or more characters)",
X"  (+|-)u . . . . (Do|Don't) strip a leading `_' from ids in strings.",
X"  -s<cc> . . . . Allow <cc> in string ids.",
XNULL
X};
Xvoid
XsetCArgs(lang, op, arg)
X	char		*lang;
X	int		op;
X	char		*arg;
X{
X	if (op == '?') {
X		document(cDocument);
X		return;
X	}
X	switch (*arg++)
X	{
X	case 'u':
X		eatUnder = (op == '+');
X		break;
X	case 's':
X		setCtype(arg, SK);
X		break;
X	default:
X		if (lang)
X			usage(lang);
X		break;
X	}
X}
SHAR_EOF
if test 6502 -ne "`wc -c < 'scan-c.c'`"
then
	echo shar: error transmitting "'scan-c.c'" '(should have been 6502 characters)'
fi
echo shar: extracting "'stoi.c'" '(1883 characters)'
sed 's/^X//' << \SHAR_EOF > 'stoi.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)stoi.c	1.1 86/10/09";
X
X#include	<radix.h>
X#include	<ctype.h>
X
Xint dtoi();
Xint otoi();
Xint radix();
Xint stoi();
Xint xtoi();
X
X/*
X	Use the C lexical rules to determine an ascii number's radix.
X	The radix is returned as a bit map, so that more than one radix
X	may apply.  In particular, it is impossible to determine the
X	radix of 0, so return all possibilities.
X*/
Xint
Xradix(name)
X	register char	*name;
X{
X	if (!isdigit(*name))
X		return 0;
X	if (*name != '0')
X		return RADIX_DEC;
X	name++;
X	if (*name == 'x' || *name == 'X')
X		return RADIX_HEX;
X	while (*name && *name == '0')
X		name++;
X	return (RADIX_OCT | ((*name)?0:RADIX_DEC));
X}
X
X/*
X	Convert an ascii string number to an integer.
X	Determine the radix before converting.
X*/
Xint
Xstoi(name)
X	char		*name;
X{
X	switch (radix(name))
X	{
X	case RADIX_DEC:	return(dtoi(name));
X	case RADIX_OCT:	return(otoi(&name[1]));
X	case RADIX_HEX:	return(xtoi(&name[2]));
X	case RADIX_DEC|RADIX_OCT: return(0);
X	default:	return(-1);
X	}
X}
X
X/*
X	Convert an ascii octal number to an integer.
X*/
Xint
Xotoi(name)
X	char		*name;
X{
X	register int	n = 0;
X
X	while (*name >= '0' && *name <= '7') {
X		n *= 010;
X		n += *name++ - '0';
X	}
X	if (*name == 'l' || *name == 'L')
X		name++;
X	return (*name ? -1 : n);
X}
X
X/*
X	Convert an ascii decimal number to an integer.
X*/
Xint
Xdtoi(name)
X	char		*name;
X{
X	register int	n = 0;
X
X	while (isdigit(*name)) {
X		n *= 10;
X		n += *name++ - '0';
X	}
X	if (*name == 'l' || *name == 'L')
X		name++;
X	return (*name ? -1 : n);
X}
X
X/*
X	Convert an ascii hex number to an integer.
X*/
Xint
Xxtoi(name)
X	char		*name;
X{
X	register int	n = 0;
X
X	while (isxdigit(*name)) {
X		n *= 0x10;
X		if (isdigit(*name))
X			n += *name++ - '0';
X		else if (islower(*name))
X			n += 0xa + *name++ - 'a';
X		else
X			n += 0xA + *name++ - 'A';
X	}
X	if (*name == 'l' || *name == 'L')
X		name++;
X	return (*name ? -1 : n);
X}
SHAR_EOF
if test 1883 -ne "`wc -c < 'stoi.c'`"
then
	echo shar: error transmitting "'stoi.c'" '(should have been 1883 characters)'
fi
echo shar: extracting "'tty.c'" '(1114 characters)'
sed 's/^X//' << \SHAR_EOF > 'tty.c'
X#ifdef TERMIO
X#include	<sys/termio.h>
X
Xstruct termio linemode, charmode, savemode;
X
Xsavetty()
X{
X	ioctl(0, TCGETA, &savemode);
X	charmode = linemode = savemode;
X
X	charmode.c_lflag &= ~(ECHO|ICANON|ISIG);
X	charmode.c_cc[VMIN] = 1;
X	charmode.c_cc[VTIME] = 0;
X
X	linemode.c_lflag |= (ECHO|ICANON|ISIG);
X	linemode.c_cc[VEOF] = 'd'&037;
X	linemode.c_cc[VEOL] = 0377;
X}
X
Xrestoretty()
X{
X	ioctl(0, TCSETA, &savemode);
X}
X
Xlinetty()
X{
X	ioctl(0, TCSETA, &linemode);
X}
X
Xchartty()
X{
X	ioctl(0, TCSETA, &charmode);
X}
X
X#else
X#include	<sgtty.h>
X
Xstruct sgttyb linemode, charmode, savemode;
X
Xsavetty()
X{
X#ifdef TIOCGETP
X	ioctl(0, TIOCGETP, &savemode);
X#else
X	gtty(0, &savemode);
X#endif
X	charmode = linemode = savemode;
X
X	charmode.sg_flags &= ~ECHO;
X	charmode.sg_flags |= RAW;
X
X	linemode.sg_flags |= ECHO;
X	linemode.sg_flags &= ~RAW;
X}
X
Xrestoretty()
X{
X#ifdef TIOCSETP
X	ioctl(0, TIOCSETP, &savemode);
X#else
X	stty(0, &savemode);
X#endif
X}
X
Xlinetty()
X{
X#ifdef TIOCSETP
X	ioctl(0, TIOCSETP, &linemode);
X#else
X	stty(0, &savemode);
X#endif
X}
X
Xchartty()
X{
X#ifdef TIOCSETP
X	ioctl(0, TIOCSETP, &charmode);
X#else
X	stty(0, &savemode);
X#endif
X}
X#endif
SHAR_EOF
if test 1114 -ne "`wc -c < 'tty.c'`"
then
	echo shar: error transmitting "'tty.c'" '(should have been 1114 characters)'
fi
echo shar: extracting "'uerror.c'" '(586 characters)'
sed 's/^X//' << \SHAR_EOF > 'uerror.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)uerror.c	1.1 86/10/09";
X
X#include	<stdio.h>
X
Xchar *uerror();
Xvoid filerr();
X
Xextern int	errno;
Xextern int	sys_nerr;
Xextern char	*sys_errlist[];
Xextern char	*MyName;
X
Xchar	cannot[] = "%s: Cannot %s `%s' (%s)\n";
X
Xchar *
Xuerror()
X{
X	static char	errbuf[10];
X
X	if (errno == 0 || errno >= sys_nerr) {
X		sprintf(errbuf, "error %d", errno);
X		return(errbuf);
X	}
X	return(sys_errlist[errno]);
X}
X
Xvoid
Xfilerr(syscall, fileName)
X	char		*syscall;
X	char		*fileName;
X{
X	fprintf(stderr, cannot, MyName, syscall, fileName, uerror());
X}
SHAR_EOF
if test 586 -ne "`wc -c < 'uerror.c'`"
then
	echo shar: error transmitting "'uerror.c'" '(should have been 586 characters)'
fi
echo shar: extracting "'wmatch.c'" '(830 characters)'
sed 's/^X//' << \SHAR_EOF > 'wmatch.c'
X/* Copyright (c) 1986, Greg McGary */
Xstatic char sccsid[] = "@(#)wmatch.c	1.1 86/10/09";
X
X#include	<bool.h>
X#include	<ctype.h>
X
Xbool wordMatch();
X
X/*
X	Does `name' occur in `line' delimited by non-alphanumerics??
X*/
Xbool
XwordMatch(name0, line)
X	char		*name0;
X	register char	*line;
X{
X	register char	*name = name0;
X#define IS_ALNUM(c)	(isalnum(c) || (c) == '_')
X
X	for (;;) {
X		/* find an initial-character match */
X		while (*line != *name) {
X			if (*line == '\n')
X				return FALSE;
X			line++;
X		}
X		/* do we have a word delimiter on the left ?? */
X		if (IS_ALNUM(line[-1])) {
X			line++;
X			continue;
X		}
X		/* march down both strings as long as we match */
X		while (*++name == *++line)
X			;
X		/* is this the end of `name', is there a word delimiter ?? */
X		if (*name == '\0' && !IS_ALNUM(*line))
X			return TRUE;
X		name = name0;
X	}
X}
SHAR_EOF
if test 830 -ne "`wc -c < 'wmatch.c'`"
then
	echo shar: error transmitting "'wmatch.c'" '(should have been 830 characters)'
fi
#	End of shell archive
exit 0