mkid 10/11 (identifier cross reference tool)
Tom Horsley
tom at ssd.csd.harris.com
Thu Dec 13 01:48:17 AEST 1990
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 10 (of 11)."
# Contents: mkid.c
# Wrapped by tom at hcx2 on Wed Dec 12 07:21:58 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mkid.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'mkid.c'\"
else
echo shar: Extracting \"'mkid.c'\" \(18541 characters\)
sed "s/^X//" >'mkid.c' <<'END_OF_FILE'
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
Xchar PWDname[BUFSIZ]; /* The current working directory */
Xchar absID[BUFSIZ]; /* The absolute name of the database */
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 if (kshgetwd(PWDname) == NULL) {
X fprintf(stderr,"%s: cannot get current working directory name.\n",MyName);
X exit(1);
X }
X strcat(PWDname, "/");
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 strcpy(absID, spanPath(PWDname, idFile));
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, *filter;
X
X lang = NULL;
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 ((lang = getLanguage(".default")) == 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 filter = getFilter(suff);
X if ((srcFILE = openSrcFILE(arg, sccsDir, rcsDir, filter)) == NULL)
X goto skip;
X if (Verbose)
X if (filter) {
X fprintf(stderr, "%s: ",lang);
X fprintf(stderr, filter, arg);
X fprintf(stderr, "\n");
X } else {
X fprintf(stderr, "%s: %s\n", lang, arg);
X }
X extractId(scanner, srcFILE, idArgs->ida_index);
X closeSrcFILE(srcFILE, filter);
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
X/* As the database is written, may need to adjust the file names.
X * If we are generating the ID file in a remote directory, then
X * adjust the file names to be relative to the location of the
X * ID database.
X *
X * (This would be a common useage if you want to make a database
X * for a directory which you have no write access to, so you cannot
X * create the ID file.)
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 int fixnames;
X char * lsl;
X
X if ((lsl = strrchr(relPath(PWDname, absID),'/')) == NULL) {
X /* The database is in the cwd, don't adjust the names */
X fixnames = FALSE;
X } else {
X /* The database is not in cwd, adjust names so they are
X * relative to the location of the database, make absID
X * just be the directory path to ID.
X */
X fixnames = TRUE;
X *(lsl+1) = '\0';
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 if (fixnames) {
X fputs(relPath(absID,spanPath(PWDname,idArgs->ida_arg)), idFILE);
X } else {
X fputs(idArgs->ida_arg, idFILE);
X }
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 == NULL) || (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}
END_OF_FILE
if test 18541 -ne `wc -c <'mkid.c'`; then
echo shar: \"'mkid.c'\" unpacked with wrong size!
fi
# end of 'mkid.c'
fi
echo shar: End of archive 10 \(of 11\).
cp /dev/null ark10isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 11 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
======================================================================
domain: tahorsley at csd.harris.com USMail: Tom Horsley
uucp: ...!uunet!hcx1!tahorsley 511 Kingbird Circle
Delray Beach, FL 33444
+==== Censorship is the only form of Obscenity ======================+
| (Wait, I forgot government tobacco subsidies...) |
+====================================================================+
More information about the Alt.sources
mailing list