/* -*- Mode:Text -*- */
#ifndef lint
static char Rcs_Id[] =
    "$Id: correct.c,v 1.26 1992/01/07 10:04:48 geoff Exp $";
#endif

/*
 * correct.c - Routines to manage the higher-level aspects of spell-checking
 *
 * This code originally resided in ispell.c, but was moved here to keep
 * file sizes smaller.
 *
 * Copyright (c), 1983, by Pace Willisson
 *
 * Copyright 1987, 1988, 1989, by Geoff Kuenning, Manhattan Beach, CA
 * Permission for non-profit use is hereby granted.
 * All other rights reserved.
 * See "version.h" for a more complete copyright notice.
 */

/*
 * $Log: correct.c,v $
 * Revision 1.26  1992/01/07  10:04:48  geoff
 * Never fill the input buffers more than halfway; this helps to prevent
 * core dumps when inserting long words into long lines.
 *
 * Revision 1.25  1992/01/04  22:08:09  geoff
 * Make sure that casecmp returns a signed result.  Change
 * makepossibilities() to continue searching for corrections even if a
 * capitalization correction is found, so that (for example) the typo
 * "Dna" can be corrected to either "DNA" or "Dan".
 *
 * Revision 1.24  91/09/11  23:22:33  geoff
 * Remember to set the "changes" flag if words are added to the personal
 * dictionary.  With the "r" command, automatically accept a replacement
 * if it is extremely short.  Fix the calculation of the width of
 * highlighted words that contain stringchars.
 * 
 * Revision 1.23  91/09/04  14:35:32  geoff
 * At the beginning of askmode(), print the version ID as a handshake
 * with ispell.el.
 * 
 * Revision 1.22  91/08/10  16:38:20  geoff
 * Fix show_char to support display of ISO Latin-1 characters as-is (if
 * they are listed in the affix file), unless the "-V" flag is given.
 * Fix line_size to use show_char to measure character widths, to ensure
 * consistency.
 * 
 * Revision 1.21  91/07/27  20:48:15  geoff
 * Add the 'u' (add uncapitalized copy of the word) and help for it.
 * 
 * Revision 1.20  91/07/15  19:26:43  geoff
 * Make sure strings passed to treeinsert are in canonical form.  Provide
 * the "canonical" parameter to all strtoichar and strtosichar calls.
 * Add a "canonical" parameter to casecmp, and add "posscmp" to handle
 * sorting the possibilities list.
 * 
 * Revision 1.19  91/07/11  19:51:56  geoff
 * Remove the include of stdio.h, since ispell.h now does this.
 * 
 * Revision 1.18  91/07/05  20:31:52  geoff
 * Fix some more lint complaints.
 * 
 * Revision 1.17  91/07/05  19:51:37  geoff
 * Fix some lint complaints.
 * 
 * Revision 1.16  91/07/05  16:48:27  geoff
 * Change the "$" code in askmode to be "~", and add the "^" code to
 * allow spell-checking of lines that happen to begin with special codes.
 * 
 * Revision 1.15  91/07/03  18:20:22  geoff
 * Replace all conversions of chars to ichar_t's with a macro call which
 * (a) does the conversion correctly and (b) makes future changes easy in
 * case (a) is false.
 * 
 * Revision 1.14  91/06/23  22:08:47  geoff
 * When casting to ichar_t, cast to unsigned first to avoid sign-extension
 * problems.
 * 
 * Revision 1.13  91/05/27  21:35:00  geoff
 * Fix the 'r' command to re-check the word being replaced.  Add code to
 * askmode to support the '$' (set file suffix) command and fix the '+'
 * and '-' commands to set the preferred string character type appropriately.
 * 
 * Revision 1.12  90/12/31  00:58:56  geoff
 * Reformat to follow a consistent convention throughout ispell
 * 
 * Revision 1.11  90/10/14  01:51:30  geoff
 * Add Guy Shaw's improvements:  handle readonly files, record whether the
 * file has been changed, and don't verify quits if the file hasn't changed.
 * 
 * Revision 1.10  90/09/05  02:35:33  geoff
 * Don't put "type space to continue" in the command-line usage message.
 * When bcopy'ing the word in ins_root_cap, be sure to bcopy the whole
 * thing, remembering that it is an ichar_t.
 * 
 * Revision 1.9  90/04/28  00:51:00  geoff
 * Accept a null correction to delete a word
 * 
 * Revision 1.8  90/04/26  22:32:48  geoff
 * Add the canonicalize parameter to the calls to ichartostr and ichartosstr.
 * 
 * Revision 1.7  90/02/07  01:54:27  geoff
 * Replace ctoken (the argument) with ctok, to make both lint and me
 * happier.
 * 
 * Revision 1.6  89/12/27  22:24:52  geoff
 * Add minword support.
 * 
 * Revision 1.5  89/12/27  03:17:16  geoff
 * Move all messages to msgs.h so they can be reconfigured
 * 
 * Revision 1.4  89/10/20  00:10:06  geoff
 * Remove version.h
 * 
 * Revision 1.3  89/10/20  00:00:30  geoff
 * Fix extraletter so that it correctly tries deleting the last letter in
 * the word, as well as all others.
 * 
 * Revision 1.2  89/07/11  00:20:17  geoff
 * Add REGEX_LOOKUP support, based on that from luis@rice.edu.
 * 
 * Revision 1.1  89/06/27  01:55:42  geoff
 * Break ispell.c up into smaller files
 * 
 *
 * The following log lines are from when this code was in ispell.c:
 *
 * Revision 1.69  89/06/09  15:53:26  geoff
 * Add support for the internal "character" type, ichar_t.
 * 
 * Revision 1.67  89/04/27  23:31:25  geoff
 * Fix extraletter() to work properly with string characters (it didn't
 * actually delete the extra letter).  Get rid of a couple of duplicate
 * tests for backslashing the flag marker in dumpmode().
 * 
 * Revision 1.66  89/04/03  01:55:37  geoff
 * Add support for string characters and the selectable flag marker, and
 * fix some lint complaints.
 * 
 * Revision 1.65  89/02/27  02:22:06  geoff
 * Rohit Aggarwal's changes -- call givehelp() from Usage(), and add
 * the -M option and the mini-menu.
 * 
 * Revision 1.64  89/02/22  23:14:21  geoff
 * Add the -L switch and support for a variable-sized context.  Also fix the
 * bug that would unlink a file if it had a 14-character filename.  Finally,
 * fix a bug in ins_root_cap when CAPITALIZATION was turned off.
 * 
 * Revision 1.62  89/02/16  00:35:40  geoff
 * Add support for 'terse' mode as per Ken Stevens' suggestion.
 * 
 * Revision 1.61  88/12/26  02:28:21  geoff
 * Update and complete the copyright notice.
 * 
 * Revision 1.59  88/11/30  01:37:31  geoff
 * Fix a stupid bug in revision 1.57
 * 
 * Revision 1.58  88/11/27  00:05:01  geoff
 * Interchange the 'q' and 'x' commands;  this makes the command more
 * consistent with other Unix programs (quit means give up;  exit
 * means I'm done but this work is valid).
 * 
 * Revision 1.57  88/11/25  19:51:02  geoff
 * Fix casecmp to generate the same result regardless of argument order when
 * one string is a leading substring of the other.
 * 
 * Revision 1.56  88/11/17  23:15:25  geoff
 * Get rid of a minor warning from some compilers
 * 
 * Revision 1.52  88/06/25  17:48:26  geoff
 * Add support for the new switches -n, -b, -B, -C, -P, and -m, for the
 * keeping of TeX/nroff special characters in the hash header, and for
 * setting certain defaults in the hash header.  Note that the -B/-C switches
 * add the new routine "compoundgood", and the -P/-m switches replace
 * "nopossibilities" with "easypossibilities" and change the emacs output
 * format.
 * 
 * Revision 1.51  88/04/30  22:12:42  geoff
 * Fix a bunch of lint complaints, including a few honest bugs.
 * 
 * Revision 1.50  88/04/11  01:34:46  geoff
 * Fix checkline to do all output onto outfile (this is for cleanliness
 * only).  Change askmode output to include the character offset within
 * the line.  Change xgets calls to reflect the new calling sequence.  In
 * askmode, don't trim the input *line* to maximum *word* length!
 * 
 * Revision 1.47  88/03/27  00:59:17  geoff
 * Get rid of some spurious declarations that are already taken care of in
 * ispell.h.  Add ".hash" to end of hash file names if it's not already there.
 * Fix ins_root_cap to use the old-style capitalization rules if CAPITALIZATION
 * isn't defined.
 * 
 * Revision 1.46  88/02/20  23:11:30  geoff
 * Fix a bug that caused multiple single quotes (e.g., ``xx'' as in many
 * troff source files) to be considered as part of the word.  Major changes
 * to add support for the new capitalization handling.  If a word has wrong
 * capitalization, don't try other corrections.  Fix entdump to handle
 * flags with null affixes.
 * 
 * Revision 1.45  87/09/30  23:30:01  geoff
 * Move some globals to ispell.h.  Add the "nopossibilities" (tryveryhard)
 * code and stuff to support it.  Add "missingspace".  Improve "ins_cap"
 * to deal with affixes better.
 * 
 * Revision 1.44  87/09/26  15:41:40  geoff
 * Add code to limit input word lengths, and make the buffer sizes
 * consistent and reasonable.
 * 
 * Revision 1.43  87/09/09  00:17:44  geoff
 * Replace a lot of #ifdef's on NO8BIT with use of SET_SIZE and NOPARITY.  Fix
 * an error in the help messages.  Fix a bug in casecmp when two words matched
 * except for case.
 * 
 * Revision 1.41  87/09/03  23:43:45  geoff
 * Add Paul Placeway's fix to generate possibilites in the most likely order.
 * 
 * Revision 1.40  87/09/03  23:00:45  geoff
 * Integrate George Sipes latest changes:  dynamically determine availability
 * of look(1), accept commands at "type space" prompts, clean up help, add
 * TRUNCATEBAK code, make ^Z spawn a shell on USG.
 * 
 * Revision 1.39  87/08/28  21:20:40  geoff
 * Fix some errors in the usage messages.  Fancify the -v switch to
 * print a multi-line message.
 * 
 * Revision 1.38  87/08/18  21:19:51  geoff
 * Handle both forward and reverse quotes (accents) identically.  Assume that
 * all word characters (iswordch) occupy one screen position on the display.
 * 
 * Revision 1.37  87/08/13  20:46:58  geoff
 * Fix the apostrophe handling to work correctly independently of whether
 * the apostrophe is a member of "iswordch".
 * 
 * Revision 1.36  87/07/20  23:21:51  geoff
 * Add table-driving support and the -e and -D flags.  Also add support
 * for nodictflag.
 * 
 * Revision 1.35  87/06/27  12:19:29  geoff
 * Fix some minor help problems.  Add support for the "sg" option for
 * brain-damaged terminals (Michael Wester).
 * 
 * Revision 1.32  87/06/02  23:39:38  geoff
 * Rewrite rev 31 to be somewhat more efficient and elegant
 * 
 * Revision 1.31  87/06/02  01:53:10  geoff
 * Change the way wrongletter() handles case, so that it will work under
 * all circumstances.
 * 
 * Revision 1.29  87/05/25  21:10:33  geoff
 * Add my interpretation of Mark Davies' changes.
 * 
 * Revision 1.27  87/05/14  00:00:08  geoff
 * Fix tab handling in show_char
 * 
 * Revision 1.26  87/04/19  22:52:11  geoff
 * Add BAKEXT (George Sipe).  Add capitalization handling.
 * 
 * Revision 1.25  87/04/06  23:41:02  geoff
 * Get rid of some minor excess statements.  Calculate token length every
 * pass through correct's main loop.  Add an ifdef for EQUAL_COLUMNS.
 * Handle non-word characters correctly in inserttoken.
 * 
 * Revision 1.24  87/04/06  22:43:33  geoff
 * Fix a couple of errors in the usage message
 * 
 * Revision 1.22  87/04/01  17:23:47  geoff
 * Improve the long-line handling to deal with control chars
 * 
 * Revision 1.21  87/04/01  15:22:14  geoff
 * Integrate Joe Orost's V7/register changes into the main branch
 * 
 * Revision 1.18  87/03/31  16:40:59  geoff
 * Integrate Steve Kelem's changes into the main branch:  really wait for
 * a space in givehelp();  accept +/- in troff size strings, and automatically
 * set TeX mode if the file extension is ".tex".
 * 
 * Revision 1.16  87/03/29  01:58:16  geoff
 * Duplicate the original file's modes on temp and output files.  Really
 * generate 100 possibilities, not 99.  Don't assume 80 columns.  Handle
 * input lines wider than the terminal properly.
 * 
 * Revision 1.15  87/03/28  23:17:26  geoff
 * Make LOOK configurable
 * 
 * Revision 1.12  87/03/27  17:21:08  geoff
 * Add the -S option.  Greatly expand the size of the substitution list,
 * including multiple columns of suggetsions.
 * 
 * Revision 1.9  87/03/22  23:00:55  geoff
 * Integrate Perry Smith's emacs-support changes
 * 
 * Revision 1.7  87/03/01  00:56:34  geoff
 * Add a declaration of treeinsert.
 * 
 * Revision 1.3  87/01/19  00:05:46  geoff
 * Add USG support;  mostly #ifdef'ing out calls to stop().
 * 
 */

#include <ctype.h>
#include "config.h"
#include "ispell.h"
#include "msgs.h"
#include "version.h"

static void	    wrongcapital ();	/* Check for bad capitalization */

extern void	    treeinsert ();
extern void	    upcase ();
extern void	    lowcase ();
extern char *	    xgets ();

extern void	    exit ();
extern char *	    strcpy ();
extern char *	    strcat ();
extern void	    qsort ();

givehelp (interactive)
    int		    interactive;	/* NZ for interactive-mode help */
    {
#ifdef COMMANDFORSPACE
    char ch;
#endif
    register FILE *helpout;	/* File to write help to */

    if (interactive)
	{
	erase ();
	helpout = stdout;
	}
    else
	helpout = stderr;

    (void) fprintf (helpout, CORR_C_HELP_1);
    (void) fprintf (helpout, CORR_C_HELP_2);
    (void) fprintf (helpout, CORR_C_HELP_3);
    (void) fprintf (helpout, CORR_C_HELP_4);
    (void) fprintf (helpout, CORR_C_HELP_5);
    (void) fprintf (helpout, CORR_C_HELP_6);
    (void) fprintf (helpout, CORR_C_HELP_7);
    (void) fprintf (helpout, CORR_C_HELP_8);
    (void) fprintf (helpout, CORR_C_HELP_9);

    (void) fprintf (helpout, CORR_C_HELP_COMMANDS);

    (void) fprintf (helpout, CORR_C_HELP_R_CMD);
    (void) fprintf (helpout, CORR_C_HELP_BLANK);
    (void) fprintf (helpout, CORR_C_HELP_A_CMD);
    (void) fprintf (helpout, CORR_C_HELP_I_CMD);
    (void) fprintf (helpout, CORR_C_HELP_U_CMD);
    (void) fprintf (helpout, CORR_C_HELP_0_CMD);
    (void) fprintf (helpout, CORR_C_HELP_L_CMD);
    (void) fprintf (helpout, CORR_C_HELP_X_CMD);
    (void) fprintf (helpout, CORR_C_HELP_Q_CMD);
    (void) fprintf (helpout, CORR_C_HELP_BANG);
    (void) fprintf (helpout, CORR_C_HELP_REDRAW);
    (void) fprintf (helpout, CORR_C_HELP_SUSPEND);
    (void) fprintf (helpout, CORR_C_HELP_HELP);

    if (interactive)
	{
	(void) fprintf (helpout, "\r\n\r\n");
	(void) fprintf (helpout, CORR_C_HELP_TYPE_SPACE);
	(void) fflush (helpout);
#ifdef COMMANDFORSPACE
	ch = getchar ();
	if (ch != ' ' && ch != '\n' && ch != '\r')
	    ungetc (ch, stdin);
#else
	while (getchar () != ' ')
	    ;
#endif
	}
    }

static void initckch (wchars)
    char *		wchars;		/* Characters in -w option, if any */
    {
    register int	c;
    char		num[4];

    for (c = 0; c < SET_SIZE + hashheader.nstrchars; ++c)
	{
	if (iswordch (chartoichar (c)))
	    {
	    if (!mylower (chartoichar (c)))
		{
		Try[Trynum] = chartoichar (c);
		++Trynum;
		}
	    }
	}
    if (wchars != NULL)
	{
	while (Trynum < SET_SIZE  &&  *wchars != '\0')
	    {
	    if (*wchars != 'n'  &&  *wchars != '\\')
		{
		c = *wchars;
		++wchars;
		}
	    else
		{
		++wchars;
		num[0] = '\0'; 
		num[1] = '\0'; 
		num[2] = '\0'; 
		num[3] = '\0';
		if (isdigit (wchars[0]))
		    {
		    num[0] = wchars[0];
		    if (isdigit (wchars[1]))
			{
			num[1] = wchars[1];
			if (isdigit (wchars[2]))
			    num[2] = wchars[2];
			}
		    }
		if (wchars[-1] == 'n')
		    {
		    wchars += strlen (num);
		    c = atoi (num);
		    }
		else
		    {
		    wchars += strlen (num);
		    c = 0;
		    if (num[0])
			c = num[0] - '0';
		    if (num[1])
			{
			c <<= 3;
			c += num[1] - '0';
			}
		    if (num[2])
			{
			c <<= 3;
			c += num[2] - '0';
			}
		    }
		}
	    c &= NOPARITY;
	    if (!hashheader.wordchars[c])
		{
		hashheader.wordchars[c] = 1;
		hashheader.sortorder[c] = hashheader.sortval++;
		Try[Trynum] = c;
		++Trynum;
		}
	    }
	}
    }

checkfile ()
    {
    int		bufno;
    int		bufsize;
    int		ch;

    for (bufno = 0;  bufno < contextsize;  bufno++)
	contextbufs[bufno][0] = '\0';

    while (1)
	{
	for (bufno = contextsize;  --bufno > 0;  )
	    (void) strcpy (contextbufs[bufno],
	      contextbufs[bufno - 1]);
	if (quit)	/* quit can't be set in l mode */
	    {
	    while (fgets (contextbufs[0],
	      sizeof contextbufs[0], infile) != NULL)
		(void) fputs (contextbufs[0], outfile);
	    break;
	    }
	/*
	 * Only read in enough characters to fill half this buffer so that any
	 * corrections we make are not likely to cause an overflow.
	 */
	if (fgets (contextbufs[0], (sizeof contextbufs[0]) / 2, infile)
	  == NULL)
	    break;
	/*
	 * If we didn't read to end-of-line, we may have ended the
	 * buffer in the middle of a word.  So keep reading until we
	 * see some sort of character that can't possibly be part of a
	 * word. (or until the buffer is full, which fortunately isn't
	 * all that likely).
	 */
	bufsize = strlen (contextbufs[0]);
	if (bufsize == (sizeof contextbufs[0]) / 2 - 1)
	    {
	    ch = (unsigned char) contextbufs[0][bufsize - 1];
	    while (bufsize < sizeof contextbufs[0] - 1
	      &&  (iswordch (ch)  ||  isboundarych (ch)
	      ||  isstringstart (ch)))
		{
		ch = getc (infile);
		if (ch == EOF)
		    break;
		contextbufs[0][bufsize++] = ch;
		contextbufs[0][bufsize] = '\0';
		}
	    }
	checkline (outfile);
	}
    }

correct (ctok, itok, curchar)
    char *		ctok;
    ichar_t *		itok;
    char **		curchar;
    {
    register int	c;
    register int	i;
    int			col_ht;
    int			ncols;
    char *		start_l2;
    char *		begintoken;

    begintoken = *curchar - strlen (ctok);

    if (icharlen (itok) <= minword)
	return;			/* Accept very short words */

checkagain:
    if (good (itok, 0, 0)  ||  compoundgood (itok))
	return;

    erase ();
    (void) printf ("    %s", ctok);
    if (currentfile)
	(void) printf (CORR_C_FILE_LABEL, currentfile);
    if (readonly)
	(void) printf (" %s", CORR_C_READONLY);
    (void) printf ("\r\n\r\n");

    makepossibilities (itok);

    /*
     * Make sure we have enough room on the screen to hold the
     * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
     * is the maximum number of columns that will fit.  col_ht is the
     * height of the columns.  The constant 4 allows 2 lines (1 blank) at
     * the top of the screen, plus another blank line between the
     * columns and the context, plus a final blank line at the bottom
     * of the screen for command entry (R, L, etc).
     */
    col_ht = li - contextsize - 4 - minimenusize;
    ncols = co / (maxposslen + 8);
    if (pcount > ncols * col_ht)
	pcount = ncols * col_ht;

#ifdef EQUAL_COLUMNS
    /*
     * Equalize the column sizes.  The last column will be short.
     */
    col_ht = (pcount + ncols - 1) / ncols;
#endif

    for (i = 0; i < pcount; i++)
	{
	move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
	if (i >= easypossibilities)
	    (void) printf ("??: %s", possibilities[i]);
	else if (easypossibilities >= 10  &&  i < 10)
	    (void) printf ("0%d: %s", i, possibilities[i]);
	else
	    (void) printf ("%2d: %s", i, possibilities[i]);
	}

    move (li - contextsize - 1 - minimenusize, 0);
    for (i = contextsize;  --i > 0;  )
	show_line (contextbufs[i], contextbufs[i], 0);

    start_l2 = contextbufs[0];
    if (line_size (contextbufs[0], *curchar) > co - (sg << 1) - 1)
	{
	start_l2 = begintoken - (co / 2);
	while (start_l2 < begintoken)
	    {
	    i = line_size (start_l2, *curchar) + 1;
	    if (i + (sg << 1) <= co)
		break;
	    start_l2 += i - co;
	    }
	if (start_l2 > begintoken)
	    start_l2 = begintoken;
	if (start_l2 < contextbufs[0])
	    start_l2 = contextbufs[0];
	}
    show_line (start_l2, begintoken, strlen (ctok));

    if (minimenusize != 0)
	{
	move (li - 2, 0);
	(void) printf (CORR_C_MINI_MENU);
	}

    while (1)
	{
	(void) fflush (stdout);
	switch (c = (getchar () & NOPARITY))
	    {
	    case 'Z' & 037:
		stop ();
		erase ();
		goto checkagain;
	    case ' ':
		erase ();
		(void) fflush (stdout);
		return;
	    case 'q': case 'Q':
		if (changes)
		    {
		    (void) printf (CORR_C_CONFIRM_QUIT);
		    (void) fflush (stdout);
		    c = (getchar () & NOPARITY);
		    }
		else
		    c = 'y';
		if (c == 'y' || c == 'Y')
		    {
		    erase ();
		    (void) fflush (stdout);
		    done ();
		    }
		goto checkagain;
	    case 'i': case 'I':
		treeinsert (ichartosstr (strtosichar (ctok, 0), 1), 1);
		erase ();
		(void) fflush (stdout);
		changes = 1;
		return;
	    case 'u': case 'U':
		itok = strtosichar (ctok, 0);
		lowcase (itok);
		treeinsert (ichartosstr (itok, 1), 1);
		erase ();
		(void) fflush (stdout);
		changes = 1;
		return;
	    case 'a': case 'A':
		treeinsert (ichartosstr (strtosichar (ctok, 0), 1), 0);
		erase ();
		(void) fflush (stdout);
		return;
	    case 'L' & 037:
		goto checkagain;
	    case '?':
		givehelp (1);
		goto checkagain;
	    case '!':
		{
		char	buf[200];

		move (li - 1, 0);
		(void) putchar ('!');
		if (getline (buf) == NULL)
		    {
		    (void) putchar (7);
		    erase ();
		    (void) fflush (stdout);
		    goto checkagain;
		    }
		(void) printf ("\r\n");
		(void) fflush (stdout);
#ifdef	USESH
		shescape (buf);
#else
		(void) shellescape (buf);
#endif
		erase ();
		goto checkagain;
		}
	    case 'r': case 'R':
		move (li - 1, 0);
		if (readonly)
		    {
		    (void) putchar (7);
		    (void) printf ("%s ", CORR_C_READONLY);
		    }
		(void) printf (CORR_C_REPLACE_WITH);
		if (getline (ctok) == NULL)
		    {
		    (void) putchar (7);
		    ichartostr (ctok, itok, 0); /* Put it back */
		    }
		else
		    {
		    inserttoken (contextbufs[0],
		      begintoken, ctok, curchar);
		    strtoichar (itok, ctok, 0);
		    changes = 1;
		    }
		erase ();
		if (icharlen (itok) <= minword)
		    return;		/* Accept very short replacements */
		goto checkagain;
	    case '0': case '1': case '2': case '3': case '4':
	    case '5': case '6': case '7': case '8': case '9':
		i = c - '0';
		if (easypossibilities > 10)
		    {
		    c = getchar () & NOPARITY;
		    if (c >= '0'  &&  c <= '9')
			i = i * 10 + c - '0';
		    else if (c != '\r'  &&  c != '\n')
			{
			(void) putchar (7);
			break;
			}
		    }
		if (i < easypossibilities)
		    {
		    (void) strcpy (ctok, possibilities[i]);
		    changes = 1;
		    inserttoken (contextbufs[0],
			begintoken, ctok, curchar);
		    erase ();
		    if (readonly)
			{
			move (li - 1, 0);
			(void) putchar (7);
			(void) printf ("%s", CORR_C_READONLY);
			(void) fflush (stdout);
			sleep (2);
			}
		    return;
		    }
		(void) putchar (7);
		break;
	    case '\r':	/* This makes typing \n after single digits */
	    case '\n':	/* ..less obnoxious */
		break;
	    case 'l': case 'L':
		{
		char	buf[100];
		move (li - 1, 0);
		(void) printf (CORR_C_LOOKUP_PROMPT);
		if (getline (buf) == NULL)
		    {
		    (void) putchar (7);
		    erase ();
		    goto checkagain;
		    }
		(void) printf ("\r\n");
		(void) fflush (stdout);
		lookharder (buf);
		erase ();
		goto checkagain;
		}
	    case 'x': case 'X':
		quit = 1;
		erase ();
		(void) fflush (stdout);
		return;
	    default:
		(void) putchar (7);
		break;
	    }
	}
    }

show_line (line, invstart, invlen)
    char *		line;
    register char *	invstart;
    register int	invlen;
    {
    register int	width;

    width = invlen ? (sg << 1) : 0;
    width++;		/* To avoid writing last character on line */
    while (line != invstart  &&  width < co)
	width += show_char ((unsigned char **) &line, width, 1);
    if (invlen)
	{
	inverse ();
	invstart += invlen;
	while (line != invstart  &&  width < co)
	    width += show_char ((unsigned char **) &line, width, 1);
	normal ();
	}
    while (*line  &&  width < co)
	width += show_char ((unsigned char **) &line, width, 1);
    (void) printf ("\r\n");
    }

show_char (cp, linew, output)
    register unsigned char ** cp;
    int			linew;
    int			output;		/* NZ to actually do output */
    {
    register int	ch;
    register int	i;
    int			len;
    ichar_t		ichar;
    register int	width;

    ch = **cp;
    if (l1_isstringch (*cp, len, 0))
	ichar = SET_SIZE + laststringch;
    else
	ichar = chartoichar (ch);
    if (!vflag  &&  iswordch (ichar)  &&  len == 1)
	{
	if (output)
	    (void) putchar (ch);
	(*cp)++;
	return 1;
	}
    if (ch == '\t')
	{
	if (output)
	    (void) putchar ('\t');
	(*cp)++;
	return 8 - (linew & 0x07);
	}
    /*
     * Character is non-printing, or it's ISO and vflag is set.  Display
     * it in "cat -v" form.  For string characters, display every element
     * separately in that form.
     */
    width = 0;
    for (i = 0;  i < len;  i++)
	{
	ch = *(*cp)++;
	if (ch > '\177')
	    {
	    if (output)
		{
		(void) putchar ('M');
		(void) putchar ('-');
		}
	    width += 2;
	    ch &= 0x7f;
	    }
	if (ch < ' '  ||  ch == '\177')
	    {
	    if (output)
		{
		(void) putchar ('^');
		if (ch == '\177')
		    (void) putchar ('?');
		else
		    (void) putchar (ch + 'A' - '\001');
		}
	    width += 2;
	    }
	else
	    {
	    if (output)
		(void) putchar (ch);
	    width += 1;
	    }
	}
    return width;
    }

line_size (buf, bufend)
    char *		buf;
    register char *	bufend;
    {
    register int	width;

    for (width = 0;  buf < bufend  &&  *buf;  )
	width += show_char (&buf, width, 0);
    return width;
    }

inserttoken (buf, start, tok, curchar)
    char *		buf;
    char *		start; 
    register char *	tok;
    char **		curchar;
    {
    char		copy[BUFSIZ];
    register char *	p;
    register char *	q;
    char *		ew;
    char *		skipoverword ();

    (void) strcpy (copy, buf);

    for (p = buf, q = copy; p != start; p++, q++)
	*p = *q;
    q += *curchar - start;
    ew = skipoverword (tok);
    while (tok < ew)
	*p++ = *tok++;
    *curchar = p;
    if (*tok)
	{

	/*
	** The token changed to two words.  Split it up and save the
	** second one for later.
	*/

	*p++ = *tok;
	*tok++ = '\0';
	while (*tok)
	    *p++ = *tok++;
	}
    while (*p++ = *q++)
	;
    }

int posscmp (a, b)
    char *		a;
    char *		b;
    {

    return casecmp (a, b, 0);
    }

int casecmp (a, b, canonical)
    char *		a;
    char *		b;
    int			canonical;	/* NZ for canonical string chars */
    {
    register ichar_t *	ap;
    register ichar_t *	bp;
    ichar_t		inta[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
    ichar_t		intb[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];

    strtoichar (inta, a, canonical);
    strtoichar (intb, b, canonical);
    for (ap = inta, bp = intb;  *ap != 0;  ap++, bp++)
	{
	if (*ap != *bp)
	    {
	    if (*bp == '\0')
		return hashheader.sortorder[*ap];
	    else if (mylower (*ap))
		{
		if (mylower (*bp)  ||  mytoupper (*ap) != *bp)
		    return (int) hashheader.sortorder[*ap]
		      - (int) hashheader.sortorder[*bp];
		}
	    else
		{
		if (myupper (*bp)  ||  mytolower (*ap) != *bp)
		    return (int) hashheader.sortorder[*ap]
		      - (int) hashheader.sortorder[*bp];
		}
	    }
	}
    if (*bp != '\0')
	return -(int) hashheader.sortorder[*bp];
    for (ap = inta, bp = intb;  *ap;  ap++, bp++)
	{
	if (*ap != *bp)
	    {
	    return (int) hashheader.sortorder[*ap]
	      - (int) hashheader.sortorder[*bp];
	    }
	}
    return 0;
    }

makepossibilities (word)
    register ichar_t *	word;
    {
    register int	i;

    for (i = 0; i < MAXPOSSIBLE; i++)
	possibilities[i][0] = 0;
    pcount = 0;
    maxposslen = 0;
    easypossibilities = 0;

#ifdef CAPITALIZATION
    wrongcapital (word);
#endif

/* 
 * according to Pollock and Zamora, CACM April 1984 (V. 27, No. 4),
 * page 363, the correct order for this is:
 * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION
 * thus, it was exactly backwards in the old version. -- PWP
 */

    if (pcount < MAXPOSSIBLE)
	missingletter (word);		/* omission */
    if (pcount < MAXPOSSIBLE)
	transposedletter (word);	/* transposition */
    if (pcount < MAXPOSSIBLE)
	extraletter (word);		/* insertion */
    if (pcount < MAXPOSSIBLE)
	wrongletter (word);		/* substitution */

    if (missingspaceflag  &&  pcount < MAXPOSSIBLE)
	missingspace (word);	/* two words */

    easypossibilities = pcount;
    if (easypossibilities == 0  ||  tryhardflag)
	tryveryhard (word);

    if ((sortit  ||  (pcount > easypossibilities))  &&  pcount)
	{
	if (easypossibilities > 0  &&  sortit)
	    qsort ((char *) possibilities,
	      (unsigned) easypossibilities,
	      sizeof (possibilities[0]), posscmp);
	if (pcount > easypossibilities)
	    qsort ((char *) &possibilities[easypossibilities][0],
	      (unsigned) (pcount - easypossibilities),
	      sizeof (possibilities[0]), posscmp);
	}
    }

insert (word)
    register ichar_t *	word;
    {
    register int	i;
    register char *	realword;

    realword = ichartosstr (word, 0);
    for (i = 0; i < pcount; i++)
	{
	if (strcmp (possibilities[i], realword) == 0)
	    return (0);
	}

    (void) strcpy (possibilities[pcount++], realword);
    i = strlen (realword);
    if (i > maxposslen)
	maxposslen = i;
    if (pcount >= MAXPOSSIBLE)
	return (-1);
    else
	return (0);
    }

#ifdef CAPITALIZATION
static void wrongcapital (word)
    register ichar_t *	word;
    {
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN];

    /*
    ** When the third parameter to "good" is nonzero, it ignores
    ** case.  If the word matches this way, "ins_cap" will recapitalize
    ** it correctly.
    */
    if (good (word, 0, 1))
	{
	(void) icharcpy (newword, word);
	upcase (newword);
	(void) ins_cap (newword, word);
	}
    }
#endif

wrongletter (word)
    register ichar_t *	word;
    {
    register int	i;
    register int	j;
    register int	n;
    ichar_t		savechar;
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN];

    n = icharlen (word);
    (void) icharcpy (newword, word);
#ifdef CAPITALIZATION
    upcase (newword);
#endif

    for (i = 0; i < n; i++)
	{
	savechar = newword[i];
	for (j=0; j < Trynum; ++j)
	    {
	    newword[i] = Try[j];
	    if (good (newword, 0, 1))
		{
		if (ins_cap (newword, word) < 0)
		    return;
		}
	    }
	newword[i] = savechar;
	}
    }

extraletter (word)
    register ichar_t *	word;
    {
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN];
    register ichar_t *	p;
    register ichar_t *	r;

    if (icharlen (word) < 2)
	return;

    (void) icharcpy (newword, word + 1);
    for (p = word, r = newword;  *p != 0;  )
	{
	if (good (newword, 0, 1))
	    {
	    if (ins_cap (newword, word) < 0)
		return;
	    }
	*r++ = *p++;
	}
    }

missingletter (word)
    ichar_t *		word;
    {
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN + 1];
    register ichar_t *	p;
    register ichar_t *	r;
    register int	i;

    (void) icharcpy (newword + 1, word);
    for (p = word, r = newword;  *p != 0;  )
	{
	for (i = 0;  i < Trynum;  i++)
	    {
	    *r = Try[i];
	    if (good (newword, 0, 1))
		{
		if (ins_cap (newword, word) < 0)
		    return;
		}
	    }
	*r++ = *p++;
	}
    for (i = 0;  i < Trynum;  i++)
	{
	*r = Try[i];
	if (good (newword, 0, 1))
	    {
	    if (ins_cap (newword, word) < 0)
		return;
	    }
	}
    }

missingspace (word)
    ichar_t *		word;
    {
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN + 1];
    register ichar_t *	p;
    register ichar_t	savech;

    /*
    ** We don't do words of length less than 3;  this keeps us from
    ** splitting all two-letter words into two single letters.
    ** Also, we just duplicate the existing capitalizations, rather
    ** than try to reconstruct both, which would require a smarter
    ** version of ins_cap.
    */
    if (word[0] == 0  ||  word[1] == 0  ||  word[2] == 0)
	return;
    (void) icharcpy (newword, word);
    for (p = newword + 1;  *p != 0;  p++)
	{
	savech = *p;
	*p = 0;;
	if (good (newword, 0, 1))
	    {
	    *p = savech;
	    if (good (p, 0, 1))
		{
		*p = ' ';
		(void) icharcpy (p + 1, word + (p - newword));
		if (insert (newword) < 0)
		    return;
		*p = '-';
		if (insert (newword) < 0)
		    return;
		(void) icharcpy (p, word + (p - newword));
		}
	    }
	*p = savech;
	}
    }

compoundgood (word)
    ichar_t *		word;
    {
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN];
    register ichar_t *	p;
    register ichar_t	savech;

    /*
    ** If missingspaceflag is set, compound words are never ok.
    */
    if (missingspaceflag)
	return 0;
    /*
    ** Test for a possible compound word (for languages like German that
    ** form lots of compounds).
    **
    ** This is similar to missingspace, except we quit on the first hit,
    ** and we won't allow either member of the compound to be a single
    ** letter.
    **
    ** We don't do words of length less than 4, since both halves must
    ** at least two letters.
    */
    if (icharlen (word) < 4)
	return 0;
    (void) icharcpy (newword, word);
    p = newword + 2;
    for (  ;  p[1] != 0;  p++)
	{
	savech = *p;
	*p = 0;
	if (good (newword, 0, 0))
	    {
	    *p = savech;
	    if (good (p, 0, 0))
	      return 1;
	    }
	*p = savech;
	}
    return 0;
    }

transposedletter (word)
    register ichar_t *	word;
    {
    ichar_t		newword[INPUTWORDLEN + MAXAFFIXLEN];
    register ichar_t *	p;
    register ichar_t	temp;

    (void) icharcpy (newword, word);
    for (p = newword;  p[1] != 0;  p++)
	{
	temp = *p;
	*p = p[1];
	p[1] = temp;
	if (good (newword, 0, 1))
	    {
	    if (ins_cap (newword, word) < 0)
		return;
	    }
	temp = *p;
	*p = p[1];
	p[1] = temp;
	}
    }

tryveryhard (word)
    ichar_t *		word;
    {
    (void) good (word, 1, 0);
    }

/* Insert one or more correctly capitalized versions of word */
ins_cap (word, pattern)
    ichar_t *		word;
    ichar_t *		pattern;
    {
    int			prestrip;
    int			preadd;
    int			sufstrip;
    int			sufadd;
    int			hitno;

    if (*word == 0)
	return 0;

    for (hitno = numhits;  --hitno >= 0;  )
	{
	if (hits[hitno].prefix)
	    {
	    prestrip = hits[hitno].prefix->stripl;
	    preadd = hits[hitno].prefix->affl;
	    }
	else
	    prestrip = preadd = 0;
	if (hits[hitno].suffix)
	    {
	    sufstrip = hits[hitno].suffix->stripl;
	    sufadd = hits[hitno].suffix->affl;
	    }
	else
	    sufadd = sufstrip = 0;
	if (ins_root_cap (word, pattern, prestrip, preadd,
	    sufstrip, sufadd,
	    hits[hitno].dictent, hits[hitno].prefix, hits[hitno].suffix)
	  < 0)
	    return -1;
	}
    return 0;
    }

/* ARGSUSED */
ins_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd, firstdent,
  pfxent, sufent)
    register ichar_t *	word;
    register ichar_t *	pattern;
    int			prestrip;
    int			preadd;
    int			sufstrip;
    int			sufadd;
    struct dent *	firstdent;
    struct flagent *	pfxent;
    struct flagent *	sufent;
    {
#ifdef CAPITALIZATION
    register struct dent * dent;
#endif /* CAPITALIZATION */
    int			firstisupper;
    ichar_t		newword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
#ifdef CAPITALIZATION
    register ichar_t *	p;
    int			len;
    int			i;
    int			limit;
#endif /* CAPITALIZATION */

    (void) icharcpy (newword, word);
    firstisupper = myupper (pattern[0]);
#ifdef CAPITALIZATION
#define flagsareok(dent)    \
    ((pfxent == NULL \
	||  TSTMASKBIT (dent->mask, pfxent->flagbit)) \
      &&  (sufent == NULL \
	||  TSTMASKBIT (dent->mask, sufent->flagbit)))

    dent = firstdent;
    if ((dent->flagfield & (CAPTYPEMASK | MOREVARIANTS)) == ALLCAPS)
	{
	upcase (newword);	/* Uppercase required */
	return insert (newword);
	}
    for (p = pattern;  *p;  p++)
	{
	if (mylower (*p))
	    break;
	}
    if (*p == 0)
	{
	upcase (newword);	/* Pattern was all caps */
	return insert (newword);
	}
    for (p = pattern + 1;  *p;  p++)
	{
	if (myupper (*p))
	    break;
	}
    if (*p == 0)
	{
	/*
	** The pattern was all-lower or capitalized.  If that's
	** legal, insert only that version.
	*/
	if (firstisupper)
	    {
	    if (captype (dent->flagfield) == CAPITALIZED
	      ||  captype (dent->flagfield) == ANYCASE)
		{
		lowcase (newword);
		newword[0] = mytoupper (newword[0]);
		return insert (newword);
		}
	    }
	else
	    {
	    if (captype (dent->flagfield) == ANYCASE)
		{
		lowcase (newword);
		return insert (newword);
		}
	    }
	while (dent->flagfield & MOREVARIANTS)
	    {
	    dent = dent->next;
	    if (captype (dent->flagfield) == FOLLOWCASE
	      ||  !flagsareok (dent))
		continue;
	    if (firstisupper)
		{
		if (captype (dent->flagfield) == CAPITALIZED)
		    {
		    lowcase (newword);
		    newword[0] = mytoupper (newword[0]);
		    return insert (newword);
		    }
		}
	    else
		{
		if (captype (dent->flagfield) == ANYCASE)
		    {
		    lowcase (newword);
		    return insert (newword);
		    }
		}
	    }
	}
    /*
    ** Either the sample had complex capitalization, or the simple
    ** capitalizations (all-lower or capitalized) are illegal.
    ** Insert all legal capitalizations, including those that are
    ** all-lower or capitalized.  If the prototype is capitalized,
    ** capitalized all-lower samples.  Watch out for affixes.
    */
    dent = firstdent;
    p = strtosichar (dent->word, 1);
    len = icharlen (p);
    if (dent->flagfield & MOREVARIANTS)
	dent = dent->next;	/* Skip place-holder entry */
    while (1)
	{
	if (flagsareok (dent))
	    {
	    if (captype (dent->flagfield) != FOLLOWCASE)
		{
		lowcase (newword);
		if (firstisupper  ||  captype (dent->flagfield) == CAPITALIZED)
		    newword[0] = mytoupper (newword[0]);
		if (insert (newword) < 0)
		    return -1;
		}
	    else
		{
		/* Followcase is the tough one. */
		p = strtosichar (dent->word, 1);
		(void) bcopy ((char *) (p + prestrip),
		  (char *) (newword + preadd),
		  (len - prestrip - sufstrip) * sizeof (ichar_t));
		if (myupper (p[prestrip]))
		    {
		    for (i = 0;  i < preadd;  i++)
			newword[i] = mytoupper (newword[i]);
		    }
		else
		    {
		    for (i = 0;  i < preadd;  i++)
			newword[i] = mytolower (newword[i]);
		    }
		limit = len + preadd + sufadd - prestrip - sufstrip;
		i = len + preadd - prestrip - sufstrip;
		p += len - sufstrip - 1;
		if (myupper (*p))
		    {
		    for (p = newword + i;  i < limit;  i++, p++)
			*p = mytoupper (*p);
		    }
		else
		    {
		    for (p = newword + i;  i < limit;  i++, p++)
		      *p = mytolower (*p);
		    }
		if (insert (newword) < 0)
		    return -1;
		}
	    }
	if ((dent->flagfield & MOREVARIANTS) == 0)
	    break;		/* End of the line */
	dent = dent->next;
	}
    return 0;
#else
    /*
    ** Apply the old, simple-minded capitalization rules.
    */
    if (firstisupper)
	{
	if (myupper (pattern[1]))
	    upcase (newword);
	else
	    {
	    lowcase (newword);
	    newword[0] = mytoupper (newword[0]);
	    }
	}
    else
	lowcase (newword);
    return insert (newword);
#endif
    }

char * getline (s)
    register char *	s;
    {
    register char *	p;
    register int	c;

    p = s;

    while (1)
	{
	(void) fflush (stdout);
	c = (getchar () & NOPARITY);
	if (c == '\\')
	    {
	    (void) putchar ('\\');
	    (void) fflush (stdout);
	    c = (getchar () & NOPARITY);
	    backup ();
	    (void) putchar (c);
	    *p++ = c;
	    }
	else if (c == ('G' & 037))
	    return (NULL);
	else if (c == '\n' || c == '\r')
	    {
	    *p = 0;
	    return (s);
	    }
	else if (c == erasechar)
	    {
	    if (p != s)
		{
		p--;
		backup ();
		(void) putchar (' ');
		backup ();
		}
	    }
	else if (c == killchar)
	    {
	    while (p != s)
		{
		p--;
		backup ();
		(void) putchar (' ');
		backup ();
		}
	    }
	else
	    {
	    *p++ = c;
	    (void) putchar (c);
	    }
	}
    }

askmode ()
    {
    register char *	cp1;
    register char *	cp2;

    if (fflag)
	{
	if (freopen (askfilename, "w", stdout) == NULL)
	    {
	    (void) fprintf (stderr, CANT_CREATE, askfilename);
	    exit (1);
	    }
	}

    (void) printf ("%s\n", Version_ID[0]);
    (void) fflush (stdout);
    setbuf (stdin, (char *) NULL);
    setbuf (stdout, (char *) NULL);

    while (xgets (contextbufs[0], sizeof contextbufs[0], stdin) != NULL)
	{
	/*
	** *line is like `i', @line is like `a'
	** `#' is like `Q' (writes personal dictionary)
	** `+' sets tflag, `-' clears tflag
	** `!' sets terse mode, `%' clears terse
	** `~' followed by a filename sets parameters according to file name
	** `^' causes rest of line to be checked after stripping 1st char
	*/
	if (contextbufs[0][0] == '*'  ||  contextbufs[0][0] == '@')
	    treeinsert(ichartosstr (strtosichar (contextbufs[0] + 1, 0), 1),
	      contextbufs[0][0] == '*');
	else if (contextbufs[0][0] == '#')
	    {
	    treeoutput();
	    math_mode = 0;
	    LaTeX_Mode = 'P';
	    }
	else if (contextbufs[0][0] == '!')
	    terse = 1;
	else if (contextbufs[0][0] == '%')
	    terse = 0;
	else if (contextbufs[0][0] == '+' || contextbufs[0][0] == '-')
	    {
	    math_mode = 0;
	    LaTeX_Mode = 'P';
	    tflag = (contextbufs[0][0] == '+');
	    prefstringchar = findfiletype (tflag ? "tex" : "nroff", 1);
	    if (prefstringchar < 0)
		prefstringchar = 0;
	    defdupchar = prefstringchar;
	    }
	else if (contextbufs[0][0] == '~')
	    {
	    defdupchar = findfiletype (&contextbufs[0][1], 0);
	    if (defdupchar < 0)
		defdupchar = 0;
	    }
	else
	    {
	    if (contextbufs[0][0] == '^')
		{
		/* Strip off leading uparrow */
		for (cp1 = contextbufs[0], cp2 = contextbufs[0] + 1;
		  (*cp1++ = *cp2++) != '\0';
		  )
		    ;
		}
	    checkline(stdout);
	    }
#ifndef USG
	if (sflag)
	    {
	    stop ();
	    if (fflag)
		{
		rewind (stdout);
		(void) creat (askfilename, 0666);
		}
	    }
#endif
	}
    }

/* Copy/ignore "cnt" number of characters pointed to by *cc. */
copyout (cc, cnt)
    register char **	cc;
    register int	cnt;
    {

    while (--cnt >= 0)
	{
	if (**cc == '\0')
	    break;
	if (!aflag && !lflag)
	    (void) putc (**cc, outfile);
	(*cc)++;
	}
    }

lookharder(string)
    char *		string;
    {
    char		cmd[150];
    char		grepstr[100];
    register char *	g;
    register char *	s;
    register int	wild = 0;
#ifdef LOOK
    static int		look = -1;
#endif /* LOOK */

    g = grepstr;
    for (s = string; *s != '\0'; s++)
	{
	if (*s == '*')
	    {
	    wild++;
	    *g++ = '.';
	    *g++ = '*';
	    }
	else
	    *g++ = *s;
	}
    *g = '\0';
    if (grepstr[0])
	{
#ifdef REGEX_LOOKUP
	regex_dict_lookup (cmd, grepstr);
#else /* REGEX_LOOKUP */
#ifdef LOOK
	/* now supports automatic use of look - gms */
	if (!wild && look)
	    {
	    /* no wild and look(1) is possibly available */
	    (void) sprintf (cmd, "%s %s %s", LOOK, grepstr, WORDS);
	    if (shellescape (cmd))
		return;
	    else
		look = 0;
	    }
#endif /* LOOK */
	/* string has wild card chars or look not avail */
	if (!wild)
	    (void) strcat (grepstr, ".*");	/* work like look */
#ifdef OS2      
        /* check if system dictionary is defined */
        if(cfsysdict[0] == '\0')        
                strcpy(cfsysdict, WORDS);

        /* check if a search command is defined */
        if(cfegrepcmd[0] == '\0')
                strcpy(cfegrepcmd, EGREPCMD);

        	(void) sprintf (cmd, "%s ^%s$ %s", cfegrepcmd, grepstr, cfsysdict);
#else   /* OS2 */
	(void) sprintf (cmd, "%s ^%s$ %s", EGREPCMD, grepstr, WORDS);
#endif  /* OS2 */
	(void) shellescape (cmd);
#endif /* REGEX_LOOKUP */
	}
    }

#ifdef REGEX_LOOKUP
regex_dict_lookup (cmd, grepstr)
    char *		cmd;
    char *		grepstr;
    {
    char *		rval;
    int			whence = 0;
    int			quit = 0;
    int			count = 0;
    int			ch;

    sprintf (cmd, "^%s$", grepstr);
    while (!quit  &&  (rval = do_regex_lookup (cmd, whence)) != NULL)
	{
	whence = 1;
        printf ("%s\r\n", rval);;
	if ((++count % (li - 1)) == 0)
	    {
	    inverse ();
	    printf (CORR_C_MORE_PROMPT);
	    normal ();
	    if ((ch = getchar ()) == 'q'
	      ||  ch == 'Q'  ||  ch == 'x'  ||  ch == 'X' )
	         quit = 1;
	    /*
	     * The following line should blank out the -- more -- even on
	     * magic-cookie terminals.
	     */
	    printf (CORR_C_BLANK_MORE);
	    }
	}
    if ( rval == NULL )
	{
	inverse ();
	printf (CORR_C_END_LOOK);
	normal ();
	getchar ();    
	}
    }

#endif /* REGEX_LOOKUP */
