home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d191 / ispell.lha / ISpell / src.zoo / buildhash.c < prev    next >
C/C++ Source or Header  |  1989-02-22  |  10KB  |  509 lines

  1. /* -*- Mode: Text -*- */
  2.  
  3. #define MAIN
  4.  
  5. /*
  6.  * buildhash.c - make a hash table for ispell
  7.  *
  8.  * Pace Willisson, 1983
  9.  */
  10.  
  11. #include <ctype.h>
  12. #include <stdio.h>
  13. #ifdef AMIGA
  14. #include <stat.h>
  15. #else
  16. #ifdef USG
  17. #include <sys/types.h>
  18. #endif
  19. #include <sys/param.h>
  20. #include <sys/stat.h>
  21. #endif
  22. #include "config.h"
  23. #include "ispell.h"
  24.  
  25. #define NSTAT 100
  26. struct stat dstat, cstat;
  27.  
  28. int numwords, hashsize;
  29.  
  30. char *malloc();
  31. char *realloc ();
  32.  
  33. struct dent *hashtbl;
  34.  
  35. char *Dfile;
  36. char *Hfile;
  37.  
  38. char Cfile[MAXPATHLEN];
  39. char Sfile[MAXPATHLEN];
  40.  
  41. main (argc,argv)
  42. int argc;
  43. char **argv;
  44. {
  45.     FILE *countf;
  46.     FILE *statf;
  47.     int stats[NSTAT];
  48.     int i;
  49.  
  50. #ifdef AMIGA
  51.     _Heapsize = 2*HEAPSIZE;
  52. #endif
  53.  
  54.     if (argc > 1) {
  55.         ++argv;
  56.         Dfile = *argv;
  57.         if (argc > 2) {
  58.             ++argv;
  59.             Hfile = *argv;
  60.         }
  61.         else
  62.             Hfile = DEFHASH;
  63.     }
  64.     else {
  65.         Dfile = DEFDICT;
  66.         Hfile = DEFHASH;
  67.     }
  68.  
  69.     sprintf(Cfile,"%s.cnt",Dfile);
  70.     sprintf(Sfile,"%s.stat",Dfile);
  71.  
  72.     if (stat (Dfile, &dstat) < 0) {
  73.         fprintf (stderr, "No dictionary (%s)\n", Dfile);
  74.         exit (1);
  75.     }
  76.  
  77.     if (stat (Cfile, &cstat) < 0 || dstat.st_mtime > cstat.st_mtime)
  78.         newcount ();
  79.  
  80.     if ((countf = fopen (Cfile, "r")) == NULL) {
  81.         fprintf (stderr, "No count file\n");
  82.         exit (1);
  83.     }
  84.     numwords = 0;
  85.     fscanf (countf, "%d", &numwords);
  86.     fclose (countf);
  87.     if (numwords == 0) {
  88.         fprintf (stderr, "Bad count file\n");
  89.         exit (1);
  90.     }
  91.     hashsize = numwords;
  92.     readdict ();
  93.  
  94.     if ((statf = fopen (Sfile, "w")) == NULL) {
  95.         fprintf (stderr, "Can't create %s\n", Sfile);
  96.         exit (1);
  97.     }
  98.  
  99.     for (i = 0; i < NSTAT; i++)
  100.         stats[i] = 0;
  101.     for (i = 0; i < hashsize; i++) {
  102.         struct dent *dp;
  103.         int j;
  104.         if (hashtbl[i].used == 0) {
  105.             stats[0]++;
  106.         } else {
  107.             for (j = 1, dp = &hashtbl[i]; dp->next != NULL; j++, dp = dp->next)
  108.                 ;
  109.             if (j >= NSTAT)
  110.                 j = NSTAT - 1;
  111.             stats[j]++;
  112.         }
  113.     }
  114.     for (i = 0; i < NSTAT; i++)
  115.         fprintf (statf, "%d: %d\n", i, stats[i]);
  116.     fclose (statf);
  117.  
  118.     filltable ();
  119.  
  120.     output ();
  121.     exit(0);
  122. }
  123.  
  124. output ()
  125. {
  126.     FILE *outfile;
  127.     struct hashheader hashheader;
  128.     int strptr, n, i;
  129.  
  130.     if ((outfile = fopen (Hfile, "w")) == NULL) {
  131.         fprintf (stderr, "can't create %s\n",Hfile);
  132.         return;
  133.     }
  134.     hashheader.magic = MAGIC;
  135.     hashheader.stringsize = 0;
  136.     hashheader.tblsize = hashsize;
  137.     fwrite (&hashheader, sizeof hashheader, 1, outfile);
  138.     strptr = 0;
  139.     for (i = 0; i < hashsize; i++) {
  140.         n = strlen (hashtbl[i].word) + 1;
  141. #ifdef CAPITALIZE
  142.         if (hashtbl[i].followcase)
  143.             n += (hashtbl[i].word[n] & 0xFF) * (n + 1) + 1;
  144. #endif
  145.         fwrite (hashtbl[i].word, n, 1, outfile);
  146.         hashtbl[i].word = (char *)strptr;
  147.         strptr += n;
  148.     }
  149.     /* Pad file to a struct dent boundary for efficiency. */
  150.     n = (strptr + sizeof hashheader) % sizeof (struct dent);
  151.     if (n != 0) {
  152.         n = sizeof (struct dent) - n;
  153.         strptr += n;
  154.         while (--n >= 0)
  155.             putc ('\0', outfile);
  156.     }
  157.     for (i = 0; i < hashsize; i++) {
  158.         if (hashtbl[i].next != 0) {
  159.             int x;
  160.             x = hashtbl[i].next - hashtbl;
  161.             hashtbl[i].next = (struct dent *)x;
  162.         } else {
  163.             hashtbl[i].next = (struct dent *)-1;
  164.         }
  165.     }
  166.     fwrite (hashtbl, sizeof (struct dent), hashsize, outfile);
  167.     hashheader.stringsize = strptr;
  168.     rewind (outfile);
  169.     fwrite (&hashheader, sizeof hashheader, 1, outfile);
  170.     fclose (outfile);
  171. }
  172.  
  173. filltable ()
  174. {
  175.     struct dent *freepointer, *nextword, *dp;
  176.     int i;
  177.  
  178.     for (freepointer = hashtbl; freepointer->used; freepointer++)
  179.         ;
  180.     for (nextword = hashtbl, i = numwords; i != 0; nextword++, i--) {
  181.         if (nextword->used == 0) {
  182.             continue;
  183.         }
  184.         if (nextword->next == NULL) {
  185.             continue;
  186.         }
  187.         if (nextword->next >= hashtbl && nextword->next < hashtbl + hashsize) {
  188.             continue;
  189.         }
  190.         dp = nextword;
  191.         while (dp->next) {
  192.             if (freepointer > hashtbl + hashsize) {
  193.                 fprintf (stderr, "table overflow\n");
  194.                 getchar ();
  195.                 break;
  196.             }
  197.             *freepointer = *(dp->next);
  198.             dp->next = freepointer;
  199.             dp = freepointer;
  200.  
  201.             while (freepointer->used)
  202.                 freepointer++;
  203.         }
  204.     }
  205. }
  206.  
  207.  
  208. readdict ()
  209. {
  210.     struct dent d;
  211.     register struct dent *dp;
  212.     char lbuf[100];
  213.     FILE *dictf;
  214.     int i;
  215.     int h;
  216.     int len;
  217.     register char *p;
  218.  
  219.     if ((dictf = fopen (Dfile, "r")) == NULL) {
  220.         fprintf (stderr, "Can't open dictionary\n");
  221.         exit (1);
  222.     }
  223.  
  224.     hashtbl = (struct dent *) calloc (numwords, sizeof (struct dent));
  225.     if (hashtbl == NULL) {
  226.         fprintf (stderr, "couldn't allocate hash table\n");
  227.         exit (1);
  228.     }
  229.  
  230.     i = 0;
  231.     while (fgets (lbuf, sizeof lbuf, dictf) != NULL) {
  232.         if ((i & 1023) == 0) {
  233.             printf ("%d ", i);
  234.             fflush (stdout);
  235.         }
  236.         i++;
  237.  
  238.         p = &lbuf [ strlen (lbuf) - 1 ];
  239.         if (*p == '\n')
  240.             *p = 0;
  241.  
  242.         if (makedent (lbuf, &d) < 0)
  243.             continue;
  244.  
  245.         len = strlen (lbuf);
  246. #ifdef CAPITALIZE
  247.         if (d.followcase)
  248.             d.word = malloc (2 * len + 4);
  249.         else
  250.             d.word = malloc (len + 1);
  251. #else
  252.         d.word = malloc (len + 1);
  253. #endif
  254.         if (d.word == NULL) {
  255.             fprintf (stderr, "couldn't allocate space for word %s\n", lbuf);
  256.             exit (1);
  257.         }
  258.         strcpy (d.word, lbuf);
  259. #ifdef CAPITALIZE
  260.         if (d.followcase) {
  261.             p = d.word + len + 1;
  262.             *p++ = 1;        /* Count of capitalizations */
  263.             *p++ = '-';        /* Don't keep in pers dict */
  264.             strcpy (p, lbuf);
  265.             
  266.         }
  267.         for (p = d.word;  *p;  p++) {
  268.             if (mylower (*p))
  269.                 *p = toupper (*p);
  270.         }
  271. #endif
  272.  
  273.         h = hash (d.word, len, hashsize);
  274.  
  275.         dp = &hashtbl[h];
  276.         if (dp->used == 0) {
  277.             *dp = d;
  278.         } else {
  279.  
  280. #ifdef CAPITALIZE
  281.             while (dp != NULL  &&  strcmp (dp->word, d.word) != 0)
  282.                 dp = dp->next;
  283.             if (dp != NULL) {
  284.                 if (d.followcase
  285.                   ||  (dp->followcase  &&  !d.allcaps
  286.                 &&  !d.capitalize)) {
  287.                 /* Add a specific capitalization */
  288.                 if (dp->followcase) {
  289.                     p = &dp->word[len + 1];
  290.                     (*p)++;    /* Bump counter */
  291.                     dp->word = realloc (dp->word,
  292.                       ((*p & 0xFF) + 1) * (len + 2));
  293.                     if (dp->word == NULL) {
  294.                     fprintf (stderr,
  295.                       "couldn't allocate space for word %s\n",
  296.                       lbuf);
  297.                     exit (1);
  298.                     }
  299.                     p = &dp->word[len + 1];
  300.                     p += ((*p & 0xFF) - 1) * (len + 2) + 1;
  301.                     *p++ = '-';
  302.                     strcpy (p,
  303.                       d.followcase ? &d.word[len + 3] : lbuf);
  304.                 }
  305.                 else {
  306.                     /* d.followcase must be true */
  307.                     /* thus, d.capitalize and d.allcaps are */
  308.                     /* clear */
  309.                     free (dp->word);
  310.                     dp->word = d.word;
  311.                     dp->followcase = 1;
  312.                     dp->k_followcase = 1;
  313.                     /* Code later will clear dp->allcaps. */
  314.                 }
  315.                 }
  316.                 /* Combine two capitalizations.  If d was */
  317.                 /* allcaps, dp remains unchanged */
  318.                 if (d.allcaps == 0) {
  319.                 /* dp is the entry that will be kept.  If */
  320.                 /* dp is followcase, the capitalize flag */
  321.                 /* reflects whether capitalization "may" */
  322.                 /* occur.  If not, it reflects whether it */
  323.                 /* "must" occur. */
  324.                 if (d.capitalize) {    /* ie lbuf was cap'd */
  325.                     if (dp->followcase)
  326.                     dp->capitalize = 1;    /* May */
  327.                     else if (dp->allcaps) /* ie not lcase */
  328.                     dp->capitalize = 1;    /* Must */
  329.                 }
  330.                 else {        /* lbuf was followc or all-lc */
  331.                     if (!dp->followcase)
  332.                     dp->capitalize == 0;    /* May */
  333.                 }
  334.                 dp->k_capitalize == dp->capitalize;
  335.                 dp->allcaps = 0;
  336.                 dp->k_allcaps = 0;
  337.                 }
  338.             }
  339.             else {
  340. #endif
  341.                 dp = (struct dent *) malloc (sizeof (struct dent));
  342.                 if (dp == NULL) {
  343.                 fprintf (stderr,
  344.                   "couldn't allocate space for collision\n");
  345.                 exit (1);
  346.                 }
  347.                 *dp = d;
  348.                 dp->next = hashtbl[h].next;
  349.                 hashtbl[h].next = dp;
  350.             }
  351.         }
  352. #ifdef CAPITALIZE
  353.     }
  354. #endif
  355.     printf ("\n");
  356. }
  357.  
  358. /*
  359.  * fill in the flags in d, and put a null after the word in s
  360.  */
  361.  
  362. makedent (lbuf, d)
  363. char *lbuf;
  364. struct dent *d;
  365. {
  366.     char *p, *index();
  367.  
  368.     d->next = NULL;
  369.     d->used = 1;
  370.     d->v_flag = 0;
  371.     d->n_flag = 0;
  372.     d->x_flag = 0;
  373.     d->h_flag = 0;
  374.     d->y_flag = 0;
  375.     d->g_flag = 0;
  376.     d->j_flag = 0;
  377.     d->d_flag = 0;
  378.     d->t_flag = 0;
  379.     d->r_flag = 0;
  380.     d->z_flag = 0;
  381.     d->s_flag = 0;
  382.     d->p_flag = 0;
  383.     d->m_flag = 0;
  384.     d->keep = 0;
  385. #ifdef CAPITALIZE
  386.     d->allcaps = 0;
  387.     d->capitalize = 0;
  388.     d->followcase = 0;
  389.     /*
  390.     ** Figure out the capitalization rules from the capitalization of
  391.     ** the sample entry.  Only one of followcase, allcaps, and capitalize
  392.     ** will be set.  Combinations are generated by higher-level code.
  393.     */
  394.     for (p = lbuf;  *p  &&  *p != '/';  p++) {
  395.         if (mylower (*p))
  396.             break;
  397.     }
  398.     if (*p == '\0'  ||  *p == '/')
  399.         d->allcaps = 1;
  400.     else {
  401.         for (  ;  *p  &&  *p != '/';  p++) {
  402.             if (myupper (*p))
  403.                 break;
  404.         }
  405.         if (*p == '\0'  ||  *p == '/') {
  406.             /*
  407.             ** No uppercase letters follow the lowercase ones.
  408.             ** If the first two letters are capitalized, it's
  409.             ** "followcase". If the first one is capitalized, it's
  410.             ** "capitalize".
  411.             */
  412.             if (myupper (lbuf[0])) {
  413.                 if (myupper (lbuf[1]))
  414.                     d->followcase = 1;
  415.                 else
  416.                     d->capitalize = 1;
  417.             }
  418.         }
  419.         else
  420.             d->followcase = 1;    /* .../lower/upper */
  421.     }
  422.     d->k_allcaps = d->allcaps ;
  423.     d->k_capitalize = d->capitalize;
  424.     d->k_followcase = d->followcase;
  425. #endif
  426.  
  427.     p = index (lbuf, '/');
  428.     if (p != NULL)
  429.         *p = 0;
  430.     if (strlen (lbuf) > WORDLEN - 1) {
  431.         printf ("%s: word too big\n", lbuf);
  432.         return (-1);
  433.     }
  434.  
  435.     if (p == NULL)
  436.         return (0);
  437.  
  438.     p++;
  439.     while (*p != '\0'  &&  *p != '\n') {
  440.         if (mylower (*p))
  441.             *p = toupper (*p);
  442.         switch (*p) {
  443.         case 'V': d->v_flag = 1; break;
  444.         case 'N': d->n_flag = 1; break;
  445.         case 'X': d->x_flag = 1; break;
  446.         case 'H': d->h_flag = 1; break;
  447.         case 'Y': d->y_flag = 1; break;
  448.         case 'G': d->g_flag = 1; break;
  449.         case 'J': d->j_flag = 1; break;
  450.         case 'D': d->d_flag = 1; break;
  451.         case 'T': d->t_flag = 1; break;
  452.         case 'R': d->r_flag = 1; break;
  453.         case 'Z': d->z_flag = 1; break;
  454.         case 'S': d->s_flag = 1; break;
  455.         case 'P': d->p_flag = 1; break;
  456.         case 'M': d->m_flag = 1; break;
  457.         case 0:
  458.              fprintf (stderr, "no flags on word %s\n", lbuf);
  459.             continue;
  460.         default:
  461.             fprintf (stderr, "unknown flag %c word %s\n", 
  462.                     *p, lbuf);
  463.             break;
  464.         }
  465.         p++;
  466.         if (*p == '/')        /* Handle old-format dictionaries too */
  467.             p++;
  468.     }
  469.     return (0);
  470. }
  471.  
  472. newcount ()
  473. {
  474.     char buf[200];
  475.     char lastbuf[200];
  476.     FILE *d;
  477.     int i;
  478.     register char *cp;
  479.  
  480.     fprintf (stderr, "Counting words in dictionary ...\n");
  481.  
  482.     if ((d = fopen (Dfile, "r")) == NULL) {
  483.         fprintf (stderr, "Can't open dictionary\n");
  484.         exit (1);
  485.     }
  486.  
  487.     for (i = 0, lastbuf[0] = '\0';  fgets (buf, sizeof buf, d);  ) {
  488.         for (cp = buf;  *cp;  cp++) {
  489.             if (mylower (*cp))
  490.                 *cp = toupper (*cp);
  491.         }
  492.         if (strcmp (buf, lastbuf) != 0) {
  493.             if ((++i & 1023) == 0) {
  494.                 printf ("%d ", i);
  495.                 fflush (stdout);
  496.             }
  497.             strcpy (lastbuf, buf);
  498.         }
  499.     }
  500.     fclose (d);
  501.     printf ("\n%d words\n", i);
  502.     if ((d = fopen (Cfile, "w")) == NULL) {
  503.         fprintf (stderr, "can't create %s\n", Cfile);
  504.         exit (1);
  505.     }
  506.     fprintf (d, "%d\n", i);
  507.     fclose (d);
  508. }
  509.