home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / id / part03 / mkid.c next >
C/C++ Source or Header  |  1987-09-25  |  17KB  |  747 lines

  1. static char copyright[] = "@(#)Copyright (c) 1986, Greg McGary";
  2. static char sccsid[] = "@(#)mkid.c    1.4 86/11/06";
  3.  
  4. #include    <bool.h>
  5. #include    <sys/types.h>
  6. #include    <sys/stat.h>
  7. #include    <stdio.h>
  8. #include    <string.h>
  9. #include    <ctype.h>
  10. #include    <id.h>
  11. #include    <bitops.h>
  12. #include    <errno.h>
  13. #include    <extern.h>
  14.  
  15. int idnHashCmp();
  16. int idnQsortCmp();
  17. int round2();
  18. struct idname *newIdName();
  19. void extractId();
  20. void fileIdArgs();
  21. void initHashTable();
  22. void oldIdArgs();
  23. void rehash();
  24. void updateID();
  25. void writeID();
  26.  
  27. long    NameCount;        /* Count of names in database */
  28. long    NumberCount;        /* Count of numbers in database */
  29. long    StringCount;        /* Count of strings in database */
  30. long    SoloCount;        /* Count of identifiers that occur only once */
  31.  
  32. long    HashSize;        /* Total Slots in hash table */
  33. long    HashMaxLoad;        /* Maximum loading of hash table */
  34. long    HashFill;        /* Number of keys inserted in table */
  35. long    HashProbes;        /* Total number of probes */
  36. long    HashSearches;        /* Total number of searches */
  37. struct idname    **HashTable;    /* Vector of idname pointers */
  38.  
  39. bool    Verbose = FALSE;
  40.  
  41. int    ArgsCount = 0;        /* Count of args to save */
  42. int    ScanCount = 0;        /* Count of files to scan */
  43. int    PathCount = 0;        /* Count of files covered in database */
  44. int    BitArraySize;        /* Size of bit array slice (per name) */
  45.  
  46.  
  47. char    *MyName;
  48. static void
  49. usage()
  50. {
  51.     fprintf(stderr, "Usage: %s [-f<idfile>] [-s<dir>] [-r<dir>] [(+|-)l[<lang>]] [-v] [(+|-)S<scanarg>] [-a<argfile>] [-] [-u] [files...]\n", MyName);
  52.     exit(1);
  53. }
  54. main(argc, argv)
  55.     int        argc;
  56.     char        **argv;
  57. {
  58.     char        *arg;
  59.     int        op;
  60.     FILE        *argFILE = NULL;
  61.     char        *idFile = IDFILE;
  62.     char        *rcsDir = NULL;
  63.     char        *sccsDir = NULL;
  64.     struct idarg    *idArgs, *idArgHead;
  65.     bool        keepLang = FALSE;
  66.     int        argsFrom = 0;
  67. #define    AF_CMDLINE    0x1    /* file args came on command line */
  68. #define    AF_FILE        0x2    /* file args came from a file (-f<file>) */
  69. #define    AF_IDFILE    0x4    /* file args came from an old ID file (-u) */
  70. #define    AF_QUERY    0x8    /* no file args necessary: usage query */
  71.  
  72.     MyName = basename(GETARG(argc, argv));
  73. #ifdef ERRLINEBUF
  74.     setlinebuf(stderr);
  75. #endif
  76.  
  77.     idArgs = idArgHead = NEW(struct idarg);
  78.  
  79.     /*
  80.         Process some arguments, and snarf-up some
  81.         others for processing later.
  82.     */
  83.     while (argc) {
  84.         arg = GETARG(argc, argv);
  85.         if (*arg != '-' && *arg != '+') {
  86.             argsFrom |= AF_CMDLINE;
  87.             idArgs->ida_arg = arg;
  88.             idArgs->ida_flags = IDA_SCAN|IDA_PATH;
  89.             idArgs->ida_index = postIncr(&PathCount);
  90.             ScanCount++;
  91.             idArgs = (idArgs->ida_next = NEW(struct idarg));
  92.             continue;
  93.         }
  94.         op = *arg++;
  95.         switch (*arg++)
  96.         {
  97.         case 'u':
  98.             argsFrom |= AF_IDFILE;
  99.             oldIdArgs(idFile, &idArgs);
  100.             break;
  101.         case '\0':
  102.             argsFrom |= AF_FILE;
  103.             fileIdArgs(stdin, &idArgs);
  104.             break;
  105.         case 'a':
  106.             if ((argFILE = fopen(arg, "r")) == NULL) {
  107.                 filerr("open", arg);
  108.                 exit(1);
  109.             }
  110.             argsFrom |= AF_FILE;
  111.             fileIdArgs(argFILE, &idArgs);
  112.             break;
  113.         case 'f':
  114.             idFile = arg;
  115.             break;
  116.         case 'v':
  117.             Verbose = TRUE;
  118.             break;
  119.         case 'S':
  120.             if (strchr(&arg[-2], '?')) {
  121.                 setScanArgs(op, arg);
  122.                 argsFrom |= AF_QUERY;
  123.             }
  124.             /*FALLTHROUGH*/
  125.         case 'l':
  126.         case 's':
  127.         case 'r':
  128.             idArgs->ida_arg = &arg[-2];
  129.             idArgs->ida_index = -1;
  130.             idArgs->ida_flags = IDA_ARG;
  131.             idArgs = (idArgs->ida_next = NEW(struct idarg));
  132.             ArgsCount++;
  133.             break;
  134.         default:
  135.             usage();
  136.         }
  137.     }
  138.  
  139.     if (argsFrom & AF_QUERY)
  140.         exit(0);
  141.     /*
  142.         File args should only come from one place.  Ding the
  143.         user if arguments came from multiple places, or if none
  144.         were supplied at all.
  145.     */
  146.     switch (argsFrom)
  147.     {
  148.     case AF_CMDLINE:
  149.     case AF_FILE:
  150.     case AF_IDFILE:
  151.         if (PathCount > 0)
  152.             break;
  153.         /*FALLTHROUGH*/
  154.     case 0:
  155.         fprintf(stderr, "%s: Use -u, -f<file>, or cmd-line for file args!\n", MyName);
  156.         usage();
  157.     default:
  158.         fprintf(stderr, "%s: Use only one of: -u, -f<file>, or cmd-line for file args!\n", MyName);
  159.         usage();
  160.     }
  161.  
  162.     if (ScanCount == 0)
  163.         exit(0);
  164.  
  165.     BitArraySize = (PathCount + 7) >> 3;
  166.     initHashTable(ScanCount);
  167.  
  168.     if (access(idFile, 06) < 0
  169.     && (errno != ENOENT || access(dirname(idFile), 06) < 0)) {
  170.         filerr("modify", idFile);
  171.         exit(1);
  172.     }
  173.  
  174.     for (idArgs = idArgHead; idArgs->ida_next; idArgs = idArgs->ida_next) {
  175.         char        *(*scanner)();
  176.         FILE        *srcFILE;
  177.         char        *arg, *lang, *suff;
  178.  
  179.         arg = idArgs->ida_arg;
  180.         if (idArgs->ida_flags & IDA_ARG) {
  181.             op = *arg++;
  182.             switch (*arg++)
  183.             {
  184.             case 'l':
  185.                 if (*arg == '\0') {
  186.                     keepLang = FALSE;
  187.                     lang = NULL;
  188.                     break;
  189.                 }
  190.                 if (op == '+')
  191.                     keepLang = TRUE;
  192.                 lang = arg;
  193.                 break;
  194.             case 's':
  195.                 sccsDir = arg;
  196.                 break;
  197.             case 'r':
  198.                 rcsDir = arg;
  199.                 break;
  200.             case 'S':
  201.                 setScanArgs(op, strsav(arg));
  202.                 break;
  203.             default:
  204.                 usage();
  205.             }
  206.             continue;
  207.         }
  208.         if (!(idArgs->ida_flags & IDA_SCAN))
  209.             goto skip;
  210.         if (lang == NULL) {
  211.             if ((suff = strrchr(arg, '.')) == NULL)
  212.                 suff = "";
  213.             if ((lang = getLanguage(suff)) == NULL) {
  214.                 fprintf(stderr, "%s: No language assigned to suffix: `%s'\n", MyName, suff);
  215.                 goto skip;
  216.             }
  217.         }
  218.         if ((scanner = getScanner(lang)) == NULL) {
  219.             fprintf(stderr, "%s: No scanner for language: `%s'\n", MyName, lang);
  220.             goto skip;
  221.         }
  222.         if ((srcFILE = openSrcFILE(arg, sccsDir, rcsDir)) == NULL)
  223.             goto skip;
  224.         if (Verbose)
  225.             fprintf(stderr, "%s: %s\n", lang, arg);
  226.         extractId(scanner, srcFILE, idArgs->ida_index);
  227.         fclose(srcFILE);
  228.     skip:
  229.         if (!keepLang)
  230.             lang = NULL;
  231.     }
  232.  
  233.     if (HashFill == 0)
  234.         exit(0);
  235.  
  236.     if (Verbose)
  237.         fprintf(stderr, "Compressing Hash Table...\n");
  238.     hashCompress(HashTable, HashSize);
  239.     if (Verbose)
  240.         fprintf(stderr, "Sorting Hash Table...\n");
  241.     qsort(HashTable, HashFill, sizeof(struct idname *), idnQsortCmp);
  242.  
  243.     if (argsFrom == AF_IDFILE) {
  244.         if (Verbose)
  245.             fprintf(stderr, "Merging Tables...\n");
  246.         updateID(idFile, idArgHead);
  247.     }
  248.  
  249.     if (Verbose)
  250.         fprintf(stderr, "Writing `%s'...\n", idFile);
  251.     writeID(idFile, idArgHead);
  252.  
  253.     if (Verbose) {
  254.         float loadFactor = (float)HashFill / (float)HashSize;
  255.         float aveProbes = (float)HashProbes / (float)HashSearches;
  256.         float aveOccur = (float)HashSearches / (float)HashFill;
  257.         fprintf(stderr, "Names: %ld, ", NameCount);
  258.         fprintf(stderr, "Numbers: %ld, ", NumberCount);
  259.         fprintf(stderr, "Strings: %ld, ", StringCount);
  260.         fprintf(stderr, "Solo: %ld, ", SoloCount);
  261.         fprintf(stderr, "Total: %ld\n", HashFill);
  262.         fprintf(stderr, "Occurances: %.2f, ", aveOccur);
  263.         fprintf(stderr, "Load: %.2f, ", loadFactor);
  264.         fprintf(stderr, "Probes: %.2f\n", aveProbes);
  265.     }
  266.     exit(0);
  267. }
  268.  
  269. void
  270. extractId(getId, srcFILE, index)
  271.     register char    *(*getId)();
  272.     register FILE    *srcFILE;
  273.     int        index;
  274. {
  275.     register struct idname    **slot;
  276.     register char    *key;
  277.     int        flags;
  278.  
  279.     while ((key = (*getId)(srcFILE, &flags)) != NULL) {
  280.         slot = (struct idname **)hashSearch(key, HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
  281.         HashSearches++;
  282.         if (*slot != NULL) {
  283.             (*slot)->idn_flags |= flags;
  284.             BITSET((*slot)->idn_bitv, index);
  285.             continue;
  286.         }
  287.         *slot = newIdName(key);
  288.         (*slot)->idn_flags = IDN_SOLO|flags;
  289.         BITSET((*slot)->idn_bitv, index);
  290.         if (HashFill++ >= HashMaxLoad)
  291.             rehash();
  292.     }
  293. }
  294.  
  295. void
  296. writeID(idFile, idArgs)
  297.     char        *idFile;
  298.     struct idarg    *idArgs;
  299. {
  300.     register struct idname    **idnp;
  301.     register struct idname    *idn;
  302.     register int    i;
  303.     char        *vecBuf;
  304.     FILE        *idFILE;
  305.     int        count;
  306.     int        lasti;
  307.     long        before, after;
  308.     int        length, longest;
  309.     struct idhead    idh;
  310.  
  311.     if ((idFILE = fopen(idFile, "w+")) == NULL) {
  312.         filerr("create", idFile);
  313.         exit(1);
  314.     }
  315.     fseek(idFILE, (long)sizeof(struct idhead), 0);
  316.  
  317.     /* write out the list of pathnames */
  318.     idh.idh_argo = ftell(idFILE);
  319.     for (i = lasti = 0; idArgs->ida_next; idArgs = idArgs->ida_next) {
  320.         if (idArgs->ida_index > 0)
  321.             while (++lasti < idArgs->ida_index)
  322.                 i++, putc('\0', idFILE);
  323.         fputs(idArgs->ida_arg, idFILE);
  324.         i++, putc('\0', idFILE);
  325.     }
  326.     idh.idh_argc = i;
  327.     idh.idh_pthc = PathCount;
  328.  
  329.     /* write out the list of identifiers */
  330.     i = 1;
  331.     if (idh.idh_pthc >= 0x000000ff)
  332.         i++;
  333.     if (idh.idh_pthc >= 0x0000ffff)
  334.         i++;
  335.     if (idh.idh_pthc >= 0x00ffffff)
  336.         i++;
  337.     idh.idh_vecc = i;
  338.  
  339.     vecBuf = malloc((idh.idh_pthc + 1) * idh.idh_vecc);
  340.  
  341.     putc('\377', idFILE);
  342.     before = idh.idh_namo = ftell(idFILE);
  343.     longest = 0;
  344.     for (idnp = HashTable, i = 0; i < HashFill; i++, idnp++) {
  345.         idn = *idnp;
  346.         if (idn->idn_name[0] == '\0') {
  347.             HashFill--; i--;
  348.             continue;
  349.         }
  350.         if (idn->idn_flags & IDN_SOLO)
  351.             SoloCount++;
  352.         if (idn->idn_flags & IDN_NUMBER)
  353.             NumberCount++;
  354.         if (idn->idn_flags & IDN_NAME)
  355.             NameCount++;
  356.         if (idn->idn_flags & IDN_STRING)
  357.             StringCount++;
  358.  
  359.         putc((*idnp)->idn_flags, idFILE);
  360.         fputs(idn->idn_name, idFILE);
  361.         putc('\0', idFILE);
  362.  
  363.         count = bitsToVec(vecBuf, (*idnp)->idn_bitv, idh.idh_pthc, idh.idh_vecc);
  364.         fwrite(vecBuf, idh.idh_vecc, count, idFILE);
  365.         putc('\377', idFILE);
  366.         after = ftell(idFILE);
  367.         
  368.         if ((length = (after - before)) > longest)
  369.             longest = length;
  370.         before = after;
  371.     }
  372.     idh.idh_namc = i;
  373.     putc('\377', idFILE);
  374.     idh.idh_endo = ftell(idFILE);
  375.     idh.idh_bsiz = longest;
  376.  
  377.     /* write out the header */
  378.     strncpy(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic));
  379.     idh.idh_vers = IDH_VERS;
  380.     fseek(idFILE, 0L, 0);
  381.     fwrite(&idh, sizeof(struct idhead), 1, idFILE);
  382.  
  383.     fclose(idFILE);
  384. }
  385.  
  386. /*
  387.     Build an idarg vector from pathnames contained in an existing
  388.     id file.  Only include pathnames for files whose modification
  389.     time is later than that of the id file itself.
  390. */
  391. void
  392. oldIdArgs(idFile, idArgsP)
  393.     char        *idFile;
  394.     struct idarg    **idArgsP;
  395. {
  396.     struct stat    statBuf;
  397.     struct idhead    idh;
  398.     FILE        *idFILE;
  399.     register int    i;
  400.     register char    *strings;
  401.     time_t        idModTime;
  402.  
  403.     if ((idFILE = fopen(idFile, "r")) == NULL) {
  404.         filerr("open", idFile);
  405.         usage();
  406.     }
  407.     /*
  408.     *  Open the id file, get its mod-time, and read its header.
  409.     */
  410.     if (fstat(fileno(idFILE), &statBuf) < 0) {
  411.         filerr("stat", idFile);
  412.         usage();
  413.     }
  414.     idModTime = statBuf.st_mtime;
  415.     fread(&idh, sizeof(struct idhead), 1, idFILE);
  416.     if (!strnequ(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic))) {
  417.         fprintf(stderr, "%s: Not an id file: `%s'\n", MyName, idFile);
  418.         exit(1);
  419.     }
  420.     if (idh.idh_vers != IDH_VERS) {
  421.         fprintf(stderr, "%s: ID version mismatch (%ld,%ld)\n", MyName, idh.idh_vers, IDH_VERS);
  422.         exit(1);
  423.     }
  424.  
  425.     /*
  426.     *  Read in the id pathnames, compare their mod-times with
  427.     *  the id file, and incorporate the pathnames of recently modified 
  428.     *  files in the idarg vector.  Also, construct a mask of
  429.     *  bit array positions we want to turn off when we build the
  430.     *  initial hash-table.
  431.     */
  432.     fseek(idFILE, idh.idh_argo, 0);
  433.     strings = malloc(i = idh.idh_namo - idh.idh_argo);
  434.     fread(strings, i, 1, idFILE);
  435.     ScanCount = 0;
  436.     for (i = 0; i < idh.idh_argc; i++) {
  437.         (*idArgsP)->ida_arg = strings;
  438.         if (*strings == '+' || *strings == '-') {
  439.             (*idArgsP)->ida_flags = IDA_ARG;
  440.             (*idArgsP)->ida_index = -1;
  441.         } else {
  442.             (*idArgsP)->ida_flags = IDA_PATH;
  443.             (*idArgsP)->ida_index = postIncr(&PathCount);
  444.             if (stat(strings, &statBuf) < 0) {
  445.                 filerr("stat", strings);
  446.             } else if (statBuf.st_mtime >= idModTime) {
  447.                 (*idArgsP)->ida_flags |= IDA_SCAN;
  448.                 ScanCount++;
  449.             }
  450.         }
  451.         (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
  452.         while (*strings++)
  453.             ;
  454.     }
  455.     if (ScanCount == 0) {
  456.         fclose(idFILE);
  457.         exit(0);
  458.     }
  459.     fclose(idFILE);
  460. }
  461.  
  462. void
  463. updateID(idFile, idArgs)
  464.     char        *idFile;
  465.     struct idarg    *idArgs;
  466. {
  467.     struct idname    *idn;
  468.     struct idhead    idh;
  469.     register char    *bitArray;
  470.     char        *entry;
  471.     register int    i;
  472.     FILE        *idFILE;
  473.     int        cmp, count, size;
  474.     char        *bitsOff;
  475.     struct idname    **newTable, **mergeTable;
  476.     struct idname    **t1, **t2, **tm;
  477.  
  478.     if ((idFILE = fopen(idFile, "r")) == NULL)
  479.         filerr("open", idFile);
  480.     fread(&idh, sizeof(struct idhead), 1, idFILE);
  481.  
  482.     entry = malloc(idh.idh_bsiz);
  483.  
  484.     bitsOff = malloc(BitArraySize);
  485.     bzero(bitsOff, BitArraySize);
  486.     for (i = 0; idArgs->ida_next; idArgs = idArgs->ida_next)
  487.         if (idArgs->ida_flags & IDA_SCAN)
  488.             BITSET(bitsOff, idArgs->ida_index);
  489.  
  490.     bitArray = malloc(BitArraySize);
  491.     bzero(bitArray, BitArraySize);
  492.     t2 = newTable = (struct idname **)malloc((idh.idh_namc + 1) * sizeof(struct idname *));
  493.     fseek(idFILE, idh.idh_namo, 0);
  494.     count = 0;
  495.     for (i = 0; i < idh.idh_namc; i++) {
  496.         size = 1 + fgets0(entry, idh.idh_bsiz, idFILE);
  497.         getsFF(&entry[size], idFILE);
  498.         vecToBits(bitArray, &entry[size], idh.idh_vecc);
  499.         bitsclr(bitArray, bitsOff, BitArraySize);
  500.         if (!bitsany(bitArray, BitArraySize))
  501.             continue;
  502.         *t2 = newIdName(ID_STRING(entry));
  503.         bitsset((*t2)->idn_bitv, bitArray, BitArraySize);
  504.         (*t2)->idn_flags = ID_FLAGS(entry);
  505.         bzero(bitArray, BitArraySize);
  506.         t2++; count++;
  507.     }
  508.     *t2 = NULL;
  509.  
  510.     t1 = HashTable;
  511.     t2 = newTable;
  512.     tm = mergeTable = (struct idname **)calloc(HashFill + count + 1, sizeof(struct idname *));
  513.     while (*t1 && *t2) {
  514.         cmp = strcmp((*t1)->idn_name, (*t2)->idn_name);
  515.         if (cmp < 0)
  516.             *tm++ = *t1++;
  517.         else if (cmp > 0)
  518.             *tm++ = *t2++;
  519.         else {
  520.             (*t1)->idn_flags |= (*t2)->idn_flags;
  521.             (*t1)->idn_flags &= ~IDN_SOLO;
  522.             bitsset((*t1)->idn_bitv, (*t2)->idn_bitv, BitArraySize);
  523.             *tm++ = *t1;
  524.             t1++, t2++;
  525.         }
  526.     }
  527.     while (*t1)
  528.         *tm++ = *t1++;
  529.     while (*t2)
  530.         *tm++ = *t2++;
  531.     *tm = NULL;
  532.     HashTable = mergeTable;
  533.     HashFill = tm - mergeTable;
  534. }
  535.  
  536. /*
  537.     Cons up a list of idArgs as supplied in a file.
  538. */
  539. void
  540. fileIdArgs(argFILE, idArgsP)
  541.     FILE        *argFILE;
  542.     struct idarg    **idArgsP;
  543. {
  544.     int        fileCount;
  545.     char        buf[BUFSIZ];
  546.     char        *arg;
  547.  
  548.     fileCount = 0;
  549.     while (fgets(buf, sizeof(buf), argFILE)) {
  550.         (*idArgsP)->ida_arg = arg = strnsav(buf, strlen(buf)-1);
  551.         if (*arg == '+' || *arg == '-') {
  552.             (*idArgsP)->ida_flags = IDA_ARG;
  553.             (*idArgsP)->ida_index = -1;
  554.         } else {
  555.             (*idArgsP)->ida_flags = IDA_SCAN|IDA_PATH;
  556.             (*idArgsP)->ida_index = postIncr(&PathCount);
  557.             ScanCount++;
  558.         }
  559.         (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
  560.     }
  561. }
  562.  
  563. void
  564. initHashTable(pathCount)
  565.     int        pathCount;
  566. {
  567.     if ((HashSize = round2((pathCount << 6) + 511)) > 0x8000)
  568.         HashSize = 0x8000;
  569.     HashMaxLoad = HashSize - (HashSize >> 4);    /* about 94% */
  570.     HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
  571. }
  572.  
  573. /*
  574.     Double the size of the hash table in the
  575.     event of overflow...
  576. */
  577. void
  578. rehash()
  579. {
  580.     long        oldHashSize = HashSize;
  581.     struct idname    **oldHashTable = HashTable;
  582.     register struct idname    **htp;
  583.     register struct idname    **slot;
  584.  
  585.     HashSize *= 2;
  586.     if (Verbose)
  587.         fprintf(stderr, "Rehashing... (doubling size to %ld)\n", HashSize);
  588.     HashMaxLoad = HashSize - (HashSize >> 4);
  589.     HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
  590.  
  591.     HashFill = 0;
  592.     for (htp = oldHashTable; htp < &oldHashTable[oldHashSize]; htp++) {
  593.         if (*htp == NULL)
  594.             continue;
  595.         slot = (struct idname **)hashSearch((*htp)->idn_name, (char *)HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
  596.         if (*slot) {
  597.             fprintf(stderr, "%s: Duplicate hash entry!\n");
  598.             exit(1);
  599.         }
  600.         *slot = *htp;
  601.         HashSearches++;
  602.         HashFill++;
  603.     }
  604.     free(oldHashTable);
  605. }
  606.  
  607. /*
  608.     Round a given number up to the nearest power of 2.
  609. */
  610. int
  611. round2(rough)
  612.     int        rough;
  613. {
  614.     int        round;
  615.  
  616.     round = 1;
  617.     while (rough) {
  618.         round <<= 1;
  619.         rough >>= 1;
  620.     }
  621.     return round;
  622. }
  623.  
  624. /*
  625.     `compar' function for hashSearch()
  626. */
  627. int
  628. idnHashCmp(key, idn)
  629.     char        *key;
  630.     struct idname    **idn;
  631. {
  632.     int        collate;
  633.  
  634.     if (*idn == NULL)
  635.         return 0;
  636.     
  637.     if ((collate = strcmp(key, (*idn)->idn_name)) == 0)
  638.         (*idn)->idn_flags &= ~IDN_SOLO;    /* we found another occurance */
  639.  
  640.     return collate;
  641. }
  642.  
  643. /*
  644.     `compar' function for qsort().
  645. */
  646. int
  647. idnQsortCmp(idn1, idn2)
  648.     struct idname    **idn1;
  649.     struct idname    **idn2;
  650. {
  651.     if (*idn1 == *idn2)
  652.         return 0;
  653.     if (*idn1 == NULL)
  654.         return 1;
  655.     if (*idn2 == NULL)
  656.         return -1;
  657.  
  658.     return strcmp((*idn1)->idn_name, (*idn2)->idn_name);
  659. }
  660.  
  661. /*
  662.     Allocate a new idname struct and fill in the name field.
  663.     We allocate memory in large chunks to avoid frequent
  664.     calls to malloc() which is a major pig.
  665. */
  666. struct idname *
  667. newIdName(name)
  668.     char        *name;
  669. {
  670.     register struct idname    *idn;
  671.     register char    *allocp;
  672.     register int    allocsiz;
  673.     static char    *allocBuf = NULL;
  674.     static char    *allocEnd = NULL;
  675. #define    ALLOCSIZ    (8*1024)
  676.  
  677.     allocsiz = sizeof(struct idname) + strlen(name) + 1 + BitArraySize;
  678.     allocsiz += (sizeof(long) - 1);
  679.     allocsiz &= ~(sizeof(long) - 1);
  680.  
  681.     allocp = allocBuf;
  682.     allocBuf += allocsiz;
  683.     if (allocBuf > allocEnd) {
  684.         allocBuf = malloc(ALLOCSIZ);
  685.         allocEnd = &allocBuf[ALLOCSIZ];
  686.         allocp = allocBuf;
  687.         allocBuf += allocsiz;
  688.     }
  689.  
  690.     idn = (struct idname *)allocp;
  691.     allocp += sizeof(struct idname);
  692.     idn->idn_bitv = allocp;
  693.     for (allocsiz = BitArraySize; allocsiz--; allocp++)
  694.         *allocp = '\0';
  695.     idn->idn_name = strcpy(allocp, name);
  696.  
  697.     return idn;
  698. }
  699.  
  700. int
  701. postIncr(ip)
  702.     int        *ip;
  703. {
  704.     register int    i;
  705.     int        save;
  706.  
  707.     save = *ip;
  708.     i = save + 1;
  709.     if ((i & 0x00ff) == 0x00ff)
  710.         i++;
  711.     if ((i & 0xff00) == 0xff00)    /* This isn't bloody likely */
  712.         i += 0x100;
  713.     *ip = i;
  714.  
  715.     return save;
  716. }
  717.  
  718. /*
  719.     Move all non-NULL table entries to the front of the table.
  720.     return the number of non-NULL elements in the table.
  721. */
  722. int
  723. hashCompress(table, size)
  724.     char        **table;
  725.     int        size;
  726. {
  727.     register char    **front;
  728.     register char    **back;
  729.  
  730.     front = &table[-1];
  731.     back = &table[size];
  732.  
  733.     for (;;) {
  734.         while (*--back == NULL)
  735.             ;
  736.         if (back < front)
  737.             break;
  738.         while (*++front != NULL)
  739.             ;
  740.         if (back < front)
  741.             break;
  742.         *front = *back;
  743.     }
  744.  
  745.     return (back - table + 1);
  746. }
  747.