home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Product / Product.zip / ISPSRC.ZIP / tgood.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-14  |  16.2 KB  |  556 lines

  1. /* -*- Mode:Text -*- */
  2. #ifndef lint
  3. static char Rcs_Id[] =
  4.     "$Id: tgood.c,v 1.18 91/09/11 23:23:00 geoff Exp $";
  5. #endif
  6.  
  7. /*
  8.  * Copyright 1987, 1988, 1989, by Geoff Kuenning, Manhattan Beach, CA
  9.  * Permission for non-profit use is hereby granted.
  10.  * All other rights reserved.
  11.  * See "version.h" for a more complete copyright notice.
  12.  */
  13.  
  14. /*
  15.  * $Log:    tgood.c,v $
  16.  * Revision 1.18  91/09/11  23:23:00  geoff
  17.  * Make sure that pure-deletion suffixes operate correctly, by adding the
  18.  * necessary null byte after the strip portion.
  19.  * 
  20.  * Revision 1.17  91/07/11  19:52:27  geoff
  21.  * Remove the include of stdio.h, since ispell.h now does this.
  22.  * 
  23.  * Revision 1.16  91/05/27  21:48:12  geoff
  24.  * When checking affixes, remember to check for the case of affixes that
  25.  * strip nothing and only add characters.
  26.  * 
  27.  * Revision 1.15  90/12/31  01:04:16  geoff
  28.  * Add a text-mode line so emacs will edit consistently.
  29.  * 
  30.  * Revision 1.14  90/04/26  22:44:28  geoff
  31.  * Add the canonicalize parameter to calls to ichartosstr.
  32.  * 
  33.  * Revision 1.13  89/06/09  15:56:32  geoff
  34.  * Add support for the internal "character" type, ichar_t.
  35.  * 
  36.  * Revision 1.12  89/04/27  23:34:27  geoff
  37.  * In suf_list_chk, call setfindlast just before the condition check, because
  38.  * the word changes on each pass through the loop.  Also call findlastchar
  39.  * with the correct parameters.
  40.  * 
  41.  * Revision 1.11  89/04/03  01:58:53  geoff
  42.  * Fix a bunch of lint complaints.  Add (partial) support for string
  43.  * characters.
  44.  * 
  45.  * Revision 1.10  88/12/26  02:33:04  geoff
  46.  * Update the copyright notice.
  47.  * 
  48.  * Revision 1.9  88/11/25  19:54:28  geoff
  49.  * Fix some inconsistencies in the formatting of curly braces.
  50.  * 
  51.  * Revision 1.8  88/04/30  22:16:04  geoff
  52.  * Fix some lint complaints.
  53.  * 
  54.  * Revision 1.7  88/02/20  23:14:44  geoff
  55.  * Support the new capitalization handling.  Add the "allhits" parameter to
  56.  * chk_aff and its descendents.
  57.  * 
  58.  * Revision 1.6  87/10/02  22:38:11  geoff
  59.  * Modify expansion routines to exactly duplicate the capitalization
  60.  * rules implemented by ins_cap and cap_ok.
  61.  * 
  62.  * Revision 1.5  87/09/30  23:31:48  geoff
  63.  * Move some globals to ispell.h.  Add support for ignoreflagbits.
  64.  * Rationalize some array sizes.  Get rid of the checkbit calls and
  65.  * replace them with a macro call.
  66.  * 
  67.  * Revision 1.4  87/09/26  15:41:25  geoff
  68.  * Make the sizes of the word buffers consistent.
  69.  * 
  70.  * Revision 1.3  87/09/14  22:39:19  geoff
  71.  * Add copyright comments
  72.  * 
  73.  * Revision 1.2  87/09/09  00:19:43  geoff
  74.  * Replace a lot of #ifdef's on NO8BIT with use of SET_SIZE and NOPARITY.
  75.  * 
  76.  * Revision 1.1  87/07/20  22:56:14  geoff
  77.  * Initial revision
  78.  * 
  79.  */
  80.  
  81. /*
  82.  * Table-driven version of good.c.
  83.  *
  84.  * Geoff Kuenning, July 1987
  85.  */
  86.  
  87. #include <ctype.h>
  88. #include "config.h"
  89. #include "ispell.h"
  90.  
  91. extern struct dent *    lookup ();    /* Look up a dictionary entry */
  92.  
  93. extern char *        strcpy ();
  94.  
  95. /* Check possible affixes */
  96. chk_aff (word, ucword, len, ignoreflagbits, allhits)
  97.     ichar_t *        word;        /* Word to be checked */
  98.     ichar_t *        ucword;        /* Upper-case-only copy of word */
  99.     int            len;        /* The length of word/ucword */
  100.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  101.     int            allhits;    /* Keep going after first hit */
  102.     {
  103.     register ichar_t *    cp;        /* Pointer to char to index on */
  104.     struct flagptr *    ind;        /* Flag index table to test */
  105.  
  106.     pfx_list_chk (word, ucword, len, &pflagindex[0], ignoreflagbits, allhits);
  107.     cp = ucword;
  108.     ind = &pflagindex[*cp++];
  109.     while (ind->numents == 0  &&  ind->pu.fp != NULL)
  110.     {
  111.     if (*cp == 0)
  112.         return;
  113.     if (ind->pu.fp[0].numents)
  114.         {
  115.         pfx_list_chk (word, ucword, len, &ind->pu.fp[0],
  116.           ignoreflagbits, allhits);
  117.         if (numhits  &&  !allhits  &&  !cflag  &&  !ignoreflagbits)
  118.         return;
  119.         }
  120.     ind = &ind->pu.fp[*cp++];
  121.     }
  122.     pfx_list_chk (word, ucword, len, ind, ignoreflagbits, allhits);
  123.     if (numhits  &&  !allhits  &&  !cflag  &&  !ignoreflagbits)
  124.     return;
  125.     chk_suf (word, ucword, len, 0, (struct flagent *) NULL,
  126.       ignoreflagbits, allhits);
  127.     }
  128.  
  129. /* Check some prefix flags */
  130. pfx_list_chk (word, ucword, len, ind, ignoreflagbits, allhits)
  131.     ichar_t *        word;        /* Word to be checked */
  132.     ichar_t *        ucword;        /* Upper-case-only word */
  133.     int            len;        /* The length of ucword */
  134.     struct flagptr *    ind;        /* Flag index table */
  135.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  136.     int            allhits;    /* Keep going after first hit */
  137.     {
  138.     int            cond;        /* Condition number */
  139.     register ichar_t *    cp;        /* Pointer into end of ucword */
  140.     struct dent *    dent;        /* Dictionary entry we found */
  141.     int            entcount;    /* Number of entries to process */
  142.     register struct flagent *
  143.             flent;        /* Current table entry */
  144.     int            preadd;        /* Length added to tword2 as prefix */
  145.     register int    tlen;        /* Length of tword */
  146.     ichar_t        tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */
  147.     ichar_t        tword2[sizeof tword]; /* 2nd copy for ins_root_cap */
  148.  
  149.     for (flent = ind->pu.ent, entcount = ind->numents;
  150.       entcount > 0;
  151.       flent++, entcount--)
  152.     {
  153.     /*
  154.      * See if the prefix matches.
  155.      */
  156.     tlen = len - flent->affl + flent->stripl;
  157.     if (tlen > 0  &&  icharncmp (flent->affix, ucword, flent->affl) == 0
  158.       &&  tlen >= flent->numconds)
  159.         {
  160.         /*
  161.          * The prefix matches.  Remove it, replace it by the "strip"
  162.          * string (if any), and check the original conditions.
  163.          */
  164.         if (flent->stripl)
  165.         (void) icharcpy (tword, flent->strip);
  166.         (void) icharcpy (tword + flent->stripl, ucword + flent->affl);
  167.         cp = tword;
  168.         for (cond = 0;  cond < flent->numconds;  cond++)
  169.         {
  170.         if ((flent->conds[*cp++] & (1 << cond)) == 0)
  171.             break;
  172.         }
  173.         if (cond >= flent->numconds)
  174.         {
  175.         /*
  176.          * The conditions match.  See if the word is in the
  177.          * dictionary.
  178.          */
  179.         if (cflag)
  180.             flagpr (tword, BITTOCHAR (flent->flagbit), flent->stripl,
  181.               flent->affl, -1, 0);
  182.         else if (ignoreflagbits)
  183.             {
  184.             if ((dent = lookup (tword, 1)) != NULL)
  185.             {
  186.             cp = tword2;
  187.             if (flent->affl)
  188.                 {
  189.                 (void) icharcpy (cp, flent->affix);
  190.                 cp += flent->affl;
  191.                 *cp++ = '+';
  192.                 }
  193.             preadd = cp - tword2;
  194.             (void) icharcpy (cp, tword);
  195.             cp += tlen;
  196.             if (flent->stripl)
  197.                 {
  198.                 *cp++ = '-';
  199.                 (void) icharcpy (cp, flent->strip);
  200.                 }
  201.             (void) ins_root_cap (tword2, word,
  202.               flent->stripl, preadd,
  203.               0, (cp - tword2) - tlen - preadd,
  204.               dent, flent, (struct flagent *) NULL);
  205.             }
  206.             }
  207.         else if ((dent = lookup (tword, 1)) != NULL
  208.           &&  TSTMASKBIT (dent->mask, flent->flagbit))
  209.             {
  210.             if (numhits < MAX_HITS)
  211.             {
  212.             hits[numhits].dictent = dent;
  213.             hits[numhits].prefix = flent;
  214.             hits[numhits].suffix = NULL;
  215.             numhits++;
  216.             }
  217.             if (!allhits)
  218.             return;
  219.             }
  220.         /*
  221.          * Handle cross-products.
  222.          */
  223.         if (flent->flagflags & FF_CROSSPRODUCT)
  224.             chk_suf (word, tword, tlen, 1, flent,
  225.               ignoreflagbits, allhits);
  226.         }
  227.         }
  228.     }
  229.     }
  230.  
  231. /* Check possible suffixes */
  232. chk_suf (word, ucword, len, crossonly, pfxent, ignoreflagbits, allhits)
  233.     ichar_t *        word;        /* Word to be checked */
  234.     ichar_t *        ucword;        /* Upper-case-only word */
  235.     int            len;        /* The length of ucword */
  236.     int            crossonly;    /* NZ to do only cross-products */
  237.     struct flagent *    pfxent;        /* Prefix flag entry if crossonly */
  238.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  239.     int            allhits;    /* Keep going after first hit */
  240.     {
  241.     register ichar_t *    cp;        /* Pointer to char to index on */
  242.     struct flagptr *    ind;        /* Flag index table to test */
  243.  
  244.     suf_list_chk (word, ucword, len, &sflagindex[0], crossonly, pfxent,
  245.       ignoreflagbits, allhits);
  246.     cp = ucword + len - 1;
  247.     ind = &sflagindex[*cp];
  248.     while (ind->numents == 0  &&  ind->pu.fp != NULL)
  249.     {
  250.     if (cp == ucword)
  251.         return;
  252.     if (ind->pu.fp[0].numents)
  253.         {
  254.         suf_list_chk (word, ucword, len, &ind->pu.fp[0],
  255.           crossonly, pfxent, ignoreflagbits, allhits);
  256.         if (numhits != 0  &&  !allhits  &&  !cflag  &&  !ignoreflagbits)
  257.         return;
  258.         }
  259.     ind = &ind->pu.fp[*--cp];
  260.     }
  261.     suf_list_chk (word, ucword, len, ind, crossonly, pfxent,
  262.       ignoreflagbits, allhits);
  263.     }
  264.     
  265. suf_list_chk (word, ucword, len, ind, crossonly, pfxent,
  266.   ignoreflagbits, allhits)
  267.     ichar_t *        word;        /* Word to be checked */
  268.     ichar_t *        ucword;        /* Upper-case-only word */
  269.     int            len;        /* The length of ucword */
  270.     struct flagptr *    ind;        /* Flag index table */
  271.     int            crossonly;    /* NZ to do only cross-products */
  272.     struct flagent *    pfxent;        /* Prefix flag entry if crossonly */
  273.     int            ignoreflagbits;    /* Ignore whether affix is legal */
  274.     int            allhits;    /* Keep going after first hit */
  275.     {
  276.     register ichar_t *    cp;        /* Pointer into end of ucword */
  277.     int            cond;        /* Condition number */
  278.     struct dent *    dent;        /* Dictionary entry we found */
  279.     int            entcount;    /* Number of entries to process */
  280.     register struct flagent *
  281.             flent;        /* Current table entry */
  282.     int            preadd;        /* Length added to tword2 as prefix */
  283.     register int    tlen;        /* Length of tword */
  284.     ichar_t        tword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4]; /* Tmp cpy */
  285.     ichar_t        tword2[sizeof tword]; /* 2nd copy for ins_root_cap */
  286.  
  287.     (void) icharcpy (tword, ucword);
  288.     for (flent = ind->pu.ent, entcount = ind->numents;
  289.       entcount > 0;
  290.       flent++, entcount--)
  291.     {
  292.     if (crossonly  &&  (flent->flagflags & FF_CROSSPRODUCT) == 0)
  293.         continue;
  294.     /*
  295.      * See if the suffix matches.
  296.      */
  297.     tlen = len - flent->affl;
  298.     if (tlen > 0
  299.       &&  tlen + flent->stripl > 1
  300.       &&  (flent->affl == 0
  301.         ||  icharcmp (flent->affix, ucword + tlen) == 0)
  302.       &&  tlen + flent->stripl >= flent->numconds)
  303.         {
  304.         /*
  305.          * The suffix matches.  Remove it, replace it by the "strip"
  306.          * string (if any), and check the original conditions.
  307.          */
  308.         (void) icharcpy (tword, ucword);
  309.         cp = tword + tlen;
  310.         if (flent->stripl)
  311.         {
  312.         (void) icharcpy (cp, flent->strip);
  313.         tlen += flent->stripl;
  314.         cp = tword + tlen;
  315.         }
  316.         else
  317.         *cp = '\0';
  318.         for (cond = flent->numconds;  --cond >= 0;  )
  319.         {
  320.         if ((flent->conds[*--cp] & (1 << cond)) == 0)
  321.             break;
  322.         }
  323.         if (cond < 0)
  324.         {
  325.         /*
  326.          * The conditions match.  See if the word is in the
  327.          * dictionary.
  328.          */
  329.         if (cflag)
  330.             {
  331.             if (crossonly)
  332.             flagpr (tword, BITTOCHAR (pfxent->flagbit),
  333.               pfxent->stripl, pfxent->affl,
  334.               BITTOCHAR (flent->flagbit), flent->affl);
  335.             else
  336.             flagpr (tword, -1, 0, 0,
  337.               BITTOCHAR (flent->flagbit), flent->affl);
  338.             }
  339.         else if (ignoreflagbits)
  340.             {
  341.             if ((dent = lookup (tword, 1)) != NULL)
  342.             {
  343.             cp = tword2;
  344.             if (crossonly  &&  pfxent->affl != 0)
  345.                 {
  346.                 (void) icharcpy (cp, pfxent->affix);
  347.                 cp += pfxent->affl;
  348.                 *cp++ = '+';
  349.                 }
  350.             preadd = cp - tword2;
  351.             (void) icharcpy (cp, tword);
  352.             cp += tlen;
  353.             if (crossonly  &&  pfxent->stripl != 0)
  354.                 {
  355.                 *cp++ = '-';
  356.                 (void) icharcpy (cp, pfxent->strip);
  357.                 cp += pfxent->stripl;
  358.                 }
  359.             if (flent->stripl)
  360.                 {
  361.                 *cp++ = '-';
  362.                 (void) icharcpy (cp, flent->strip);
  363.                 cp += flent->stripl;
  364.                 }
  365.             if (flent->affl)
  366.                 {
  367.                 *cp++ = '+';
  368.                 (void) icharcpy (cp, flent->affix);
  369.                 cp += flent->affl;
  370.                 }
  371.             (void) ins_root_cap (tword2, word,
  372.               crossonly ? pfxent->stripl : 0, preadd,
  373.               flent->stripl, (cp - tword2) - tlen - preadd,
  374.               dent, pfxent, flent);
  375.             }
  376.             }
  377.         else if ((dent = lookup (tword, 1)) != NULL
  378.           &&  TSTMASKBIT (dent->mask, flent->flagbit)
  379.           &&  (!crossonly || TSTMASKBIT (dent->mask, pfxent->flagbit)))
  380.             {
  381.             if (numhits < MAX_HITS)
  382.             {
  383.             hits[numhits].dictent = dent;
  384.             hits[numhits].prefix = pfxent;
  385.             hits[numhits].suffix = flent;
  386.             numhits++;
  387.             }
  388.             if (!allhits)
  389.             return;
  390.             }
  391.         }
  392.         }
  393.     }
  394.     }
  395.  
  396. /*
  397.  * Expand a dictionary prefix entry
  398.  */
  399. expand_pre (rootword, mask)
  400.     ichar_t *            rootword;    /* Root word to expand */
  401.     register MASKTYPE        mask[];        /* Mask bits to expand on */
  402.     {
  403.     int                entcount;    /* No. of entries to process */
  404.     register struct flagent *
  405.                 flent;        /* Current table entry */
  406.  
  407.     for (flent = pflaglist, entcount = numpflags;
  408.       entcount > 0;
  409.       flent++, entcount--)
  410.     {
  411.     if (TSTMASKBIT (mask, flent->flagbit))
  412.         pr_pre_expansion (rootword, flent, mask);
  413.     }
  414.     }
  415.  
  416. pr_pre_expansion (rootword, flent, mask) /* Print a prefix expansion */
  417.     register ichar_t *        rootword; /* Root word to expand */
  418.     register struct flagent *    flent;    /* Current table entry */
  419.     MASKTYPE            mask[];        /* Mask bits to expand on */
  420.     {
  421.     int                cond;    /* Current condition number */
  422.     register ichar_t *        nextc;    /* Next case choice */
  423.     int                tlen;    /* Length of tword */
  424.     ichar_t            tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Tmp cpy */
  425.  
  426.     tlen = icharlen (rootword);
  427.     if (flent->numconds > tlen)
  428.     return;
  429.     if (tlen - flent->stripl + flent->affl <= 0)
  430.     return;
  431.     for (cond = 0, nextc = rootword;  cond < flent->numconds;  cond++)
  432.     {
  433.     if ((flent->conds[mytoupper (*nextc++)] & (1 << cond)) == 0)
  434.         return;
  435.     }
  436.     /*
  437.      * The conditions are satisfied.  Copy the word, add the prefix,
  438.      * and make it the proper case.   This code is carefully written
  439.      * to match that ins_cap and cap_ok.  Note that the affix, as
  440.      * inserted, is uppercase.
  441.      *
  442.      * There is a tricky bit here:  if the root is capitalized, we
  443.      * want a capitalized result.  If the root is followcase, however,
  444.      * we want to duplicate the case of the first remaining letter
  445.      * of the root.  In other words, "Loved/U" should generate "Unloved",
  446.      * but "LOved/U" should generate "UNLOved" and "lOved/U" should
  447.      * produce "unlOved".
  448.      */
  449.     if (flent->affl)
  450.     {
  451.     (void) icharcpy (tword, flent->affix);
  452.     nextc = tword + flent->affl;
  453.     }
  454.     (void) icharcpy (nextc, rootword + flent->stripl);
  455.     if (myupper (rootword[0]))
  456.     {
  457.     /* We must distinguish followcase from capitalized */
  458.     for (nextc = rootword + 1;  *nextc;  )
  459.         {
  460.         if (!myupper (*nextc++))
  461.         break;
  462.         }
  463.     if (*nextc)
  464.         {
  465.         /* It's a followcase or all-upper word.  We don't care which. */
  466.         if (!myupper (tword[flent->affl]));
  467.         forcelc (tword, flent->affl);
  468.         }
  469.     else
  470.         {
  471.         /* It's capitalized */
  472.         forcelc (tword + 1, tlen + flent->affl - flent->stripl);
  473.         }
  474.     }
  475.     else
  476.     {
  477.     /* Followcase or all-lower, we don't care which */
  478.     if (!myupper (*nextc));
  479.         forcelc (tword, flent->affl);
  480.     }
  481.     (void) printf (" %s", ichartosstr (tword, 1));
  482.     if (flent->flagflags & FF_CROSSPRODUCT)
  483.     expand_suf (tword, mask, 1);
  484.     }
  485.  
  486. /*
  487.  * Expand a dictionary suffix entry
  488.  */
  489. expand_suf (rootword, mask, crossonly)
  490.     ichar_t *            rootword;    /* Root word to expand */
  491.     register MASKTYPE        mask[];        /* Mask bits to expand on */
  492.     int                crossonly;    /* NZ for cross-products only */
  493.     {
  494.     int                entcount;    /* No. of entries to process */
  495.     register struct flagent *
  496.                 flent;        /* Current table entry */
  497.  
  498.     for (flent = sflaglist, entcount = numsflags;
  499.       entcount > 0;
  500.       flent++, entcount--)
  501.     {
  502.     if (TSTMASKBIT (mask, flent->flagbit))
  503.         {
  504.         if (!crossonly  ||  (flent->flagflags & FF_CROSSPRODUCT))
  505.         pr_suf_expansion (rootword, flent);
  506.         }
  507.     }
  508.     }
  509.  
  510. pr_suf_expansion (rootword, flent)    /* Print a suffix expansion */
  511.     register ichar_t *        rootword; /* Root word to expand */
  512.     register struct flagent *    flent;    /* Current table entry */
  513.     {
  514.     int                cond;    /* Current condition number */
  515.     register ichar_t *        nextc;    /* Next case choice */
  516.     int                tlen;    /* Length of tword */
  517.     ichar_t            tword[INPUTWORDLEN + MAXAFFIXLEN]; /* Tmp cpy */
  518.  
  519.     tlen = icharlen (rootword);
  520.     cond = flent->numconds;
  521.     if (cond > tlen)
  522.     return;
  523.     if (tlen - flent->stripl + flent->affl <= 0)
  524.     return;
  525.     for (nextc = rootword + tlen;  --cond >= 0;  )
  526.     {
  527.     if ((flent->conds[mytoupper (*--nextc)] & (1 << cond)) == 0)
  528.         return;
  529.     }
  530.     /*
  531.      * The conditions are satisfied.  Copy the word, add the suffix,
  532.      * and make it match the case of the last remaining character of the
  533.      * root.  Again, this code carefully matches ins_cap and cap_ok.
  534.      */
  535.     (void) icharcpy (tword, rootword);
  536.     nextc = tword + tlen - flent->stripl;
  537.     if (flent->affl)
  538.     {
  539.     (void) icharcpy (nextc, flent->affix);
  540.     if (!myupper (nextc[-1]))
  541.         forcelc (nextc, flent->affl);
  542.     }
  543.     else
  544.     *nextc = 0;
  545.     (void) printf (" %s", ichartosstr (tword, 1));
  546.     }
  547.  
  548. forcelc (dst, len)                /* Force to lowercase */
  549.     register ichar_t *        dst;        /* Destination to modify */
  550.     register int        len;        /* Length to copy */
  551.     {
  552.  
  553.     for (  ;  --len >= 0;  dst++)
  554.     *dst = mytolower (*dst);
  555.     }
  556.