source: trunk/third/ispell/correct.c @ 10334

Revision 10334, 43.0 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10333, which included commits to RCS files with non-trunk default branches.
Line 
1#ifndef lint
2static char Rcs_Id[] =
3    "$Id: correct.c,v 1.1.1.1 1997-09-03 21:08:10 ghudson Exp $";
4#endif
5
6/*
7 * correct.c - Routines to manage the higher-level aspects of spell-checking
8 *
9 * This code originally resided in ispell.c, but was moved here to keep
10 * file sizes smaller.
11 *
12 * Copyright (c), 1983, by Pace Willisson
13 *
14 * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 *
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 * 3. All modifications to the source code must be clearly marked as
27 *    such.  Binary redistributions based on modified source code
28 *    must be clearly marked as modified versions in the documentation
29 *    and/or other materials provided with the distribution.
30 * 4. All advertising materials mentioning features or use of this software
31 *    must display the following acknowledgment:
32 *      This product includes software developed by Geoff Kuenning and
33 *      other unpaid contributors.
34 * 5. The name of Geoff Kuenning may not be used to endorse or promote
35 *    products derived from this software without specific prior
36 *    written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 */
50
51/*
52 * $Log: not supported by cvs2svn $
53 * Revision 1.59  1995/08/05  23:19:43  geoff
54 * Fix a bug that caused offsets for long lines to be confused if the
55 * line started with a quoting uparrow.
56 *
57 * Revision 1.58  1994/11/02  06:56:00  geoff
58 * Remove the anyword feature, which I've decided is a bad idea.
59 *
60 * Revision 1.57  1994/10/26  05:12:39  geoff
61 * Try boundary characters when inserting or substituting letters, except
62 * (naturally) at word boundaries.
63 *
64 * Revision 1.56  1994/10/25  05:46:30  geoff
65 * Fix an assignment inside a conditional that could generate spurious
66 * warnings (as well as being bad style).  Add support for the FF_ANYWORD
67 * option.
68 *
69 * Revision 1.55  1994/09/16  04:48:24  geoff
70 * Don't pass newlines from the input to various other routines, and
71 * don't assume that those routines leave the input unchanged.
72 *
73 * Revision 1.54  1994/09/01  06:06:41  geoff
74 * Change erasechar/killchar to uerasechar/ukillchar to avoid
75 * shared-library problems on HP systems.
76 *
77 * Revision 1.53  1994/08/31  05:58:38  geoff
78 * Add code to handle extremely long lines in -a mode without splitting
79 * words or reporting incorrect offsets.
80 *
81 * Revision 1.52  1994/05/25  04:29:24  geoff
82 * Fix a bug that caused line widths to be calculated incorrectly when
83 * displaying lines containing tabs.  Fix a couple of places where
84 * characters were sign-extended incorrectly, which could cause 8-bit
85 * characters to be displayed wrong.
86 *
87 * Revision 1.51  1994/05/17  06:44:05  geoff
88 * Add support for controlled compound formation and the COMPOUNDONLY
89 * option to affix flags.
90 *
91 * Revision 1.50  1994/04/27  05:20:14  geoff
92 * Allow compound words to be formed from more than two components
93 *
94 * Revision 1.49  1994/04/27  01:50:31  geoff
95 * Add support to correctly capitalize words generated as a result of a
96 * missing-space suggestion.
97 *
98 * Revision 1.48  1994/04/03  23:23:02  geoff
99 * Clean up the code in missingspace() to be a bit simpler and more
100 * efficient.
101 *
102 * Revision 1.47  1994/03/15  06:24:23  geoff
103 * Fix the +/-/~ commands to be independent.  Allow the + command to
104 * receive a suffix which is a deformatter type (currently hardwired to
105 * be either tex or nroff/troff).
106 *
107 * Revision 1.46  1994/02/21  00:20:03  geoff
108 * Fix some bugs that could cause bad displays in the interaction between
109 * TeX parsing and string characters.  Show_char now will not overrun
110 * the inverse-video display area by accident.
111 *
112 * Revision 1.45  1994/02/14  00:34:51  geoff
113 * Fix correct to accept length parameters for ctok and itok, so that it
114 * can pass them to the to/from ichar routines.
115 *
116 * Revision 1.44  1994/01/25  07:11:22  geoff
117 * Get rid of all old RCS log lines in preparation for the 3.1 release.
118 *
119 */
120
121#include <ctype.h>
122#include "config.h"
123#include "ispell.h"
124#include "proto.h"
125#include "msgs.h"
126#include "version.h"
127
128void            givehelp P ((int interactive));
129void            checkfile P ((void));
130void            correct P ((char * ctok, int ctokl, ichar_t * itok, int itokl,
131                  char ** curchar));
132static void     show_line P ((char * line, char * invstart, int invlen));
133static int      show_char P ((char ** cp, int linew, int output, int maxw));
134static int      line_size P ((char * buf, char * bufend));
135static void     inserttoken P ((char * buf, char * start, char * tok,
136                  char ** curchar));
137static int      posscmp P ((char * a, char * b));
138int             casecmp P ((char * a, char * b, int canonical));
139void            makepossibilities P ((ichar_t * word));
140static int      insert P ((ichar_t * word));
141#ifndef NO_CAPITALIZATION_SUPPORT
142static void     wrongcapital P ((ichar_t * word));
143#endif /* NO_CAPITALIZATION_SUPPORT */
144static void     wrongletter P ((ichar_t * word));
145static void     extraletter P ((ichar_t * word));
146static void     missingletter P ((ichar_t * word));
147static void     missingspace P ((ichar_t * word));
148int             compoundgood P ((ichar_t * word, int pfxopts));
149static void     transposedletter P ((ichar_t * word));
150static void     tryveryhard P ((ichar_t * word));
151static int      ins_cap P ((ichar_t * word, ichar_t * pattern));
152static int      save_cap P ((ichar_t * word, ichar_t * pattern,
153                  ichar_t savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN]));
154int             ins_root_cap P ((ichar_t * word, ichar_t * pattern,
155                  int prestrip, int preadd, int sufstrip, int sufadd,
156                  struct dent * firstdent, struct flagent * pfxent,
157                  struct flagent * sufent));
158static void     save_root_cap P ((ichar_t * word, ichar_t * pattern,
159                  int prestrip, int preadd, int sufstrip, int sufadd,
160                  struct dent * firstdent, struct flagent * pfxent,
161                  struct flagent * sufent,
162                  ichar_t savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN],
163                  int * nsaved));
164static char *   getline P ((char * buf));
165void            askmode P ((void));
166void            copyout P ((char ** cc, int cnt));
167static void     lookharder P ((char * string));
168#ifdef REGEX_LOOKUP
169static void     regex_dict_lookup P ((char * cmd, char * grepstr));
170#endif /* REGEX_LOOKUP */
171
172void givehelp (interactive)
173    int             interactive;        /* NZ for interactive-mode help */
174    {
175#ifdef COMMANDFORSPACE
176    char ch;
177#endif
178    register FILE *helpout;     /* File to write help to */
179
180    if (interactive)
181        {
182        erase ();
183        helpout = stdout;
184        }
185    else
186        helpout = stderr;
187
188    (void) fprintf (helpout, CORR_C_HELP_1);
189    (void) fprintf (helpout, CORR_C_HELP_2);
190    (void) fprintf (helpout, CORR_C_HELP_3);
191    (void) fprintf (helpout, CORR_C_HELP_4);
192    (void) fprintf (helpout, CORR_C_HELP_5);
193    (void) fprintf (helpout, CORR_C_HELP_6);
194    (void) fprintf (helpout, CORR_C_HELP_7);
195    (void) fprintf (helpout, CORR_C_HELP_8);
196    (void) fprintf (helpout, CORR_C_HELP_9);
197
198    (void) fprintf (helpout, CORR_C_HELP_COMMANDS);
199
200    (void) fprintf (helpout, CORR_C_HELP_R_CMD);
201    (void) fprintf (helpout, CORR_C_HELP_BLANK);
202    (void) fprintf (helpout, CORR_C_HELP_A_CMD);
203    (void) fprintf (helpout, CORR_C_HELP_I_CMD);
204    (void) fprintf (helpout, CORR_C_HELP_U_CMD);
205    (void) fprintf (helpout, CORR_C_HELP_0_CMD);
206    (void) fprintf (helpout, CORR_C_HELP_L_CMD);
207    (void) fprintf (helpout, CORR_C_HELP_X_CMD);
208    (void) fprintf (helpout, CORR_C_HELP_Q_CMD);
209    (void) fprintf (helpout, CORR_C_HELP_BANG);
210    (void) fprintf (helpout, CORR_C_HELP_REDRAW);
211    (void) fprintf (helpout, CORR_C_HELP_SUSPEND);
212    (void) fprintf (helpout, CORR_C_HELP_HELP);
213
214    if (interactive)
215        {
216        (void) fprintf (helpout, "\r\n\r\n");
217        (void) fprintf (helpout, CORR_C_HELP_TYPE_SPACE);
218        (void) fflush (helpout);
219#ifdef COMMANDFORSPACE
220        ch = GETKEYSTROKE ();
221        if (ch != ' ' && ch != '\n' && ch != '\r')
222            (void) ungetc (ch, stdin);
223#else
224        while (GETKEYSTROKE () != ' ')
225            ;
226#endif
227        }
228    }
229
230void checkfile ()
231    {
232    int         bufno;
233    int         bufsize;
234    int         ch;
235
236    for (bufno = 0;  bufno < contextsize;  bufno++)
237        contextbufs[bufno][0] = '\0';
238
239    for (  ;  ;  )
240        {
241        for (bufno = contextsize;  --bufno > 0;  )
242            (void) strcpy (contextbufs[bufno],
243              contextbufs[bufno - 1]);
244        if (quit)       /* quit can't be set in l mode */
245            {
246            while (fgets (contextbufs[0],
247              sizeof contextbufs[0], infile) != NULL)
248                (void) fputs (contextbufs[0], outfile);
249            break;
250            }
251        /*
252         * Only read in enough characters to fill half this buffer so that any
253         * corrections we make are not likely to cause an overflow.
254         */
255        if (fgets (contextbufs[0], (sizeof contextbufs[0]) / 2, infile)
256          == NULL)
257            break;
258        /*
259         * If we didn't read to end-of-line, we may have ended the
260         * buffer in the middle of a word.  So keep reading until we
261         * see some sort of character that can't possibly be part of a
262         * word. (or until the buffer is full, which fortunately isn't
263         * all that likely).
264         */
265        bufsize = strlen (contextbufs[0]);
266        if (bufsize == (sizeof contextbufs[0]) / 2 - 1)
267            {
268            ch = (unsigned char) contextbufs[0][bufsize - 1];
269            while (bufsize < sizeof contextbufs[0] - 1
270              &&  (iswordch ((ichar_t) ch)  ||  isboundarych ((ichar_t) ch)
271              ||  isstringstart (ch)))
272                {
273                ch = getc (infile);
274                if (ch == EOF)
275                    break;
276                contextbufs[0][bufsize++] = (char) ch;
277                contextbufs[0][bufsize] = '\0';
278                }
279            }
280        checkline (outfile);
281        }
282    }
283
284void correct (ctok, ctokl, itok, itokl, curchar)
285    char *              ctok;
286    int                 ctokl;
287    ichar_t *           itok;
288    int                 itokl;
289    char **             curchar;
290    {
291    register int        c;
292    register int        i;
293    int                 col_ht;
294    int                 ncols;
295    char *              start_l2;
296    char *              begintoken;
297
298    begintoken = *curchar - strlen (ctok);
299
300    if (icharlen (itok) <= minword)
301        return;                 /* Accept very short words */
302
303checkagain:
304    if (good (itok, 0, 0, 0, 0)  ||  compoundgood (itok, 0))
305        return;
306
307    erase ();
308    (void) printf ("    %s", ctok);
309    if (currentfile)
310        (void) printf (CORR_C_FILE_LABEL, currentfile);
311    if (readonly)
312        (void) printf (" %s", CORR_C_READONLY);
313    (void) printf ("\r\n\r\n");
314
315    makepossibilities (itok);
316
317    /*
318     * Make sure we have enough room on the screen to hold the
319     * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
320     * is the maximum number of columns that will fit.  col_ht is the
321     * height of the columns.  The constant 4 allows 2 lines (1 blank) at
322     * the top of the screen, plus another blank line between the
323     * columns and the context, plus a final blank line at the bottom
324     * of the screen for command entry (R, L, etc).
325     */
326    col_ht = li - contextsize - 4 - minimenusize;
327    ncols = co / (maxposslen + 8);
328    if (pcount > ncols * col_ht)
329        pcount = ncols * col_ht;
330
331#ifdef EQUAL_COLUMNS
332    /*
333     * Equalize the column sizes.  The last column will be short.
334     */
335    col_ht = (pcount + ncols - 1) / ncols;
336#endif
337
338    for (i = 0; i < pcount; i++)
339        {
340#ifdef BOTTOMCONTEXT
341        move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
342#else /* BOTTOMCONTEXT */
343        move (3 + contextsize + (i % col_ht), (maxposslen + 8) * (i / col_ht));
344#endif /* BOTTOMCONTEXT */
345        if (i >= easypossibilities)
346            (void) printf ("??: %s", possibilities[i]);
347        else if (easypossibilities >= 10  &&  i < 10)
348            (void) printf ("0%d: %s", i, possibilities[i]);
349        else
350            (void) printf ("%2d: %s", i, possibilities[i]);
351        }
352
353#ifdef BOTTOMCONTEXT
354    move (li - contextsize - 1 - minimenusize, 0);
355#else /* BOTTOMCONTEXT */
356    move (2, 0);
357#endif /* BOTTOMCONTEXT */
358    for (i = contextsize;  --i > 0;  )
359        show_line (contextbufs[i], contextbufs[i], 0);
360
361    start_l2 = contextbufs[0];
362    if (line_size (contextbufs[0], *curchar) > co - (sg << 1) - 1)
363        {
364        start_l2 = begintoken - (co / 2);
365        while (start_l2 < begintoken)
366            {
367            i = line_size (start_l2, *curchar) + 1;
368            if (i + (sg << 1) <= co)
369                break;
370            start_l2 += i - co;
371            }
372        if (start_l2 > begintoken)
373            start_l2 = begintoken;
374        if (start_l2 < contextbufs[0])
375            start_l2 = contextbufs[0];
376        }
377    show_line (start_l2, begintoken, (int) strlen (ctok));
378
379    if (minimenusize != 0)
380        {
381        move (li - 2, 0);
382        (void) printf (CORR_C_MINI_MENU);
383        }
384
385    for (  ;  ;  )
386        {
387        (void) fflush (stdout);
388        switch (c = (GETKEYSTROKE () & NOPARITY))
389            {
390            case 'Z' & 037:
391                stop ();
392                erase ();
393                goto checkagain;
394            case ' ':
395                erase ();
396                (void) fflush (stdout);
397                return;
398            case 'q': case 'Q':
399                if (changes)
400                    {
401                    (void) printf (CORR_C_CONFIRM_QUIT);
402                    (void) fflush (stdout);
403                    c = (GETKEYSTROKE () & NOPARITY);
404                    }
405                else
406                    c = 'y';
407                if (c == 'y' || c == 'Y')
408                    {
409                    erase ();
410                    (void) fflush (stdout);
411                    done (0);
412                    }
413                goto checkagain;
414            case 'i': case 'I':
415                treeinsert (ichartosstr (strtosichar (ctok, 0), 1),
416                 ICHARTOSSTR_SIZE, 1);
417                erase ();
418                (void) fflush (stdout);
419                changes = 1;
420                return;
421            case 'u': case 'U':
422                itok = strtosichar (ctok, 0);
423                lowcase (itok);
424                treeinsert (ichartosstr (itok, 1), ICHARTOSSTR_SIZE, 1);
425                erase ();
426                (void) fflush (stdout);
427                changes = 1;
428                return;
429            case 'a': case 'A':
430                treeinsert (ichartosstr (strtosichar (ctok, 0), 1),
431                  ICHARTOSSTR_SIZE, 0);
432                erase ();
433                (void) fflush (stdout);
434                return;
435            case 'L' & 037:
436                goto checkagain;
437            case '?':
438                givehelp (1);
439                goto checkagain;
440            case '!':
441                {
442                char    buf[200];
443
444                move (li - 1, 0);
445                (void) putchar ('!');
446                if (getline (buf) == NULL)
447                    {
448                    (void) putchar (7);
449                    erase ();
450                    (void) fflush (stdout);
451                    goto checkagain;
452                    }
453                (void) printf ("\r\n");
454                (void) fflush (stdout);
455#ifdef  USESH
456                shescape (buf);
457#else
458                (void) shellescape (buf);
459#endif
460                erase ();
461                goto checkagain;
462                }
463            case 'r': case 'R':
464                move (li - 1, 0);
465                if (readonly)
466                    {
467                    (void) putchar (7);
468                    (void) printf ("%s ", CORR_C_READONLY);
469                    }
470                (void) printf (CORR_C_REPLACE_WITH);
471                if (getline (ctok) == NULL)
472                    {
473                    (void) putchar (7);
474                    /* Put it back */
475                    (void) ichartostr (ctok, itok, ctokl, 0);
476                    }
477                else
478                    {
479                    inserttoken (contextbufs[0],
480                      begintoken, ctok, curchar);
481                    if (strtoichar (itok, ctok, itokl, 0))
482                        {
483                        (void) putchar (7);
484                        (void) printf (WORD_TOO_LONG (ctok));
485                        }
486                    changes = 1;
487                    }
488                erase ();
489                if (icharlen (itok) <= minword)
490                    return;             /* Accept very short replacements */
491                goto checkagain;
492            case '0': case '1': case '2': case '3': case '4':
493            case '5': case '6': case '7': case '8': case '9':
494                i = c - '0';
495                if (easypossibilities >= 10)
496                    {
497                    c = GETKEYSTROKE () & NOPARITY;
498                    if (c >= '0'  &&  c <= '9')
499                        i = i * 10 + c - '0';
500                    else if (c != '\r'  &&  c != '\n')
501                        {
502                        (void) putchar (7);
503                        break;
504                        }
505                    }
506                if (i < easypossibilities)
507                    {
508                    (void) strcpy (ctok, possibilities[i]);
509                    changes = 1;
510                    inserttoken (contextbufs[0],
511                        begintoken, ctok, curchar);
512                    erase ();
513                    if (readonly)
514                        {
515                        move (li - 1, 0);
516                        (void) putchar (7);
517                        (void) printf ("%s", CORR_C_READONLY);
518                        (void) fflush (stdout);
519                        (void) sleep ((unsigned) 2);
520                        }
521                    return;
522                    }
523                (void) putchar (7);
524                break;
525            case '\r':  /* This makes typing \n after single digits */
526            case '\n':  /* ..less obnoxious */
527                break;
528            case 'l': case 'L':
529                {
530                char    buf[100];
531                move (li - 1, 0);
532                (void) printf (CORR_C_LOOKUP_PROMPT);
533                if (getline (buf) == NULL)
534                    {
535                    (void) putchar (7);
536                    erase ();
537                    goto checkagain;
538                    }
539                (void) printf ("\r\n");
540                (void) fflush (stdout);
541                lookharder (buf);
542                erase ();
543                goto checkagain;
544                }
545            case 'x': case 'X':
546                quit = 1;
547                erase ();
548                (void) fflush (stdout);
549                return;
550            default:
551                (void) putchar (7);
552                break;
553            }
554        }
555    }
556
557static void show_line (line, invstart, invlen)
558    char *              line;
559    register char *     invstart;
560    register int        invlen;
561    {
562    register int        width;
563
564    width = invlen ? (sg << 1) : 0;
565    while (line < invstart  &&  width < co - 1)
566        width += show_char (&line, width, 1, invstart - line);
567    if (invlen)
568        {
569        inverse ();
570        invstart += invlen;
571        while (line < invstart  &&  width < co - 1)
572            width += show_char (&line, width, 1, invstart - line);
573        normal ();
574        }
575    while (*line  &&  width < co - 1)
576        width += show_char (&line, width, 1, 0);
577    (void) printf ("\r\n");
578    }
579
580static int show_char (cp, linew, output, maxw)
581    register char **    cp;
582    int                 linew;
583    int                 output;         /* NZ to actually do output */
584    int                 maxw;           /* NZ to limit width shown */
585    {
586    register int        ch;
587    register int        i;
588    int                 len;
589    ichar_t             ichar;
590    register int        width;
591
592    ch = (unsigned char) **cp;
593    if (l1_isstringch (*cp, len, 0))
594        ichar = SET_SIZE + laststringch;
595    else
596        ichar = chartoichar (ch);
597    if (!vflag  &&  iswordch (ichar)  &&  len == 1)
598        {
599        if (output)
600            (void) putchar (ch);
601        (*cp)++;
602        return 1;
603        }
604    if (ch == '\t')
605        {
606        if (output)
607            (void) putchar ('\t');
608        (*cp)++;
609        return 8 - (linew & 0x07);
610        }
611    /*
612     * Character is non-printing, or it's ISO and vflag is set.  Display
613     * it in "cat -v" form.  For string characters, display every element
614     * separately in that form.
615     */
616    width = 0;
617    if (maxw != 0  &&  len > maxw)
618        len = maxw;                     /* Don't show too much */
619    for (i = 0;  i < len;  i++)
620        {
621        ch = (unsigned char) *(*cp)++;
622        if (ch > '\177')
623            {
624            if (output)
625                {
626                (void) putchar ('M');
627                (void) putchar ('-');
628                }
629            width += 2;
630            ch &= 0x7f;
631            }
632        if (ch < ' '  ||  ch == '\177')
633            {
634            if (output)
635                {
636                (void) putchar ('^');
637                if (ch == '\177')
638                    (void) putchar ('?');
639                else
640                    (void) putchar (ch + 'A' - '\001');
641                }
642            width += 2;
643            }
644        else
645            {
646            if (output)
647                (void) putchar (ch);
648            width += 1;
649            }
650        }
651    return width;
652    }
653
654static int line_size (buf, bufend)
655    char *              buf;
656    register char *     bufend;
657    {
658    register int        width;
659
660    for (width = 0;  buf < bufend  &&  *buf != '\0';  )
661        width += show_char (&buf, width, 0, bufend - buf);
662    return width;
663    }
664
665static void inserttoken (buf, start, tok, curchar)
666    char *              buf;
667    char *              start;
668    register char *     tok;
669    char **             curchar;
670    {
671    char                copy[BUFSIZ];
672    register char *     p;
673    register char *     q;
674    char *              ew;
675
676    (void) strcpy (copy, buf);
677
678    for (p = buf, q = copy; p != start; p++, q++)
679        *p = *q;
680    q += *curchar - start;
681    ew = skipoverword (tok);
682    while (tok < ew)
683        *p++ = *tok++;
684    *curchar = p;
685    if (*tok)
686        {
687
688        /*
689        ** The token changed to two words.  Split it up and save the
690        ** second one for later.
691        */
692
693        *p++ = *tok;
694        *tok++ = '\0';
695        while (*tok)
696            *p++ = *tok++;
697        }
698    while ((*p++ = *q++) != '\0')
699        ;
700    }
701
702static int posscmp (a, b)
703    char *              a;
704    char *              b;
705    {
706
707    return casecmp (a, b, 0);
708    }
709
710int casecmp (a, b, canonical)
711    char *              a;
712    char *              b;
713    int                 canonical;      /* NZ for canonical string chars */
714    {
715    register ichar_t *  ap;
716    register ichar_t *  bp;
717    ichar_t             inta[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
718    ichar_t             intb[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
719
720    (void) strtoichar (inta, a, sizeof inta, canonical);
721    (void) strtoichar (intb, b, sizeof intb, canonical);
722    for (ap = inta, bp = intb;  *ap != 0;  ap++, bp++)
723        {
724        if (*ap != *bp)
725            {
726            if (*bp == '\0')
727                return hashheader.sortorder[*ap];
728            else if (mylower (*ap))
729                {
730                if (mylower (*bp)  ||  mytoupper (*ap) != *bp)
731                    return (int) hashheader.sortorder[*ap]
732                      - (int) hashheader.sortorder[*bp];
733                }
734            else
735                {
736                if (myupper (*bp)  ||  mytolower (*ap) != *bp)
737                    return (int) hashheader.sortorder[*ap]
738                      - (int) hashheader.sortorder[*bp];
739                }
740            }
741        }
742    if (*bp != '\0')
743        return -(int) hashheader.sortorder[*bp];
744    for (ap = inta, bp = intb;  *ap;  ap++, bp++)
745        {
746        if (*ap != *bp)
747            {
748            return (int) hashheader.sortorder[*ap]
749              - (int) hashheader.sortorder[*bp];
750            }
751        }
752    return 0;
753    }
754
755void makepossibilities (word)
756    register ichar_t *  word;
757    {
758    register int        i;
759
760    for (i = 0; i < MAXPOSSIBLE; i++)
761        possibilities[i][0] = 0;
762    pcount = 0;
763    maxposslen = 0;
764    easypossibilities = 0;
765
766#ifndef NO_CAPITALIZATION_SUPPORT
767    wrongcapital (word);
768#endif
769
770/*
771 * according to Pollock and Zamora, CACM April 1984 (V. 27, No. 4),
772 * page 363, the correct order for this is:
773 * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION
774 * thus, it was exactly backwards in the old version. -- PWP
775 */
776
777    if (pcount < MAXPOSSIBLE)
778        missingletter (word);           /* omission */
779    if (pcount < MAXPOSSIBLE)
780        transposedletter (word);        /* transposition */
781    if (pcount < MAXPOSSIBLE)
782        extraletter (word);             /* insertion */
783    if (pcount < MAXPOSSIBLE)
784        wrongletter (word);             /* substitution */
785
786    if ((compoundflag != COMPOUND_ANYTIME)  &&  pcount < MAXPOSSIBLE)
787        missingspace (word);    /* two words */
788
789    easypossibilities = pcount;
790    if (easypossibilities == 0  ||  tryhardflag)
791        tryveryhard (word);
792
793    if ((sortit  ||  (pcount > easypossibilities))  &&  pcount)
794        {
795        if (easypossibilities > 0  &&  sortit)
796            qsort ((char *) possibilities,
797              (unsigned) easypossibilities,
798              sizeof (possibilities[0]),
799              (int (*) P ((const void *, const void *))) posscmp);
800        if (pcount > easypossibilities)
801            qsort ((char *) &possibilities[easypossibilities][0],
802              (unsigned) (pcount - easypossibilities),
803              sizeof (possibilities[0]),
804              (int (*) P ((const void *, const void *))) posscmp);
805        }
806    }
807
808static int insert (word)
809    register ichar_t *  word;
810    {
811    register int        i;
812    register char *     realword;
813
814    realword = ichartosstr (word, 0);
815    for (i = 0; i < pcount; i++)
816        {
817        if (strcmp (possibilities[i], realword) == 0)
818            return (0);
819        }
820
821    (void) strcpy (possibilities[pcount++], realword);
822    i = strlen (realword);
823    if (i > maxposslen)
824        maxposslen = i;
825    if (pcount >= MAXPOSSIBLE)
826        return (-1);
827    else
828        return (0);
829    }
830
831#ifndef NO_CAPITALIZATION_SUPPORT
832static void wrongcapital (word)
833    register ichar_t *  word;
834    {
835    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN];
836
837    /*
838    ** When the third parameter to "good" is nonzero, it ignores
839    ** case.  If the word matches this way, "ins_cap" will recapitalize
840    ** it correctly.
841    */
842    if (good (word, 0, 1, 0, 0))
843        {
844        (void) icharcpy (newword, word);
845        upcase (newword);
846        (void) ins_cap (newword, word);
847        }
848    }
849#endif
850
851static void wrongletter (word)
852    register ichar_t *  word;
853    {
854    register int        i;
855    register int        j;
856    register int        n;
857    ichar_t             savechar;
858    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN];
859
860    n = icharlen (word);
861    (void) icharcpy (newword, word);
862#ifndef NO_CAPITALIZATION_SUPPORT
863    upcase (newword);
864#endif
865
866    for (i = 0; i < n; i++)
867        {
868        savechar = newword[i];
869        for (j=0; j < Trynum; ++j)
870            {
871            if (Try[j] == savechar)
872                continue;
873            else if (isboundarych (Try[j])  &&  (i == 0  ||  i == n - 1))
874                continue;
875            newword[i] = Try[j];
876            if (good (newword, 0, 1, 0, 0))
877                {
878                if (ins_cap (newword, word) < 0)
879                    return;
880                }
881            }
882        newword[i] = savechar;
883        }
884    }
885
886static void extraletter (word)
887    register ichar_t *  word;
888    {
889    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN];
890    register ichar_t *  p;
891    register ichar_t *  r;
892
893    if (icharlen (word) < 2)
894        return;
895
896    (void) icharcpy (newword, word + 1);
897    for (p = word, r = newword;  *p != 0;  )
898        {
899        if (good (newword, 0, 1, 0, 0))
900            {
901            if (ins_cap (newword, word) < 0)
902                return;
903            }
904        *r++ = *p++;
905        }
906    }
907
908static void missingletter (word)
909    ichar_t *           word;
910    {
911    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN + 1];
912    register ichar_t *  p;
913    register ichar_t *  r;
914    register int        i;
915
916    (void) icharcpy (newword + 1, word);
917    for (p = word, r = newword;  *p != 0;  )
918        {
919        for (i = 0;  i < Trynum;  i++)
920            {
921            if (isboundarych (Try[i])  &&  r == newword)
922                continue;
923            *r = Try[i];
924            if (good (newword, 0, 1, 0, 0))
925                {
926                if (ins_cap (newword, word) < 0)
927                    return;
928                }
929            }
930        *r++ = *p++;
931        }
932    for (i = 0;  i < Trynum;  i++)
933        {
934        if (isboundarych (Try[i]))
935            continue;
936        *r = Try[i];
937        if (good (newword, 0, 1, 0, 0))
938            {
939            if (ins_cap (newword, word) < 0)
940                return;
941            }
942        }
943    }
944
945static void missingspace (word)
946    ichar_t *           word;
947    {
948    ichar_t             firsthalf[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
949    int                 firstno;        /* Index into first */
950    ichar_t *           firstp;         /* Ptr into current firsthalf word */
951    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN + 1];
952    int                 nfirsthalf;     /* No. words saved in 1st half */
953    int                 nsecondhalf;    /* No. words saved in 2nd half */
954    register ichar_t *  p;
955    ichar_t             secondhalf[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
956    int                 secondno;       /* Index into second */
957
958    /*
959    ** We don't do words of length less than 3;  this keeps us from
960    ** splitting all two-letter words into two single letters.  We
961    ** also don't do maximum-length words, since adding the space
962    ** would exceed the size of the "possibilities" array.
963    */
964    nfirsthalf = icharlen (word);
965    if (nfirsthalf < 3  ||  nfirsthalf >= INPUTWORDLEN + MAXAFFIXLEN - 1)
966        return;
967    (void) icharcpy (newword + 1, word);
968    for (p = newword + 1;  p[1] != '\0';  p++)
969        {
970        p[-1] = *p;
971        *p = '\0';
972        if (good (newword, 0, 1, 0, 0))
973            {
974            /*
975             * Save_cap must be called before good() is called on the
976             * second half, because it uses state left around by
977             * good().  This is unfortunate because it wastes a bit of
978             * time, but I don't think it's a significant performance
979             * problem.
980             */
981            nfirsthalf = save_cap (newword, word, firsthalf);
982            if (good (p + 1, 0, 1, 0, 0))
983                {
984                nsecondhalf = save_cap (p + 1, p + 1, secondhalf);
985                for (firstno = 0;  firstno < nfirsthalf;  firstno++)
986                    {
987                    firstp = &firsthalf[firstno][p - newword];
988                    for (secondno = 0;  secondno < nsecondhalf;  secondno++)
989                        {
990                        *firstp = ' ';
991                        (void) icharcpy (firstp + 1, secondhalf[secondno]);
992                        if (insert (firsthalf[firstno]) < 0)
993                            return;
994                        *firstp = '-';
995                        if (insert (firsthalf[firstno]) < 0)
996                            return;
997                        }
998                    }
999                }
1000            }
1001        }
1002    }
1003
1004int compoundgood (word, pfxopts)
1005    ichar_t *           word;
1006    int                 pfxopts;        /* Options to apply to prefixes */
1007    {
1008    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN];
1009    register ichar_t *  p;
1010    register ichar_t    savech;
1011    long                secondcap;      /* Capitalization of 2nd half */
1012
1013    /*
1014    ** If compoundflag is COMPOUND_NEVER, compound words are never ok.
1015    */
1016    if (compoundflag == COMPOUND_NEVER)
1017        return 0;
1018    /*
1019    ** Test for a possible compound word (for languages like German that
1020    ** form lots of compounds).
1021    **
1022    ** This is similar to missingspace, except we quit on the first hit,
1023    ** and we won't allow either member of the compound to be a single
1024    ** letter.
1025    **
1026    ** We don't do words of length less than 2 * compoundmin, since
1027    ** both halves must at least compoundmin letters.
1028    */
1029    if (icharlen (word) < 2 * hashheader.compoundmin)
1030        return 0;
1031    (void) icharcpy (newword, word);
1032    p = newword + hashheader.compoundmin;
1033    for (  ;  p[hashheader.compoundmin - 1] != 0;  p++)
1034        {
1035        savech = *p;
1036        *p = 0;
1037        if (good (newword, 0, 0, pfxopts, FF_COMPOUNDONLY))
1038            {
1039            *p = savech;
1040            if (good (p, 0, 1, FF_COMPOUNDONLY, 0)
1041              ||  compoundgood (p, FF_COMPOUNDONLY))
1042                {
1043                secondcap = whatcap (p);
1044                switch (whatcap (newword))
1045                    {
1046                    case ANYCASE:
1047                    case CAPITALIZED:
1048                    case FOLLOWCASE:    /* Followcase can have l.c. suffix */
1049                        return secondcap == ANYCASE;
1050                    case ALLCAPS:
1051                        return secondcap == ALLCAPS;
1052                    }
1053                }
1054            }
1055        else
1056            *p = savech;
1057        }
1058    return 0;
1059    }
1060
1061static void transposedletter (word)
1062    register ichar_t *  word;
1063    {
1064    ichar_t             newword[INPUTWORDLEN + MAXAFFIXLEN];
1065    register ichar_t *  p;
1066    register ichar_t    temp;
1067
1068    (void) icharcpy (newword, word);
1069    for (p = newword;  p[1] != 0;  p++)
1070        {
1071        temp = *p;
1072        *p = p[1];
1073        p[1] = temp;
1074        if (good (newword, 0, 1, 0, 0))
1075            {
1076            if (ins_cap (newword, word) < 0)
1077                return;
1078            }
1079        temp = *p;
1080        *p = p[1];
1081        p[1] = temp;
1082        }
1083    }
1084
1085static void tryveryhard (word)
1086    ichar_t *           word;
1087    {
1088    (void) good (word, 1, 0, 0, 0);
1089    }
1090
1091/* Insert one or more correctly capitalized versions of word */
1092static int ins_cap (word, pattern)
1093    ichar_t *           word;
1094    ichar_t *           pattern;
1095    {
1096    int                 i;              /* Index into savearea */
1097    int                 nsaved;         /* No. of words saved */
1098    ichar_t             savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
1099
1100    nsaved = save_cap (word, pattern, savearea);
1101    for (i = 0;  i < nsaved;  i++)
1102        {
1103        if (insert (savearea[i]) < 0)
1104            return -1;
1105        }
1106    return 0;
1107    }
1108
1109/* Save one or more correctly capitalized versions of word */
1110static int save_cap (word, pattern, savearea)
1111    ichar_t *           word;           /* Word to save */
1112    ichar_t *           pattern;        /* Prototype capitalization pattern */
1113    ichar_t             savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
1114                                        /* Room to save words */
1115    {
1116    int                 hitno;          /* Index into hits array */
1117    int                 nsaved;         /* Number of words saved */
1118    int                 preadd;         /* No. chars added to front of root */
1119    int                 prestrip;       /* No. chars stripped from front */
1120    int                 sufadd;         /* No. chars added to back of root */
1121    int                 sufstrip;       /* No. chars stripped from back */
1122
1123    if (*word == 0)
1124        return 0;
1125
1126    for (hitno = numhits, nsaved = 0;  --hitno >= 0  &&  nsaved < MAX_CAPS;  )
1127        {
1128        if (hits[hitno].prefix)
1129            {
1130            prestrip = hits[hitno].prefix->stripl;
1131            preadd = hits[hitno].prefix->affl;
1132            }
1133        else
1134            prestrip = preadd = 0;
1135        if (hits[hitno].suffix)
1136            {
1137            sufstrip = hits[hitno].suffix->stripl;
1138            sufadd = hits[hitno].suffix->affl;
1139            }
1140        else
1141            sufadd = sufstrip = 0;
1142        save_root_cap (word, pattern, prestrip, preadd,
1143            sufstrip, sufadd,
1144            hits[hitno].dictent, hits[hitno].prefix, hits[hitno].suffix,
1145            savearea, &nsaved);
1146        }
1147    return nsaved;
1148    }
1149
1150int ins_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd,
1151  firstdent, pfxent, sufent)
1152    register ichar_t *  word;
1153    register ichar_t *  pattern;
1154    int                 prestrip;
1155    int                 preadd;
1156    int                 sufstrip;
1157    int                 sufadd;
1158    struct dent *       firstdent;
1159    struct flagent *    pfxent;
1160    struct flagent *    sufent;
1161    {
1162    int                 i;              /* Index into savearea */
1163    ichar_t             savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
1164    int                 nsaved;         /* Number of words saved */
1165
1166    nsaved = 0;
1167    save_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd,
1168      firstdent, pfxent, sufent, savearea, &nsaved);
1169    for (i = 0;  i < nsaved;  i++)
1170        {
1171        if (insert (savearea[i]) < 0)
1172            return -1;
1173        }
1174    return 0;
1175    }
1176
1177/* ARGSUSED */
1178static void save_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd,
1179  firstdent, pfxent, sufent, savearea, nsaved)
1180    register ichar_t *  word;           /* Word to be saved */
1181    register ichar_t *  pattern;        /* Capitalization pattern */
1182    int                 prestrip;       /* No. chars stripped from front */
1183    int                 preadd;         /* No. chars added to front of root */
1184    int                 sufstrip;       /* No. chars stripped from back */
1185    int                 sufadd;         /* No. chars added to back of root */
1186    struct dent *       firstdent;      /* First dent for root */
1187    struct flagent *    pfxent;         /* Pfx-flag entry for word */
1188    struct flagent *    sufent;         /* Sfx-flag entry for word */
1189    ichar_t             savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
1190                                        /* Room to save words */
1191    int *               nsaved;         /* Number saved so far (updated) */
1192    {
1193#ifndef NO_CAPITALIZATION_SUPPORT
1194    register struct dent * dent;
1195#endif /* NO_CAPITALIZATION_SUPPORT */
1196    int                 firstisupper;
1197    ichar_t             newword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
1198#ifndef NO_CAPITALIZATION_SUPPORT
1199    register ichar_t *  p;
1200    int                 len;
1201    int                 i;
1202    int                 limit;
1203#endif /* NO_CAPITALIZATION_SUPPORT */
1204
1205    if (*nsaved >= MAX_CAPS)
1206        return;
1207    (void) icharcpy (newword, word);
1208    firstisupper = myupper (pattern[0]);
1209#ifdef NO_CAPITALIZATION_SUPPORT
1210    /*
1211    ** Apply the old, simple-minded capitalization rules.
1212    */
1213    if (firstisupper)
1214        {
1215        if (myupper (pattern[1]))
1216            upcase (newword);
1217        else
1218            {
1219            lowcase (newword);
1220            newword[0] = mytoupper (newword[0]);
1221            }
1222        }
1223    else
1224        lowcase (newword);
1225    (void) icharcpy (savearea[*nsaved], newword);
1226    (*nsaved)++;
1227    return;
1228#else /* NO_CAPITALIZATION_SUPPORT */
1229#define flagsareok(dent)    \
1230    ((pfxent == NULL \
1231        ||  TSTMASKBIT (dent->mask, pfxent->flagbit)) \
1232      &&  (sufent == NULL \
1233        ||  TSTMASKBIT (dent->mask, sufent->flagbit)))
1234
1235    dent = firstdent;
1236    if ((dent->flagfield & (CAPTYPEMASK | MOREVARIANTS)) == ALLCAPS)
1237        {
1238        upcase (newword);       /* Uppercase required */
1239        (void) icharcpy (savearea[*nsaved], newword);
1240        (*nsaved)++;
1241        return;
1242        }
1243    for (p = pattern;  *p;  p++)
1244        {
1245        if (mylower (*p))
1246            break;
1247        }
1248    if (*p == 0)
1249        {
1250        upcase (newword);       /* Pattern was all caps */
1251        (void) icharcpy (savearea[*nsaved], newword);
1252        (*nsaved)++;
1253        return;
1254        }
1255    for (p = pattern + 1;  *p;  p++)
1256        {
1257        if (myupper (*p))
1258            break;
1259        }
1260    if (*p == 0)
1261        {
1262        /*
1263        ** The pattern was all-lower or capitalized.  If that's
1264        ** legal, insert only that version.
1265        */
1266        if (firstisupper)
1267            {
1268            if (captype (dent->flagfield) == CAPITALIZED
1269              ||  captype (dent->flagfield) == ANYCASE)
1270                {
1271                lowcase (newword);
1272                newword[0] = mytoupper (newword[0]);
1273                (void) icharcpy (savearea[*nsaved], newword);
1274                (*nsaved)++;
1275                return;
1276                }
1277            }
1278        else
1279            {
1280            if (captype (dent->flagfield) == ANYCASE)
1281                {
1282                lowcase (newword);
1283                (void) icharcpy (savearea[*nsaved], newword);
1284                (*nsaved)++;
1285                return;
1286                }
1287            }
1288        while (dent->flagfield & MOREVARIANTS)
1289            {
1290            dent = dent->next;
1291            if (captype (dent->flagfield) == FOLLOWCASE
1292              ||  !flagsareok (dent))
1293                continue;
1294            if (firstisupper)
1295                {
1296                if (captype (dent->flagfield) == CAPITALIZED)
1297                    {
1298                    lowcase (newword);
1299                    newword[0] = mytoupper (newword[0]);
1300                    (void) icharcpy (savearea[*nsaved], newword);
1301                    (*nsaved)++;
1302                    return;
1303                    }
1304                }
1305            else
1306                {
1307                if (captype (dent->flagfield) == ANYCASE)
1308                    {
1309                    lowcase (newword);
1310                    (void) icharcpy (savearea[*nsaved], newword);
1311                    (*nsaved)++;
1312                    return;
1313                    }
1314                }
1315            }
1316        }
1317    /*
1318    ** Either the sample had complex capitalization, or the simple
1319    ** capitalizations (all-lower or capitalized) are illegal.
1320    ** Insert all legal capitalizations, including those that are
1321    ** all-lower or capitalized.  If the prototype is capitalized,
1322    ** capitalized all-lower samples.  Watch out for affixes.
1323    */
1324    dent = firstdent;
1325    p = strtosichar (dent->word, 1);
1326    len = icharlen (p);
1327    if (dent->flagfield & MOREVARIANTS)
1328        dent = dent->next;      /* Skip place-holder entry */
1329    for (  ;  ;  )
1330        {
1331        if (flagsareok (dent))
1332            {
1333            if (captype (dent->flagfield) != FOLLOWCASE)
1334                {
1335                lowcase (newword);
1336                if (firstisupper  ||  captype (dent->flagfield) == CAPITALIZED)
1337                    newword[0] = mytoupper (newword[0]);
1338                (void) icharcpy (savearea[*nsaved], newword);
1339                (*nsaved)++;
1340                if (*nsaved >= MAX_CAPS)
1341                    return;
1342                }
1343            else
1344                {
1345                /* Followcase is the tough one. */
1346                p = strtosichar (dent->word, 1);
1347                (void) bcopy ((char *) (p + prestrip),
1348                  (char *) (newword + preadd),
1349                  (len - prestrip - sufstrip) * sizeof (ichar_t));
1350                if (myupper (p[prestrip]))
1351                    {
1352                    for (i = 0;  i < preadd;  i++)
1353                        newword[i] = mytoupper (newword[i]);
1354                    }
1355                else
1356                    {
1357                    for (i = 0;  i < preadd;  i++)
1358                        newword[i] = mytolower (newword[i]);
1359                    }
1360                limit = len + preadd + sufadd - prestrip - sufstrip;
1361                i = len + preadd - prestrip - sufstrip;
1362                p += len - sufstrip - 1;
1363                if (myupper (*p))
1364                    {
1365                    for (p = newword + i;  i < limit;  i++, p++)
1366                        *p = mytoupper (*p);
1367                    }
1368                else
1369                    {
1370                    for (p = newword + i;  i < limit;  i++, p++)
1371                      *p = mytolower (*p);
1372                    }
1373                (void) icharcpy (savearea[*nsaved], newword);
1374                (*nsaved)++;
1375                if (*nsaved >= MAX_CAPS)
1376                    return;
1377                }
1378            }
1379        if ((dent->flagfield & MOREVARIANTS) == 0)
1380            break;              /* End of the line */
1381        dent = dent->next;
1382        }
1383    return;
1384#endif /* NO_CAPITALIZATION_SUPPORT */
1385    }
1386
1387static char * getline (s)
1388    register char *     s;
1389    {
1390    register char *     p;
1391    register int        c;
1392
1393    p = s;
1394
1395    for (  ;  ;  )
1396        {
1397        (void) fflush (stdout);
1398        c = (GETKEYSTROKE () & NOPARITY);
1399        if (c == '\\')
1400            {
1401            (void) putchar ('\\');
1402            (void) fflush (stdout);
1403            c = (GETKEYSTROKE () & NOPARITY);
1404            backup ();
1405            (void) putchar (c);
1406            *p++ = (char) c;
1407            }
1408        else if (c == ('G' & 037))
1409            return (NULL);
1410        else if (c == '\n' || c == '\r')
1411            {
1412            *p = 0;
1413            return (s);
1414            }
1415        else if (c == uerasechar)
1416            {
1417            if (p != s)
1418                {
1419                p--;
1420                backup ();
1421                (void) putchar (' ');
1422                backup ();
1423                }
1424            }
1425        else if (c == ukillchar)
1426            {
1427            while (p != s)
1428                {
1429                p--;
1430                backup ();
1431                (void) putchar (' ');
1432                backup ();
1433                }
1434            }
1435        else
1436            {
1437            *p++ = (char) c;
1438            (void) putchar (c);
1439            }
1440        }
1441    }
1442
1443void askmode ()
1444    {
1445    int                 bufsize;        /* Length of contextbufs[0] */
1446    int                 ch;             /* Next character read from input */
1447    register char *     cp1;
1448    register char *     cp2;
1449    ichar_t *           itok;           /* Ichar version of current word */
1450    int                 hadnl;          /* NZ if \n was at end of line */
1451
1452    if (fflag)
1453        {
1454        if (freopen (askfilename, "w", stdout) == NULL)
1455            {
1456            (void) fprintf (stderr, CANT_CREATE, askfilename);
1457            exit (1);
1458            }
1459        }
1460
1461    (void) printf ("%s\n", Version_ID[0]);
1462
1463    contextoffset = 0;
1464    while (1)
1465        {
1466        (void) fflush (stdout);
1467        /*
1468         * Only read in enough characters to fill half this buffer so that any
1469         * corrections we make are not likely to cause an overflow.
1470         */
1471        if (contextoffset == 0)
1472            {
1473            if (xgets (contextbufs[0], (sizeof contextbufs[0]) / 2, stdin)
1474              == NULL)
1475                break;
1476            }
1477        else
1478            {
1479            if (fgets (contextbufs[0], (sizeof contextbufs[0]) / 2, stdin)
1480              == NULL)
1481                break;
1482            }
1483        /*
1484         * If we didn't read to end-of-line, we may have ended the
1485         * buffer in the middle of a word.  So keep reading until we
1486         * see some sort of character that can't possibly be part of a
1487         * word. (or until the buffer is full, which fortunately isn't
1488         * all that likely).
1489         */
1490        bufsize = strlen (contextbufs[0]);
1491        if (contextbufs[0][bufsize - 1] == '\n')
1492            {
1493            hadnl = 1;
1494            contextbufs[0][--bufsize] = '\0';
1495            }
1496        else
1497            hadnl = 0;
1498        if (bufsize == (sizeof contextbufs[0]) / 2 - 1)
1499            {
1500            ch = (unsigned char) contextbufs[0][bufsize - 1];
1501            while (bufsize < sizeof contextbufs[0] - 1
1502              &&  (iswordch ((ichar_t) ch)  ||  isboundarych ((ichar_t) ch)
1503              ||  isstringstart (ch)))
1504                {
1505                ch = getc (stdin);
1506                if (ch == EOF)
1507                    break;
1508                contextbufs[0][bufsize++] = (char) ch;
1509                contextbufs[0][bufsize] = '\0';
1510                }
1511            }
1512        /*
1513        ** *line is like `i', @line is like `a', &line is like 'u'
1514        ** `#' is like `Q' (writes personal dictionary)
1515        ** `+' sets tflag, `-' clears tflag
1516        ** `!' sets terse mode, `%' clears terse
1517        ** `~' followed by a filename sets parameters according to file name
1518        ** `^' causes rest of line to be checked after stripping 1st char
1519        */
1520        if (contextoffset != 0)
1521            checkline (stdout);
1522        else
1523            {
1524            if (contextbufs[0][0] == '*'  ||  contextbufs[0][0] == '@')
1525                treeinsert(ichartosstr (strtosichar (contextbufs[0] + 1, 0), 1),
1526                  ICHARTOSSTR_SIZE,
1527                  contextbufs[0][0] == '*');
1528            else if (contextbufs[0][0] == '&')
1529                {
1530                itok = strtosichar (contextbufs[0] + 1, 0);
1531                lowcase (itok);
1532                treeinsert (ichartosstr (itok, 1), ICHARTOSSTR_SIZE, 1);
1533                }
1534            else if (contextbufs[0][0] == '#')
1535                {
1536                treeoutput ();
1537                math_mode = 0;
1538                LaTeX_Mode = 'P';
1539                }
1540            else if (contextbufs[0][0] == '!')
1541                terse = 1;
1542            else if (contextbufs[0][0] == '%')
1543                terse = 0;
1544            else if (contextbufs[0][0] == '-')
1545                {
1546                math_mode = 0;
1547                LaTeX_Mode = 'P';
1548                tflag = 0;
1549                }
1550            else if (contextbufs[0][0] == '+')
1551                {
1552                math_mode = 0;
1553                LaTeX_Mode = 'P';
1554                tflag = strcmp (&contextbufs[0][1], "nroff") != 0
1555                  &&  strcmp (&contextbufs[0][1], "troff") != 0;
1556                }
1557            else if (contextbufs[0][0] == '~')
1558                {
1559                defdupchar = findfiletype (&contextbufs[0][1], 1, (int *) NULL);
1560                if (defdupchar < 0)
1561                    defdupchar = 0;
1562                }
1563            else
1564                {
1565                if (contextbufs[0][0] == '^')
1566                    {
1567                    /* Strip off leading uparrow */
1568                    for (cp1 = contextbufs[0], cp2 = contextbufs[0] + 1;
1569                      (*cp1++ = *cp2++) != '\0';
1570                      )
1571                        ;
1572                    contextoffset++;
1573                    bufsize--;
1574                    }
1575                checkline (stdout);
1576                }
1577            }
1578        if (hadnl)
1579            contextoffset = 0;
1580        else
1581            contextoffset += bufsize;
1582#ifndef USG
1583        if (sflag)
1584            {
1585            stop ();
1586            if (fflag)
1587                {
1588                rewind (stdout);
1589                (void) creat (askfilename, 0666);
1590                }
1591            }
1592#endif
1593        }
1594    }
1595
1596/* Copy/ignore "cnt" number of characters pointed to by *cc. */
1597void copyout (cc, cnt)
1598    register char **    cc;
1599    register int        cnt;
1600    {
1601
1602    while (--cnt >= 0)
1603        {
1604        if (**cc == '\0')
1605            break;
1606        if (!aflag && !lflag)
1607            (void) putc (**cc, outfile);
1608        (*cc)++;
1609        }
1610    }
1611
1612static void lookharder (string)
1613    char *              string;
1614    {
1615    char                cmd[150];
1616    char                grepstr[100];
1617    register char *     g;
1618    register char *     s;
1619#ifndef REGEX_LOOKUP
1620    register int        wild = 0;
1621#ifdef LOOK
1622    static int          look = -1;
1623#endif /* LOOK */
1624#endif /* REGEX_LOOKUP */
1625
1626    g = grepstr;
1627    for (s = string; *s != '\0'; s++)
1628        {
1629        if (*s == '*')
1630            {
1631#ifndef REGEX_LOOKUP
1632            wild++;
1633#endif /* REGEX_LOOKUP */
1634            *g++ = '.';
1635            *g++ = '*';
1636            }
1637        else
1638            *g++ = *s;
1639        }
1640    *g = '\0';
1641    if (grepstr[0])
1642        {
1643#ifdef REGEX_LOOKUP
1644        regex_dict_lookup (cmd, grepstr);
1645#else /* REGEX_LOOKUP */
1646#ifdef LOOK
1647        /* now supports automatic use of look - gms */
1648        if (!wild && look)
1649            {
1650            /* no wild and look(1) is possibly available */
1651            (void) sprintf (cmd, "%s %s %s", LOOK, grepstr, WORDS);
1652            if (shellescape (cmd))
1653                return;
1654            else
1655                look = 0;
1656            }
1657#endif /* LOOK */
1658        /* string has wild card chars or look not avail */
1659        if (!wild)
1660            (void) strcat (grepstr, ".*");      /* work like look */
1661        (void) sprintf (cmd, "%s ^%s$ %s", EGREPCMD, grepstr, WORDS);
1662        (void) shellescape (cmd);
1663#endif /* REGEX_LOOKUP */
1664        }
1665    }
1666
1667#ifdef REGEX_LOOKUP
1668static void regex_dict_lookup (cmd, grepstr)
1669    char *              cmd;
1670    char *              grepstr;
1671    {
1672    char *              rval;
1673    int                 whence = 0;
1674    int                 quitlookup = 0;
1675    int                 count = 0;
1676    int                 ch;
1677
1678    (void) sprintf (cmd, "^%s$", grepstr);
1679    while (!quitlookup  &&  (rval = do_regex_lookup (cmd, whence)) != NULL)
1680        {
1681        whence = 1;
1682        (void) printf ("%s\r\n", rval);;
1683        if ((++count % (li - 1)) == 0)
1684            {
1685            inverse ();
1686            (void) printf (CORR_C_MORE_PROMPT);
1687            normal ();
1688            (void) fflush (stdout);
1689            if ((ch = GETKEYSTROKE ()) == 'q'
1690              ||  ch == 'Q'  ||  ch == 'x'  ||  ch == 'X' )
1691                 quitlookup = 1;
1692            /*
1693             * The following line should blank out the -- more -- even on
1694             * magic-cookie terminals.
1695             */
1696            (void) printf (CORR_C_BLANK_MORE);
1697            (void) fflush (stdout);
1698            }
1699        }
1700    if ( rval == NULL )
1701        {
1702        inverse ();
1703        (void) printf (CORR_C_END_LOOK);
1704        normal ();
1705        (void) fflush (stdout);
1706        (void) GETKEYSTROKE ();   
1707        }
1708    }
1709
1710#endif /* REGEX_LOOKUP */
Note: See TracBrowser for help on using the repository browser.