home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 495a.lha / ISpell_v3.1ljr / src / buildhash.c < prev    next >
C/C++ Source or Header  |  1991-04-06  |  11KB  |  582 lines

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