[comp.sources.misc] Ispell Version 2.0 Beta Part 03/04

allbery@ncoast.UUCP (05/31/87)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	ispell.c
#	ispell.el
#	ispell.h
#	lookup.c
#	makedict.sh
# This archive created: Sat May 30 17:13:36 1987
export PATH; PATH=/bin:$PATH
echo shar: extracting "'ispell.c'" '(25840 characters)'
if test -f 'ispell.c'
then
	echo shar: will not over-write existing file "'ispell.c'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.c'
X /* -*- Mode:Text -*- */
X 
X #define MAIN
X 
X /*
X  * ispell.c - An interactive spelling corrector.
X  *
X  * Copyright (c), 1983, by Pace Willisson
X  * Permission for non-profit use is hereby granted.
X  * All other rights reserved.
X  *
X  * 1987, Robert McQueer, added:
X  *	-w option & handling of extra legal word characters
X  *	-d option for alternate dictionary file
X  *	-p option & WORDLIST variable for alternate personal dictionary
X  *	-x option to suppress .bak files.
X  *	8 bit text & config.h parameters
X  * 1987, Geoff Kuenning, added:
X  *	-c option for creating suffix suggestions from raw words
X  *	suffixes in personal dictionary file
X  *	hashed personal dictionary file
X  *	-S option for unsorted word lists
X  * 1987, Greg Schaffer, added:
X  *	-T option (for TeX and LaTeX instead of troff) [later changed to -t]
X  *	   passes over \ till next whitespace.
X  *	   does not recognize % (comment)
X  */
X 
X #include <stdio.h>
X #include <ctype.h>
X #include <sys/param.h>
X #ifdef USG
X #include <sys/types.h>
X #endif
X #include <sys/stat.h>
X #include "config.h"
X #include "ispell.h"
X #include "version.h"
X 
X FILE *infile;
X FILE *outfile;
X 
X char hashname[MAXPATHLEN];
X 
X extern struct dent *treeinsert();
X extern char *upcase ();
X extern char *lowcase ();
X 
X extern char *rindex();
X extern char *strcpy ();
X 
X /*
X ** we use extended character set range specifically to allow intl.
X ** character set characters.  We are being REALLY paranoid about indexing
X ** this array - explicitly cast into unsigned INTEGER, then mask
X ** If NO8BIT is set, text will be masked to ascii range.
X */
X static int Trynum;
X #ifdef NO8BIT
X static char Try[128];
X static char Checkch[128];
X #define iswordch(X) (Checkch[((unsigned)(X))&0x7f])
X #else
X static char Try[256];
X static char Checkch[256];
X #define iswordch(X) (Checkch[((unsigned)(X))&0xff])
X #endif
X 
X static int sortit = 1;
X 
X givehelp ()
X {
X 	erase ();
X 	printf ("Whenever a word is found that is not in the dictionary,\r\n");
X 	printf ("it is printed on the first line of the screen.  If the dictionary\r\n");
X 	printf ("contains any similar words, they are listed with a single digit\r\n");
X 	printf ("next to each one.  You have the option of replacing the word\r\n");
X 	printf ("completely, or choosing one of the suggested words.\r\n");
X 	printf ("\r\n");
X 	printf ("Commands are:\r\n\r\n");
X 	printf ("R       Replace the misspelled word completely.\r\n");
X 	printf ("Space   Accept the word this time only\r\n");
X 	printf ("A       Accept the word for the rest of this file.\r\n");
X 	printf ("I       Accept the word, and put it in your private dictionary.\r\n");
X 	printf ("0-9     Replace with one of the suggested words.\r\n");
X 	printf ("L       Look up words in system dictionary.\r\n");
X 	printf ("Q       Write the rest of this file, ignoring misspellings, ");
X 	printf (         "and start next file.\r\n");
X 	printf ("X       Exit immediately.  Asks for confirmation.  ");
X 	printf (         "Leaves file unchanged.\r\n");
X 	printf ("!       Shell escape.\r\n");
X 	printf ("^L      Redraw screen.\r\n");
X 	printf ("\r\n\r\n");
X 	printf ("-- Type space to continue --");
X 	fflush (stdout);
X 	while (getchar () != ' ')
X 		;
X }
X 
X 
X char *getline();
X 
X int cflag = 0;
X int lflag = 0;
X int incfileflag = 0;
X int aflag = 0;
X int fflag = 0;
X #ifndef USG
X int sflag = 0;
X #endif
X int xflag = 0;
X int tflag = 0;
X 
X char *askfilename;
X 
X static char *Cmd;
X 
X usage ()
X {
X 	fprintf (stderr,
X 	    "Usage: %s [-dfile | -pfile | -wchars | -t | -x | -S] file .....\n",
X 	    Cmd);
X 	fprintf (stderr,
X 	    "       %s [-dfile | -pfile | -wchars | -t] -l\n",
X 	    Cmd);
X #ifndef USG
X 	fprintf (stderr,
X 	    "       %s [-dfile | -pfile | -ffile | -t | -s] {-a | -A}\n",
X 	    Cmd);
X #else
X 	fprintf (stderr,
X 	    "       %s [-dfile | -pfile | -ffile | -t] {-a | -A}\n",
X 	    Cmd);
X #endif
X 	fprintf (stderr, "       %s [-wchars] -c\n", Cmd);
X 	fprintf (stderr, "       %s -v\n", Cmd);
X 	exit (1);
X }
X 
X static initckch()
X {
X 	register int c;
X 
X 	Trynum = 0;
X #ifdef NO8BIT
X 	for (c = 0; c < 128; ++c) {
X #else
X 	for (c = 0; c < 256; ++c) {
X #endif
X 		if (myalpha((char) c)) {
X 			Checkch[c] = (char) 1;
X 			if (myupper((char) c)) {
X 				Try[Trynum] = (char) c;
X 				++Trynum;
X 			}
X 		}
X 		else
X 			Checkch[c] = (char) 0;
X 	}
X }
X 
X main (argc, argv)
X char **argv;
X {
X 	char *p;
X 	char *cpd;
X 	char num[4];
X 	unsigned mask;
X 	static char outbuf[BUFSIZ];
X 
X 	Cmd = *argv;
X 
X 	initckch();
X 	sprintf(hashname,"%s/%s",LIBDIR,DEFHASH);
X 
X 	cpd = NULL;
X 
X 	argv++;
X 	argc--;
X 	while (argc && **argv == '-') {
X 		switch ((*argv)[1]) {
X 		case 'v':
X 			printf ("%s\n", Version_ID);
X 			exit (0);
X 		case 't':
X 			tflag++;
X 			break;
X 		case 'A':
X 			incfileflag = 1;
X 			aflag = 1;
X 			break;
X 		case 'a':
X 			aflag++;
X 			break;
X 		case 'c':
X 			cflag++;
X 			lflag++;
X 			break;
X 		case 'x':
X 			xflag++;
X 			break;
X 		case 'f':
X 			fflag++;
X 			p = (*argv)+2;
X 			if (*p == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				p = *argv;
X 			}
X 			askfilename = p;
X 			break;
X 		case 'l':
X 			lflag++;
X 			break;
X #ifndef USG
X 		case 's':
X 			sflag++;
X 			break;
X #endif
X 		case 'S':
X 			sortit = 0;
X 			break;
X 		case 'p':
X 			cpd = (*argv)+2;
X 			if (*cpd == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				cpd = *argv;
X 			}
X 			break;
X 		case 'd':
X 			p = (*argv)+2;
X 			if (*p == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				p = *argv;
X 			}
X 			if (*p == '/')
X 				strcpy(hashname,p);
X 			else
X 				sprintf(hashname,"%s/%s",LIBDIR,p);
X 			break;
X 		case 'w':
X 			num[3] = '\0';
X #ifdef NO8BIT
X 			mask = 0x7f;
X #else
X 			mask = 0xff;
X #endif
X 			p = (*argv)+2;
X 			if (*p == '\0') {
X 				argv++; argc--;
X 				if (argc == 0)
X 					usage ();
X 				p = *argv;
X 			}
X 			while (Trynum <= mask && *p != '\0') {
X 				if (*p != 'n'  &&  *p != '\\') {
X 					Checkch[((unsigned)(*p))&mask] = (char) 1;
X 					Try[Trynum] = *p & mask;
X 					++p;
X 				}
X 				else {
X 					++p;
X 					num[0] = '\0'; 
X 					num[1] = '\0'; 
X 					num[2] = '\0'; 
X 					num[3] = '\0';
X 					if (isdigit (p[0]))
X 						num[0] = p[0];
X 					if (isdigit (p[1]))
X 						num[1] = p[1];
X 					if (isdigit (p[2]))
X 						num[2] = p[2];
X 					if (p[-1] == 'n') {
X 						p += strlen (num);
X 						num[0] = atoi (num);
X 					}
X 					else {
X 						p += strlen (num);
X 						if (num[0])
X 							num[0] -= '0';
X 						if (num[1]) {
X 							num[0] <<= 3;
X 							num[0] += num[1] - '0';
X 						}
X 						if (num[2]) {
X 							num[0] <<= 3;
X 							num[0] += num[2] - '0';
X 						}
X 					}
X 					Try[Trynum] = num[0] & mask;
X 					Checkch[num[0] & mask] = 1;
X 				}
X 				++Trynum;
X 			}
X 			break;
X 		default:
X 			usage();
X 		}
X 		argv++; argc--;
X 	}
X 
X 	if (!argc && !lflag && !aflag)
X 		usage ();
X 
X 	if (linit () < 0)
X 		exit (0);
X 
X 	treeinit (cpd);
X 
X 	if (aflag) {
X 		askmode ();
X 		exit (0);
X 	}
X 
X 	setbuf (stdout, outbuf);
X 	if (lflag) {
X 		infile = stdin;
X 		checkfile ();
X 		exit (0);
X 	}
X 
X 	terminit ();
X 
X 	while (argc--)
X 		dofile (*argv++);
X 
X 	done ();
X }
X 
X char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
X char *currentchar;
X char token[BUFSIZ];
X 
X int quit;
X 
X char *currentfile = NULL;
X 
X dofile (filename)
X char *filename;
X {
X 	int c;
X 	char	bakfile[256];
X 	struct stat statbuf;
X 	char *cp;
X 
X 	currentfile = filename;
X 
X 	if ((infile = fopen (filename, "r")) == NULL) {
X 		fprintf (stderr, "Can't open %s\r\n", filename);
X 		sleep (2);
X 		return;
X 	}
X 
X 	if (access (filename, 2) < 0) {
X 		fprintf (stderr, "Can't write to %s\r\n", filename);
X 		sleep (2);
X 		return;
X 	}
X 
X 	fstat (fileno (infile), &statbuf);
X 	strcpy(tempfile, TEMPNAME);
X 	mktemp (tempfile);
X 	chmod (tempfile, statbuf.st_mode);
X 	if ((outfile = fopen (tempfile, "w")) == NULL) {
X 		fprintf (stderr, "Can't create %s\r\n", tempfile);
X 		sleep (2);
X 		return;
X 	}
X 
X 	quit = 0;
X 
X 	/* See if the file is a .tex file.  If so, set the appropriate flag. */
X 	if ((cp = rindex (filename, '.')) != NULL  &&  strcmp (cp, ".tex") == 0)
X 		tflag = 1;
X 	checkfile ();
X 
X 	fclose (infile);
X 	fclose (outfile);
X 
X 	if (!cflag)
X 		treeoutput ();
X 
X 	if ((infile = fopen (tempfile, "r")) == NULL) {
X 		fprintf (stderr, "temporary file disappeared (%s)\r\n", tempfile);	
X 		sleep (2);
X 		return;
X 	}
X 
X 	sprintf(bakfile, "%s%s", filename, BAKEXT);
X 	if(link(filename, bakfile) == 0)
X 		unlink(filename);
X 
X 	/* if we can't write new, preserve .bak regardless of xflag */
X 	if ((outfile = fopen (filename, "w")) == NULL) {
X 		fprintf (stderr, "can't create %s\r\n", filename);
X 		sleep (2);
X 		return;
X 	}
X 
X 	chmod (filename, statbuf.st_mode);
X 
X 	while ((c = getc (infile)) != EOF)
X 		putc (c, outfile);
X 
X 	fclose (infile);
X 	fclose (outfile);
X 
X 	unlink (tempfile);
X 	if (xflag)
X 		unlink(bakfile);
X }
X 
X checkfile ()
X {
X 	register int c;
X 	register char *p;
X 	register int len;
X 
X 	secondbuf[0] = 0;
X 
X 	while (1) {
X 		strcpy (firstbuf, secondbuf);
X 		if (quit) {	/* quit can't be set in l mode */
X 			while (fgets (secondbuf, sizeof secondbuf, infile) != NULL)
X 				fputs (secondbuf, outfile);
X 			break;
X 		}
X 
X 		if (fgets (secondbuf, sizeof secondbuf, infile) == NULL)
X 			break;
X 		currentchar = secondbuf;
X 		
X 		len = strlen (secondbuf) - 1;
X 
X 		/* skip over .if */
X 		if (strncmp(currentchar,".if t",5) == 0 
X 		||  strncmp(currentchar,".if n",5) == 0) {
X 			copyout(&currentchar,5);
X 			while (*currentchar && isspace(*currentchar)) 
X 				copyout(&currentchar, 1);
X 		}
X 
X 		/* skip over .ds XX or .nr XX */
X 		if (strncmp(currentchar,".ds ",4) == 0 
X 		||  strncmp(currentchar,".de ",4) == 0
X 		||  strncmp(currentchar,".nr ",4) == 0) {
X 			copyout(&currentchar, 3);
X 			while (*currentchar && isspace(*currentchar)) 
X 				copyout(&currentchar, 1);
X 			while (*currentchar && !isspace(*currentchar))
X 				copyout(&currentchar, 1);
X 			if (*currentchar == 0) {
X 				if (!lflag) putc ('\n', outfile);
X 				continue;
X 			}
X 		}
X 
X 		if (secondbuf [ len ] == '\n')
X 			secondbuf [ len ] = 0;
X 
X 		/* if this is a formatter command, skip over it */
X 		if (!tflag && *currentchar == '.') {
X 			while (*currentchar && !myspace (*currentchar)) {
X 				if (!lflag)
X 					putc (*currentchar, outfile);
X 				currentchar++;
X 			}
X 			if (*currentchar == 0) {
X 				if (!lflag)
X 					putc ('\n', outfile);
X 				continue;
X 			}
X 		}
X 
X 		while (1) {
X 			while (*currentchar && !iswordch(*currentchar)) {
X 			    if (tflag)		/* TeX or LaTeX stuff */
X 			    {
X 				if (*currentchar == '\\') {
X 				    /* skip till whitespace */
X 				    while (*currentchar && 
X 					!isspace(*currentchar)) {
X 					    if (!lflag)
X 						putc(*currentchar, outfile);
X 					    currentchar++;
X 					}
X 				    continue;
X 				}
X 			    }
X 			    else
X 			    {
X 				/* formatting escape sequences */
X 				if (*currentchar == '\\') {
X 				switch ( currentchar [1] ) {
X 				case 'f':
X 					if(currentchar[2] != '(') {
X 						/* font change: \fX */
X 						copyout(&currentchar, 3);
X 					}
X 					else {
X 						/* font change: \f(XY */
X 						copyout(&currentchar, 5);
X 					}
X 					continue;
X 				case 's':
X 					/* size change */
X 					p = currentchar + 2;
X 					if (*p == '+'  ||  *p == '-')
X 						p++;
X 					/* This looks wierd 'cause we assume
X 					** *p is now a digit.
X 					*/
X 					if (isdigit (p[1]))
X 						p++;
X 					copyout (&currentchar,
X 						    p - currentchar + 1);
X 					continue;
X 				case '(':
X 					/* extended char set escape: \(XX */
X 					copyout(&currentchar, 4);
X 					continue;
X 				case '*':
X 					if ( currentchar[2] != '(' )
X 						copyout(&currentchar, 3);
X 					else
X 						copyout(&currentchar, 5);
X 					continue;
X 				default:
X 					break;
X 				    }
X 				}
X 			    }
X 
X 				if (!lflag)
X 					putc (*currentchar, outfile);
X 				currentchar++;
X 			}
X 
X 			if (*currentchar == 0)
X 				break;
X 
X 			p = token;
X 			while (iswordch(*currentchar) ||
X 			       (*currentchar == '\'' &&
X 				iswordch(*(currentchar + 1))))
X 			  *p++ = *currentchar++;
X 			*p = 0;
X 			if (lflag) {
X 				if (!good (token)  &&  !cflag)
X 					printf ("%s\n", token);
X 			} else {
X 				if (!quit)
X 				correct (token, &currentchar);
X 			}
X 			if (!lflag)
X 				fprintf (outfile, "%s", token);
X 		}
X 		if (!lflag)
X 			putc ('\n', outfile);
X 	}
X }
X 
X #define MAXPOSSIBLE	100	/* Max no. of possibilities to generate */
X 
X char possibilities[MAXPOSSIBLE][BUFSIZ];
X int pcount;
X int maxposslen;
X 
X correct (token, currentchar)
X char *token;
X char **currentchar;
X {
X 	register int c;
X 	register int i;
X 	int col_ht;
X 	int ncols;
X 	register char *p;
X 	char *start_l2;
X 	char *begintoken;
X 
X 	begintoken = *currentchar - strlen (token);
X 
X checkagain:
X 	if (good (token))
X 		return;
X 
X 	erase ();
X 	printf ("    %s", token);
X 	if (currentfile)
X 		printf ("              File: %s", currentfile);
X 	printf ("\r\n\r\n");
X 
X 	makepossibilities (token);
X 
X 	/*
X 	 * Make sure we have enough room on the screen to hold the
X 	 * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
X 	 * is the maximum number of columns that will fit.
X 	 */
X 	col_ht = li - 6;		/* Height of columns of words */
X 	ncols = co / (maxposslen + 8);
X 	if (pcount > ncols * col_ht)
X 		pcount = ncols * col_ht;
X 
X #ifdef EQUAL_COLUMNS
X 	/*
X 	 * Equalize the column sizes.  The last column will be short.
X 	 */
X 	col_ht = (pcount + ncols - 1) / ncols;
X #endif
X 
X 	for (i = 0; i < pcount; i++) {
X 		move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
X 		printf ("%2d: %s", i, possibilities[i]);
X 	}
X 
X 	move (li - 3, 0);
X 	show_line (firstbuf, firstbuf, 0);
X 
X 	start_l2 = secondbuf;
X 	if (line_size (secondbuf, *currentchar) > co - 1) {
X 		start_l2 = begintoken - (co / 2);
X 		while (start_l2 < begintoken) {
X 			i = line_size (start_l2, *currentchar) + 1;
X 			if (i <= co)
X 				break;
X 			start_l2 += i - co;
X 		}
X 		if (start_l2 > begintoken)
X 			start_l2 = begintoken;
X 		if (start_l2 < secondbuf)
X 			start_l2 = secondbuf;
X 	}
X 	show_line (start_l2, begintoken, strlen (token));
X 
X 
X 	while (1) {
X 		fflush (stdout);
X 		switch (c = (getchar () & NOPARITY)) {
X #ifndef USG
X 		case 'Z' & 037:
X 			stop ();
X 			erase ();
X 			goto checkagain;
X #endif
X 		case ' ':
X 			erase ();
X 			fflush (stdout);
X 			return;
X 		case 'x': case 'X':
X 			printf ("Are you sure you want to throw away your changes? ");
X 			fflush (stdout);
X 			c = (getchar () & NOPARITY);
X 			if (c == 'y' || c == 'Y') {
X 				erase ();
X 				fflush (stdout);
X 				done ();
X 			}
X 			putchar (7);
X 			goto checkagain;
X 		case 'i': case 'I':
X 			treeinsert (token, 1);
X 			erase ();
X 			fflush (stdout);
X 			return;
X 		case 'a': case 'A':
X 			treeinsert (token, 0);
X 			erase ();
X 			fflush (stdout);
X 			return;
X 		case 'L' & 037:
X 			goto checkagain;
X 		case '?':
X 			givehelp ();
X 			goto checkagain;
X 		case '!':
X 			{
X 				char buf[200];
X 				move (li - 1, 0);
X 				putchar ('!');
X 				if (getline (buf) == NULL) {
X 					putchar (7);
X 					erase ();
X 					fflush (stdout);
X 					goto checkagain;
X 				}
X 				printf ("\r\n");
X 				fflush (stdout);
X 				shellescape (buf);
X 				erase ();
X 				goto checkagain;
X 			}
X 		case 'r': case 'R':
X 			move (li - 1, 0);
X 			printf ("Replace with: ");
X 			if (getline (token) == NULL) {
X 				putchar (7);
X 				erase ();
X 				goto checkagain;
X 			}
X 			inserttoken (secondbuf, begintoken, token, currentchar);
X 			erase ();
X 			goto checkagain;
X 		case '0': case '1': case '2': case '3': case '4':
X 		case '5': case '6': case '7': case '8': case '9':
X 			i = c - '0';
X 			if (pcount > 10
X 			    &&  i > 0  &&  i <= (pcount - 1) / 10) {
X 				c = getchar () & NOPARITY;
X 				if (c >= '0'  &&  c <= '9')
X 					i = i * 10 + c - '0';
X 				else if (c != '\r'  &&  c != '\n') {
X 					putchar (7);
X 					break;
X 				}
X 			}
X 			if (i < pcount) {
X 				strcpy (token, possibilities[i]);
X 				inserttoken (secondbuf, begintoken,
X 				    token, currentchar);
X 				erase ();
X 				return;
X 			}
X 			putchar (7);
X 			break;
X 		case '\r':	/* This makes typing \n after single digits */
X 		case '\n':	/* ..less obnoxious */
X 			break;
X 		case 'l': case 'L':
X 			{
X 				char buf[100];
X 				move (li - 1, 0);
X 				printf ("Lookup string ('*' is wildcard): ");
X 				if (getline (buf) == NULL) {
X 					putchar (7);
X 					erase ();
X 					goto checkagain;
X 				}
X 				printf ("\r\n\r\n");
X 				fflush (stdout);
X 				lookharder (buf);
X 				erase ();
X 				goto checkagain;
X 			}
X 		case 'q': case 'Q':
X 			quit = 1;
X 			erase ();
X 			fflush (stdout);
X 			return;
X 		default:
X 			putchar (7);
X 			break;
X 		}
X 	}
X }
X 
X show_line (line, invstart, invlen)
X register char *line;
X register char *invstart;
X register int invlen;
X {
X 	register int width;
X 
X 	width = 0;
X 	while (line != invstart  &&  width < co - 1)
X 		width += show_char (*line++, width);
X 	if (invlen) {
X 		inverse ();
X 		while (--invlen >= 0  &&  width < co - 1)
X 			width += show_char (*line++, width);
X 		normal ();
X 	}
X 	while (*line  &&  width < co - 1)
X 		width += show_char (*line++, width);
X 	printf ("\r\n");
X }
X 
X show_char (ch, linew)
X register int ch;
X int linew;
X {
X 	if (ch == '\t') {
X 		putchar ('\t');
X 		return 8 - (linew & 0x07);
X 	}
X 	else if (ch < ' ') {
X 		putchar ('^');
X 		putchar (ch + 'A' - '\001');
X 		return 2;
X 	}
X 	putchar (ch);
X 	return 1;
X }
X 
X line_size (buf, bufend)
X register char *buf;
X register char *bufend;
X {
X 	register int width;
X 
X 	for (width = 0;  buf < bufend  &&  *buf;  buf++) {
X 		if (*buf == '\t')
X 			width = (width + 8) & ~0x07;
X 		else if (*buf < ' ')
X 			width += 2;
X 		else
X 			width++;
X 	}
X 	return width;
X }
X 
X inserttoken (buf, start, token, currentchar)
X char *buf, *start; 
X register char *token;
X char **currentchar;
X {
X 	char copy[BUFSIZ];
X 	register char *p, *q;
X 
X 	strcpy (copy, buf);
X 
X 	for (p = buf, q = copy; p != start; p++, q++)
X 		*p = *q;
X 	q += *currentchar - start;
X 	while (*token  &&  iswordch (*token))
X 		*p++ = *token++;
X 	*currentchar = p;
X 	if (*token) {
X 
X 		/*
X 		** The token changed to two words.  Split it up and save the
X 		** second one for later.
X 		*/
X 
X 		*p++ = *token;
X 		*token++ = '\0';
X 		while (*token)
X 			*p++ = *token++;
X 	}
X 	while (*p++ = *q++)
X 		;
X }
X 
X int casecmp (a, b)
X char *a;
X char *b;
X {
X 	register char *ap;
X 	register char *bp;
X 
X 	for (ap = a, bp = b;  *ap;  ap++, bp++) {
X 		if (mylower (*ap)) {
X 			if (mylower (*bp)) {
X 				if (*ap != *bp)
X 					return *ap - *bp;
X 			}
X 			else {
X 				if (toupper (*ap) != *bp)
X 					return toupper (*ap) - *bp;
X 			}
X 		}
X 		else {
X 			if (myupper (*bp)) {
X 				if (*ap != *bp)
X 					return *ap - *bp;
X 			}
X 			else {
X 				if (tolower (*ap) != *bp)
X 					return tolower (*ap) - *bp;
X 			}
X 		}
X 	}
X 	if (*bp != '\0')
X 		return -*bp;
X 	return strcmp (a, b);
X }
X 
X makepossibilities (word)
X register char *word;
X {
X 	register int i;
X 
X 	for (i = 0; i < MAXPOSSIBLE; i++)
X 		possibilities[i][0] = 0;
X 	pcount = 0;
X 	maxposslen = 0;
X 
X #ifdef CAPITALIZE
X 	wrongcapital (word);
X #endif
X 	if (pcount < MAXPOSSIBLE) wrongletter (word);
X 	if (pcount < MAXPOSSIBLE) extraletter (word);
X 	if (pcount < MAXPOSSIBLE) missingletter (word);
X 	if (pcount < MAXPOSSIBLE) transposedletter (word);
X 
X 	if (sortit  &&  pcount)
X 		qsort ((char *) possibilities, pcount,
X 		    sizeof (possibilities[0]), casecmp);
X }
X 
X insert (word)
X register char *word;
X {
X 	register int i;
X 
X 	for (i = 0; i < pcount; i++)
X 		if (strcmp (possibilities[i], word) == 0)
X 			return (0);
X 
X 	strcpy (possibilities[pcount++], word);
X 	i = strlen (word);
X 	if (i > maxposslen)
X 		maxposslen = i;
X 	if (pcount >= MAXPOSSIBLE)
X 		return (-1);
X 	else
X 		return (0);
X }
X 
X #ifdef CAPITALIZE
X wrongcapital (word)
X register char *word;
X {
X 	char newword[BUFSIZ];
X 
X 	/*
X 	** All-uppercase is always legal.  If the word matches, "ins_cap"
X 	** will recapitalize it correctly.
X 	*/
X 	strcpy (newword, word);
X 	upcase (newword);
X 	if (good (newword))
X 		return ins_cap (newword, word);
X 	return 0;
X }
X #endif
X 
X wrongletter (word)
X register char *word;
X {
X 	register int i, j, c, n;
X 	char newword[BUFSIZ];
X 
X 	n = strlen (word);
X 	strcpy (newword, word);
X #ifdef CAPITALIZE
X 	upcase (newword);
X #endif
X 
X 	for (i = 0; i < n; i++) {
X 		for (j=0; j < Trynum; ++j) {
X 			newword[i] = Try[j];
X 			if (good (newword)) {
X 				if (ins_cap (newword, word) < 0)
X 					return;
X 			}
X 		}
X 		newword[i] = word[i];
X 	}
X }
X 
X extraletter (word)
X register char *word;
X {
X 	char newword[BUFSIZ];
X 	register char *p, *s, *t;
X 
X 	if (strlen (word) < 3)
X 		return;
X 
X 	for (p = word; *p; p++) {
X 		for (s = word, t = newword; *s; s++)
X 			if (s != p)
X 				*t++ = *s;
X 		*t = 0;
X #ifdef CAPITALIZE
X 		if (good (upcase (newword))) {
X 			if (ins_cap (newword, word) < 0)
X 				return;
X 		}
X #else
X 		if (good (newword)) {
X 			if (ins_cap (newword, word) < 0)
X 				return;
X 		}
X #endif
X 	}
X }
X 
X missingletter (word)
X char word[];
X {
X 	char newword[BUFSIZ]; 
X 	register char *p, *r, *s, *t;
X 	register int i;
X 
X 	for (p = word; p == word || p[-1]; p++) {
X 		for (s = newword, t = word; t != p; s++, t++)
X 			*s = *t;
X 		r = s++;
X 		while (*t)
X 			*s++ = *t++;
X 		*s = 0;
X 		for (i=0; i < Trynum; ++i) {
X 			*r = Try[i];
X #ifdef CAPITALIZE
X 			if (good (upcase (newword))) {
X 				if (ins_cap (newword, word) < 0)
X 					return;
X 			}
X #else
X 			if (good (newword)) {
X 				if (ins_cap (newword, word) < 0)
X 					return;
X 			}
X #endif
X 		}
X 	}
X }
X 
X transposedletter (word)
X register char *word;
X {
X 	char newword[BUFSIZ];
X 	register int t;
X 	register char *p;
X 
X 	strcpy (newword, word);
X 	for (p = newword; p[1]; p++) {
X 		t = p[0];
X 		p[0] = p[1];
X 		p[1] = t;
X #ifdef CAPITALIZE
X 		if (good (upcase (newword))) {
X 			if (ins_cap (newword, word) < 0)
X 				return;
X 		}
X #else
X 		if (good (newword)) {
X 			if (ins_cap (newword, word) < 0)
X 				return;
X 		}
X #endif
X 		t = p[0];
X 		p[0] = p[1];
X 		p[1] = t;
X 	}
X }
X 
X /* Insert one or more correctly capitalized versions of pattern */
X ins_cap (word, pattern)
X register char *word, *pattern;
X {
X 	static char newword[BUFSIZ];
X 	register char *p, *q;
X 	char *psave;
X 	register int wcount;
X 
X 	if (*word == 0)
X 		return;
X 
X 	strcpy (newword, word);
X #ifdef CAPITALIZE
X 	if (lastdent->allcaps)
X 		return insert (upcase (newword)); /* Uppercase required */
X 	for (p = pattern;  *p;  p++)
X 		if (mylower (*p))
X 			break;
X 	if (*p == '\0')
X 		return insert (upcase (newword)); /* Pattern was all caps */
X 	for (p = pattern;  *p;  p++)
X 		if (myupper (*p))
X 			break;
X 	if (*p == '\0') {			/* Pattern was all lower */
X 		if (!lastdent->followcase  &&  !lastdent->capitalize)
X 			return insert (lowcase (newword));
X 		/*
X 		** If there's a followcase version that's all-lower,
X 		** insert only that version.
X 		*/
X 		if (lastdent->followcase) {
X 			p = lastdent->word;
X 			p += strlen (p) + 1;
X 			wcount = (*p++ & 0xFF);
X 			while (--wcount >= 0) {
X 				for (psave = ++p;
X 				    *p  &&  !myupper (*p);
X 				    p++)
X 					;
X 				if (*p == '\0')	/* Was it all lowercase? */
X 					return insert (psave);	/* Yup, quit */
X 				while (*p++)
X 					;	/* Skip to next case sample */
X 			}
X 		}
X 	}
X 	/*
X 	** The sample wasn't all-upper, and either it wasn't all-lower or
X 	** all-lower is illegal.  Insert all legal capitalizations.  In
X 	** some cases, this may include all-lowercase.
X 	*/
X 	if (lastdent->capitalize) {
X 		lowcase (newword);
X 		if (mylower (newword[0]))
X 			newword[0] = toupper (newword[0]);
X 		insert (newword);
X 	}
X 	if (lastdent->followcase) {
X 		p = lastdent->word;
X 		p += strlen (p) + 1;
X 		wcount = (*p++ & 0xFF);
X 		while (--wcount >= 0) {
X 			/* Insert every variation;  it's easier */
X 			if (insert (++p) < 0)
X 				return -1;
X 			while (*p++)
X 				;		/* Skip to end of sample */
X 		}
X 		return 0;
X 	}
X 	if (lastdent->capitalize)
X 		return 0;
X 	/*
X 	** We get here only if none of the special capitalization flags are
X 	** set.  If first letter of the pattern is capitalized, capitalize
X 	** the first letter of the result.  Otherwise produce all lowercase.
X 	*/
X 	lowcase (newword);
X 	if (myupper (pattern[0])  &&  mylower (newword[0]))
X 		newword[0] = toupper (newword[0]);
X 	return insert (newword);
X #else
X 	if (myupper (pattern[0])) {
X 		if (myupper (pattern[1])) {
X 			for (p = word, q = newword; *p; p++, q++) {
X 				if (mylower (*p))
X 					*q = toupper (*p);
X 				else
X 					*q = *p;
X 			}
X 			*q = 0;
X 		} else {
X 			if (mylower (word [0]))
X 				newword[0] = toupper (word[0]);
X 			else
X 				newword[0] = word[0];
X 
X 			for (p = word + 1, q = newword + 1; *p; p++, q++)
X 				if (myupper (*p))
X 					*q = tolower (*p);
X 				else
X 					*q = *p;
X 
X 			*q = 0;
X 		}
X 	} else {
X 		for (p = word, q = newword; *p; p++, q++)
X 			if (myupper (*p))
X 				*q = tolower (*p);
X 			else
X 				*q = *p;
X 		*q = 0;
X 	}
X 	return insert (newword);
X #endif
X }
X 
X char *
X getline (s)
X register char *s;
X {
X 	register char *p;
X 	register int c;
X 
X 	p = s;
X 
X 	while (1) {
X 		fflush (stdout);
X 		c = (getchar () & NOPARITY);
X 		if (c == '\\') {
X 			putchar ('\\');
X 			fflush (stdout);
X 			c = (getchar () & NOPARITY);
X 			backup ();
X 			putchar (c);
X 			*p++ = c;
X 		} else if (c == ('G' & 037)) {
X 			return (NULL);
X 		} else if (c == '\n' || c == '\r') {
X 			*p = 0;
X 			return (s);
X 		} else if (c == erasechar) {
X 			if (p != s) {
X 				p--;
X 				backup ();
X 				putchar (' ');
X 				backup ();
X 			}
X 		} else if (c == killchar) {
X 			while (p != s) {
X 				p--;
X 				backup ();
X 				putchar (' ');
X 				backup ();
X 			}
X 		} else {
X 			*p++ = c;
X 			putchar (c);
X 		}
X 	}
X }
X 
X askmode ()
X {
X 	char buf[BUFSIZ];
X 	register int i;
X 
X 	if (fflag) {
X 		if (freopen (askfilename, "w", stdout) == NULL) {
X 			fprintf (stderr, "Can't create %s\n", askfilename);
X 			exit (1);
X 		}
X 	}
X 
X 	setbuf (stdin, NULL);
X 	setbuf (stdout, NULL);
X 
X 	while (xgets (buf) != NULL) {
X 		/* *line is like `i', @line is like `a' */
X 		if (buf[0] == '*' || buf[0] == '@') {
X 			treeinsert(buf + 1, buf[0] == '*');
X 			printf("*\n");
X 			treeoutput ();
X 		} else if (good (buf)) {
X 			if (rootword[0] == 0) {
X 				printf ("*\n");	/* perfect match */
X 			} else {
X 				printf ("+ %s\n", rootword);
X 			}
X 		} else {
X 			makepossibilities (buf);
X 			if (possibilities[0][0]) {
X 				printf ("& ");
X 				for (i = 0; i < MAXPOSSIBLE; i++) {
X 					if (possibilities[i][0] == 0)
X 						break;
X 					printf ("%s ", possibilities[i]);
X 				}
X 				printf ("\n");
X 			} else {
X 				printf ("#\n");
X 			}
X 		}
X #ifndef USG
X 		if (sflag) {
X 			stop ();
X 			if (fflag) {
X 				rewind (stdout);
X 				creat (askfilename, 0666);
X 			}
X 		}
X #endif
X 	}
X }
X 
X /* Copy/ignore "cnt" number of characters pointed to by *cc. */
X copyout(cc, cnt)
X register char	**cc;
X register cnt;
X {
X 	while (--cnt >= 0) {
X 		if (*(*cc) == 0)
X 			break;
X 		if (!lflag)
X 			putc (*(*cc), outfile);
X 		(*cc)++;
X 	}
X }
X 
X lookharder(string)
X char *string;
X {
X 	char cmd[150], grepstr[100];
X 	register char *g, *s;
X 	register int wild = 0;
X 
X 	g = grepstr;
X 	for (s = string; *s != '\0'; s++)
X 		if (*s == '*') {
X 			wild++;
X 			*g++ = '.';
X 			*g++ = '*';
X 		} else
X 			*g++ = *s;
X 	*g = '\0';
X 	if (grepstr[0]) {
X #ifdef LOOK
X 		if (wild)
X 			/* string has wild card characters */
X 			sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
X 		else
X 			/* no wild, use look(1) */
X 			sprintf (cmd, "%s %s %s", LOOK, grepstr, WORDS);
X #else
X 		sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
X #endif
X 		shellescape (cmd);
X 	}
X }
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'ispell.el'" '(12958 characters)'
if test -f 'ispell.el'
then
	echo shar: will not over-write existing file "'ispell.el'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.el'
X ;;; Spelling correction interface for GNU EMACS using "ispell"
X 
X ;;; Walt Buehring
X ;;; Texas Instruments - Computer Science Center
X ;;; ARPA:  Buehring%TI-CSL@CSNet-Relay
X ;;; UUCP:  {smu, texsun, im4u, rice} ! ti-csl ! buehring
X 
X ;;; ispell-region and associated routines added by
X ;;; Perry Smith
X ;;; pedz@bobkat
X ;;; Tue Jan 13 20:18:02 CST 1987
X 
X ;;; extensively modified by Mark Davies and Andrew Vignaux
X ;;; {mark,andrew}@vuwcomp
X ;;; Sun May 10 11:45:04 NZST 1987
X 
X ;;; Depends on the ispell program snarfed from MIT-PREP in early 
X ;;; 1986.  The only interactive command is "ispell-word" which should be
X ;;; bound to M-$.  If someone writes an "ispell-region" command, 
X ;;; I would appreciate a copy. -- ispell-region, ispell-buffer now added.
X 
X ;;; To fully install this, add this file to your GNU lisp directory and 
X ;;; compile it with M-X byte-compile-file.  Then add the following to the
X ;;; appropriate init file:
X 
X ;;;  (autoload 'ispell-word "ispell"
X ;;;    "Check the spelling of word in buffer." t)
X ;;;  (global-set-key "\e$" 'ispell-word)
X ;;;  (autoload 'ispell-region "ispell"
X ;;;    "Check the spelling of region." t)
X ;;;  (autoload 'ispell-buffer "ispell"
X ;;;    "Check the spelling of buffer." t)
X 
X ;;; If run on a heavily loaded system, the initial sleep time in
X ;;; ispell-init-process may need to be increased.
X 
X ;;; No warranty expressed or implied.  All sales final.  Void where prohibited.
X ;;; If you don't like it, change it.
X 
X (defconst ispell-out-name " *ispell*"
X   "Name of the buffer that is associated with the 'ispell' process")
X 
X (defconst ispell-temp-name " *ispell-temp*"
X   "Name of the temporary buffer that 'ispell-region' uses to hold the
X filtered region")
X 
X (defvar ispell-program-name "ispell"
X   "Program invoked by ispell-word and ispell-region commands.")
X 
X (defvar ispell-syntax-table nil)
X 
X (if (null ispell-syntax-table)
X     ;; The following assumes that the standard-syntax-table
X     ;; is static.  If you add words with funky characters
X     ;; to your dictionary, the following may have to change.
X     (progn
X       (setq ispell-syntax-table (make-syntax-table))
X       ;; Make certain characters word constituents
X       ;; (modify-syntax-entry ?' "w   " ispell-syntax-table)
X       ;; (modify-syntax-entry ?- "w   " ispell-syntax-table)
X       ;; Get rid on existing word syntax on certain characters 
X       (modify-syntax-entry ?0 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?1 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?2 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?3 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?4 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?5 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?6 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?7 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?8 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?9 ".   " ispell-syntax-table)
X       (modify-syntax-entry ?$ ".   " ispell-syntax-table)
X       (modify-syntax-entry ?% ".   " ispell-syntax-table)))
X 
X 
X (defun ispell-word (&optional quietly)
X   "Check spelling of word at or before dot.
X If word not found in dictionary, display possible corrections in a window 
X and let user select."
X   (interactive)
X   (let* ((current-syntax (syntax-table))
X 	 start end word poss replace)
X     (unwind-protect
X 	(save-excursion
X 	  ;; Ensure syntax table is reasonable 
X 	  (set-syntax-table ispell-syntax-table)
X 	  ;; Move backward for word if not already on one.
X 	  (if (not (looking-at "\\w"))
X 	      (re-search-backward "\\w" (point-min) 'stay))
X 	  ;; Move to start of word
X 	  (re-search-backward "\\W" (point-min) 'stay)
X 	  ;; Find start and end of word
X 	  (or (re-search-forward "\\w+" nil t)
X 	      (error "No word to check."))
X 	  (setq start (match-beginning 0)
X 		end (match-end 0)
X 		word (buffer-substring start end)))
X       (set-syntax-table current-syntax))
X     (ispell-init-process)		; erases ispell output buffer
X     (or quietly (message "Checking spelling of %s..." (upcase word)))
X     (save-excursion
X       (set-buffer ispell-out-name)
X       (send-string ispell-process (concat word "\n"))
X       ;; wait until we have a complete line
X       (while (progn
X 	       (goto-char (point-max))
X 	       (/= (preceding-char) ?\n))
X 	(accept-process-output ispell-process))
X       (goto-char (point-min))
X       (setq poss (ispell-parse-output
X 		  (buffer-substring (point) 
X 				    (progn (end-of-line) (point))))))
X     (cond ((eq poss t)
X 	   (or quietly (message "Found %s" (upcase word))))
X 	  ((stringp poss)
X 	   (or quietly (message "Found it because of %s" (upcase poss))))
X 	  ((null poss)
X 	   (or quietly (message "Could Not Find %s" (upcase word))))
X 	  (t (setq replace (ispell-choose poss word))
X 	     (if replace
X 		 (progn
X 		    (goto-char end)
X 		    (delete-region start end)
X 		    (insert-string replace)))))
X     poss))
X 
X 
X (defun ispell-choose (choices word)
X   "Display possible corrections from list CHOICES.  Return chosen word
X if one is chosen; Return nil to keep word"
X   (unwind-protect 
X       (save-window-excursion
X 	(let ((count 0)
X 	      (line 2)
X 	      (words choices)
X 	      (window-min-height 2)
X 	      char num result)
X 	  (save-excursion
X 	    (set-buffer (get-buffer-create "*Choices*")) (erase-buffer)
X 	    (setq mode-line-format "--  %b  --")
X 	    (while words
X 	      (if (<= (+ 7 (current-column) (length (car words)))
X 		      (window-width))
X 		  nil
X 		(insert "\n")
X 		(setq line (1+ line)))
X 	      (insert "(" (+ count ?0) ") " (car words) "  ")
X 	      (setq words (cdr words)
X 		    count (1+ count))))
X 	  (overlay-window line)
X 	  (switch-to-buffer "*Choices*")
X 	  (select-window (next-window))
X 	  (while (eq t
X 		     (setq result
X 			   (progn
X 			     (message "Enter letter to replace word;  Space to leave unchanged")
X 			     (setq char (read-char))
X 			     (setq num (- char ?0))
X 			     (cond ((= char ? ) nil)
X 				   ((= char ?i)
X 				    (send-string ispell-process
X 						 (concat "*" word "\n"))
X 				    (if (get-buffer ispell-temp-name)
X 					(save-excursion
X 					  (set-buffer ispell-temp-name)
X 					  (save-excursion
X 					    (replace-regexp (concat "^" word "$")
X 							    (concat "+" word)))))
X 				    nil)
X 				   ((= char ?a)
X 				    (send-string ispell-process
X 						(concat "@" word "\n"))
X 				    (if (get-buffer ispell-temp-name)
X 					(save-excursion
X 					  (set-buffer ispell-temp-name)
X 					  (save-excursion
X 					    (replace-regexp (concat "^" word "$")
X 							    (concat "+" word)))))
X 				    nil)
X 				   ((= char ?r) (read-string "Replacement: " nil))
X 				   ((and (>= num 0) (< num count)) (nth num choices))
X 				   ((= char ?\C-r)
X 					; Note: does not reset syntax table
X 				    (save-excursion (recursive-edit)) t) ; dangerous
X 				   ((= char ?\C-z)
X 				    (suspend-emacs) t)
X 				   ((= char help-char)
X 				    (message "[r]eplace; [a]ccept for session; [i] accept and add to private dictionary")
X 				    (sit-for 3) t)
X 				   (t (ding) t))))))
X 	  result))
X     ;; Protected forms...
X     (bury-buffer "*Choices*")))
X 
X 
X (defun overlay-window (height)
X   "Create a (usually small) window with HEIGHT lines and avoid
X recentering."
X   (save-excursion
X     (let ((oldot (save-excursion (beginning-of-line) (dot)))
X 	  (top (save-excursion (move-to-window-line height) (dot)))
X 	  newin)
X       (if (< oldot top) (setq top oldot))
X       (setq newin (split-window-vertically height))
X       (set-window-start newin top))))
X 
X 
X (defvar ispell-process nil
X   "Holds the process object for 'ispell'")
X 
X (defun ispell-parse-output (output)
X "Parse the OUTPUT string of 'ispell' and return either t for an exact
X match, a string containing the root word for a match via suffix
X removal, a list of possible correct spellings, or nil for a complete
X miss."
X   (cond
X    ((string= output "*") t)
X    ((string= output "#") nil)
X    ((string= (substring output 0 1) "+")
X     (substring output 2))
X    (t
X     (let ((choice-list '()))
X       (while (not (string= output ""))
X 	(let* ((start (string-match "[A-z]" output))
X 	       (end (string-match " \\|$" output start)))
X 	  (if start
X 	      (setq choice-list (cons (substring output start end)
X 				      choice-list)))
X 	  (setq output (substring output (1+ end)))))
X       choice-list))))
X 
X 
X (defun ispell-init-process ()
X   "Check status of 'ispell' process and start if necessary."
X   (if (and ispell-process
X 	   (eq (process-status ispell-process) 'run))
X       (save-excursion
X 	(set-buffer ispell-out-name)
X 	(erase-buffer))
X     (message "Starting new ispell process...")
X     (and (get-buffer ispell-out-name) (kill-buffer ispell-out-name))
X     (setq ispell-process (start-process "ispell" ispell-out-name
X 					ispell-program-name "-A"))
X     (process-kill-without-query ispell-process)
X     (sit-for 3)))
X 
X (defvar ispell-filter-hook "/usr/bin/tr"
X   "Filter to pass a region through before sending it to ispell.
X Must produce output one word per line.  Typically this is set to tr,
X deroff, detex, etc.")
X (make-variable-buffer-local 'ispell-filter-hook)
X 
X (defvar ispell-filter-hook-args '("-cs" "A-Za-z" "\n")
X   "Argument LIST to pass to ispell-filter-hook")
X (make-variable-buffer-local 'ispell-filter-hook-args)
X 
X ; This routine has certain limitations brought about by the filter
X ; hook.  For example, deroff will take ``\fBcat\fR'' and spit out
X ; ``cat''.  This is hard to search for since word-search-forward will
X ; not match at all and search-forward for ``cat'' will match
X ; ``concatenate'' if it happens to occur before.
X ; `ispell-region' filters the region into `*ispell-temp*', writes the
X ; buffer to a temporary file, and sends a ``&Include_File&foobar''
X ; string to the ispell process which is writing into `*ispell*'.
X ; `ispell-region' then searches `*ispell*' for a spelling error (`#' or
X ; `&'), checks the `*ispell-temp*' buffer for the misspelled word and
X ; then skips forward `count' words (the number of correct lines in
X ; `*ispell*') in the region.  It then searches for the misspelled
X ; word.  This is not a foolproof heuristic but it is fast and works
X ; most of the time.
X 
X (defun ispell-region (start end)
X   "Check a region for spelling errors interactively.  The variable
X which should be buffer or mode specific ispell-filter-hook is called
X to filter out text processing commands."
X   (interactive "r")
X   (let ((this-buf (current-buffer))
X 	(spell-file (make-temp-name "/usr/tmp/is"))
X 	(spell-buf (get-buffer-create ispell-temp-name))
X 	(current-syntax (syntax-table))
X 	(tracker 1)
X 	word poss replace endbound ispell-out)
X     (ispell-init-process)
X     (setq ispell-out (get-buffer ispell-out-name))
X     (unwind-protect
X 	(save-excursion
X 	  (message "Prefrobnicating...")
X 	  (sit-for 0)
X 	  (set-syntax-table ispell-syntax-table)
X 	  (set-buffer spell-buf)
X 	  (erase-buffer)
X 	  (set-buffer this-buf)
X 	  (apply 'call-process-region 
X 		 (append (list start end ispell-filter-hook nil spell-buf nil)
X 			 ispell-filter-hook-args))
X 	  (goto-char start)
X 	  (set-buffer spell-buf)
X 	  (and (/= (preceding-char) ?\n) ; couple of hacks for tr
X 	       (insert "\n"))
X 	  (goto-char (point-min))
X 	  (while (= (following-char) ?\n)
X 	    (delete-char 1))
X 	  (write-region (point-min) (point-max) spell-file nil 1)
X 	  (send-string ispell-process 
X 		       (concat "&Include_File&" spell-file "\n"))
X 	  (message "Looking for a misspelled word") (sit-for 0)
X 	  (while (not (eobp))
X 	    (set-buffer ispell-out)
X 	    (goto-char (point-max))
X 	    (beginning-of-line)
X 	    (setq endbound (point))
X 	    (goto-char tracker)
X 	    (if (prog1
X 		    (not (re-search-forward "^[#&]" endbound 1))
X 		  (beginning-of-line)
X 		  (setq count (count-lines tracker (point))
X 			tracker (point))
X 		  (set-buffer spell-buf)
X 		  (forward-line count))
X 		(accept-process-output)	; give it some time to get something
X 	      (setq word (buffer-substring (point)
X 					   (progn (end-of-line) (point))))
X 	      (forward-char 1)
X 	      (set-buffer ispell-out) ; (goto-char tracker)
X 	      (setq poss (ispell-parse-output
X 			  (buffer-substring (point) 
X 					    (progn (end-of-line) (point)))))
X 	      (forward-char 1)
X 	      (setq tracker (point))
X 	      (set-buffer this-buf)
X 	      (re-search-forward "\\W*\\(\\w+\\)" nil t (1- count)) ; get close
X 	      (if (string= "+" (substring word 0 1))
X 		  (search-forward (substring word 1) nil t)
X 		(if (search-forward word nil t)
X 		    (progn
X 		      (sit-for 0)
X 		      (setq replace (ispell-choose poss word))
X 		      (if replace
X 			  (replace-match replace)))
X 		  (message "Can not find %s in original text -- Any key to continue" word)
X 		  (and (= ?\C-z (read-char)) (suspend-emacs)))
X 		(message "Looking for a misspelled word") (sit-for 0))
X 	      (set-buffer spell-buf))))
X       (message "")
X       (set-syntax-table current-syntax)
X       (and (file-exists-p spell-file)
X 	   (delete-file spell-file)))))
X 
X (defun ispell-buffer () 
X   "Check the current buffer for spelling errors interactively.  The variable
X which should be buffer or mode specific ispell-filter-hook is called to
X filter out text processing commands."
X   (interactive)
X   (ispell-region (point-min) (point-max)))
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'ispell.h'" '(6646 characters)'
if test -f 'ispell.h'
then
	echo shar: will not over-write existing file "'ispell.h'"
else
sed 's/^X //' << \SHAR_EOF > 'ispell.h'
X /* -*- Mode: Text -*- */
X 
X struct dent {
X 	struct dent *next;
X 	char *word;
X 
X 	unsigned short used : 1;
X 
X /* bit fields for all of the flags */
X 	unsigned short v_flag : 1;
X 		/*
X 			"V" flag:
X 		        ...E --> ...IVE  as in CREATE --> CREATIVE
X 		        if # .ne. E, ...# --> ...#IVE  as in PREVENT --> PREVENTIVE
X 		*/
X 	unsigned short n_flag : 1;
X 		/*
X 			"N" flag:
X 			        ...E --> ...ION  as in CREATE --> CREATION
X 			        ...Y --> ...ICATION  as in MULTIPLY --> MULTIPLICATION
X 			        if # .ne. E or Y, ...# --> ...#EN  as in FALL --> FALLEN
X 		*/
X 	unsigned short x_flag : 1;
X 		/*
X 			"X" flag:
X 			        ...E --> ...IONS  as in CREATE --> CREATIONS
X 			        ...Y --> ...ICATIONS  as in MULTIPLY --> MULTIPLICATIONS
X 			        if # .ne. E or Y, ...# --> ...#ENS  as in WEAK --> WEAKENS
X 		*/
X 	unsigned short h_flag : 1;
X 		/*
X 			"H" flag:
X 			        ...Y --> ...IETH  as in TWENTY --> TWENTIETH
X 			        if # .ne. Y, ...# --> ...#TH  as in HUNDRED --> HUNDREDTH
X 		*/
X 	unsigned short y_flag : 1;
X 		/*
X 			"Y" FLAG:
X 			        ... --> ...LY  as in QUICK --> QUICKLY
X 		*/
X 	unsigned short g_flag : 1;
X 		/*
X 			"G" FLAG:
X 			        ...E --> ...ING  as in FILE --> FILING
X 			        if # .ne. E, ...# --> ...#ING  as in CROSS --> CROSSING
X 		*/
X 	unsigned short j_flag : 1;
X 		/*
X 			"J" FLAG"
X 			        ...E --> ...INGS  as in FILE --> FILINGS
X 			        if # .ne. E, ...# --> ...#INGS  as in CROSS --> CROSSINGS
X 		*/
X 	unsigned short d_flag : 1;
X 		/*
X 			"D" FLAG:
X 			        ...E --> ...ED  as in CREATE --> CREATED
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IED  as in IMPLY --> IMPLIED
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#ED  as in CROSS --> CROSSED
X 			                                or CONVEY --> CONVEYED
X 		*/
X 	unsigned short t_flag : 1;
X 		/*
X 			"T" FLAG:
X 			        ...E --> ...EST  as in LATE --> LATEST
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IEST  as in DIRTY --> DIRTIEST
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#EST  as in SMALL --> SMALLEST
X 			                                or GRAY --> GRAYEST
X 		*/
X 	unsigned short r_flag : 1;
X 		/*
X 			"R" FLAG:
X 			        ...E --> ...ER  as in SKATE --> SKATER
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IER  as in MULTIPLY --> MULTIPLIER
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#ER  as in BUILD --> BUILDER
X 			                                or CONVEY --> CONVEYER
X 		*/
X 	unsigned short z_flag : 1;
X 		/*
X 			"Z FLAG:
X 			        ...E --> ...ERS  as in SKATE --> SKATERS
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IERS  as in MULTIPLY --> MULTIPLIERS
X 			        if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...@# --> ...@#ERS  as in BUILD --> BUILDERS
X 			                                or SLAY --> SLAYERS
X 		*/
X 	unsigned short s_flag : 1;
X 		/*
X 			"S" FLAG:
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@IES  as in IMPLY --> IMPLIES
X 			        if # .eq. S, X, Z, or H,
X 			                ...# --> ...#ES  as in FIX --> FIXES
X 			        if # .ne. S,X,Z,H, or Y, or (# = Y and @ = A, E, I, O, or U)
X 			                ...# --> ...#S  as in BAT --> BATS
X 			                                or CONVEY --> CONVEYS
X 		*/
X 	unsigned short p_flag : 1;
X 		/*
X 			"P" FLAG:
X 			        if @ .ne. A, E, I, O, or U,
X 			                ...@Y --> ...@INESS  as in CLOUDY --> CLOUDINESS
X 			        if # .ne. Y, or @ = A, E, I, O, or U,
X 			                ...@# --> ...@#NESS  as in LATE --> LATENESS
X 			                                or GRAY --> GRAYNESS
X 		*/
X 	unsigned short m_flag : 1;
X 		/*
X 			"M" FLAG:
X 			        ... --> ...'S  as in DOG --> DOG'S
X 		*/
X 
X 	unsigned short keep : 1;
X 
X #ifdef CAPITALIZE
X 	/*
X 	** if followcase is set, the actual word entry (dent->word)
X 	** is followed by one or more further strings giving exact
X 	** capitalizations.   The first byte after the uppercase word
X 	** gives the number of capitalizations.  Each capitalization
X 	** is preceded by the character "+" if it is to be kept, or
X 	** "-" if it is to be discarded from the personal dictionary.
X 	** For example, the entry "ITCORP\0\3+ITcorp\0+ITCorp\0+ItCorp\0"
X 	** gives various ways of writing my e-mail address.  If all-lowercase
X 	** is acceptable, an all-lower entry must appear.  Simple
X 	** capitalization, on the other hand, is signified by the "capitalize"
X 	** flag.
X 	**
X 	** Suffixes always match the case of the final character of a word.
X 	**
X 	** If "allcaps" is set, the other two flags must be clear.
X 	*/
X 	unsigned short allcaps : 1;	/* Word must be all capitals */
X 	unsigned short capitalize : 1;	/* Capitalize the word */
X 	unsigned short followcase : 1;	/* Follow capitalization exactly */
X 	/*
X 	** The following entries denote the flag values that are actually
X 	** to be kept for this dictionary entry.  They may differ if the
X 	** "a" command is used for a word that differs only in capitalization.
X 	*/
X 	unsigned short k_allcaps : 1;
X 	unsigned short k_capitalize : 1;
X 	unsigned short k_followcase : 1;
X #endif
X 
X };
X 
X #define WORDLEN 30
X 
X struct hashheader {
X 	int magic;
X 	int stringsize;
X 	int tblsize;
X };
X 
X /* hash table magic number */
X #define MAGIC 2
X 
X 	
X /*
X  * termcap variables
X  */
X #ifdef MAIN
X # define EXTERN /* nothing */
X #else
X # define EXTERN extern
X #endif
X 
X EXTERN char *tgetstr();
X EXTERN char PC;	/* padding character */
X EXTERN char *BC;	/* backspace if not ^H */
X EXTERN char *UP;	/* Upline (cursor up) */
X EXTERN char *cd;	/* clear to end of display */
X EXTERN char *ce;	/* clear to end of line */
X EXTERN char *cl;	/* clear display */
X EXTERN char *cm;	/* cursor movement */
X EXTERN char *dc;	/* delete character */
X EXTERN char *dl;	/* delete line */
X EXTERN char *dm;	/* delete mode */
X EXTERN char *ed;	/* exit delete mode */
X EXTERN char *ei;	/* exit insert mode */
X EXTERN char *ho;	/* home */
X EXTERN char *ic;	/* insert character */
X EXTERN char *il;	/* insert line */
X EXTERN char *im;	/* insert mode */
X EXTERN char *ip;	/* insert padding */
X EXTERN char *nd;	/* non-destructive space */
X EXTERN char *vb;	/* visible bell */
X EXTERN char *so;	/* standout */
X EXTERN char *se;	/* standout end */
X EXTERN int bs;
X EXTERN int li, co;	/* lines, columns */
X 
X EXTERN char termcap[1024];
X EXTERN char termstr[1024];	/* for string values */
X EXTERN char *termptr;
X 
X EXTERN char rootword[BUFSIZ];
X EXTERN struct dent *lastdent;
X 
X EXTERN char *hashstrings;
X EXTERN struct hashheader hashheader;
X 
X extern int aflag;
X extern int lflag;
X 
X EXTERN int erasechar;
X EXTERN int killchar;
X 
X EXTERN char tempfile[200];
X 
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'lookup.c'" '(2758 characters)'
if test -f 'lookup.c'
then
	echo shar: will not over-write existing file "'lookup.c'"
else
sed 's/^X //' << \SHAR_EOF > 'lookup.c'
X /* -*- Mode:Text -*- */
X 
X /*
X  * lookup.c - see if a word appears in the dictionary
X  *
X  * Pace Willisson, 1983
X  */
X 
X #include <stdio.h>
X #include "config.h"
X #include "ispell.h"
X 
X 
X struct dent *treelookup();
X struct dent *hashtbl;
X int hashsize;
X 
X extern char hashname[];
X 
X static inited = 0;
X 
X linit ()
X {
X 	int hashfd;
X 	register int i;
X 	register struct dent *dp;
X 
X 	if (inited)
X 		return;
X 
X 	if ((hashfd = open (hashname, 0)) < 0) {
X 		fprintf (stderr, "can't open %s\r\n", hashname);
X 		return (-1);
X 	}
X 
X 	hashsize = read (hashfd, &hashheader, sizeof hashheader);
X 	if (hashsize == 0) {
X 		/*
X 		 * Empty file - create an empty dummy table.  We
X 		 * actually have to have one entry since the hash
X 		 * algorithm involves a divide by the table size
X 		 * (actually modulo, but zero is still unacceptable).
X 		 * So we create an entry with a word of all lowercase,
X 		 * which can't match because the comparison string has
X 		 * been converted to uppercase by then.
X 		 */
X 		close (hashfd);
X 		hashsize = 1;		/* This prevents divides by zero */
X 		hashtbl = (struct dent *) calloc (1, sizeof (struct dent));
X 		if (hashtbl == NULL) {
X 			(void) fprintf (stderr,
X 			    "Couldn't allocate space for hash table\n");
X 			return (-1);
X 		}
X 		hashtbl[0].word = "xxxxxxxxxxx";
X 		hashtbl[0].next = NULL;
X 		hashtbl[0].keep = 0;
X 		hashtbl[0].used = 1;
X 		/* The flag bits don't matter, but calloc cleared them. */
X 		inited = 1;
X 		return 0;
X 	}
X 	else if (hashsize < 0  ||  hashheader.magic != MAGIC) {
X 		fprintf (stderr, "Illegal format hash table\r\n");
X 		return (-1);
X 	}
X 	hashstrings = (char *) malloc (hashheader.stringsize);
X 	hashtbl = (struct dent *) malloc (hashheader.tblsize * sizeof (struct dent));
X 	if (hashtbl == NULL  ||  hashstrings == NULL) {
X 		(void) fprintf (stderr,
X 		    "Couldn't allocate space for hash table\n");
X 		return (-1);
X 	}
X 	hashsize = hashheader.tblsize;
X 
X 	read (hashfd, hashstrings, hashheader.stringsize);
X 	read (hashfd, hashtbl, hashheader.tblsize * sizeof (struct dent));
X 	close (hashfd);
X 
X 	for (i = hashsize, dp = hashtbl;  --i >= 0;  dp++) {
X 		dp->word = &hashstrings [ (int)(dp->word) ];
X 		if (dp->next == (struct dent *) -1)
X 			dp->next = NULL;
X 		else
X 			dp->next = &hashtbl [ (int)(dp->next) ];
X 	}
X 
X 	inited = 1;
X 	return (0);
X }
X 
X /* n is length of s */
X struct dent *
X lookup (s, n, dotree)
X register char *s;
X {
X 	int i;
X 	register struct dent *dp;
X 	register char *s1, *s2;
X 
X 	dp = &hashtbl [ hash (s, n, hashsize) ];
X 	for (  ; dp != NULL; dp = dp->next) {
X 		/* quick strcmp, but only for equality */
X 		s1 = dp->word;
X 		s2 = s;
X 		while (*s1 == *s2++)
X 			if (*s1++=='\0') {
X 				lastdent = dp;
X 				return (lastdent);
X 			}
X 	}
X 	if (dotree) {
X 		i = s[n];
X 		s[n] = '\0';
X 		if ((dp = treelookup (s)) != NULL)
X 			lastdent = dp;
X 		s[n] = i;
X 		return dp;
X 	}
X 	else
X 		return NULL;
X }
X 
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'makedict.sh'" '(964 characters)'
if test -f 'makedict.sh'
then
	echo shar: will not over-write existing file "'makedict.sh'"
else
sed 's/^X //' << \SHAR_EOF > 'makedict.sh'
X : Use /bin/sh
X #
X #	Make a beginning dictionary file for ispell, using an existing
X #	speller.
X #
X #	Usage:
X #
X #	makedict file-list
X #
X #	The specified files are collected, split into words, and run through
X #	the system speller (usually spell(1)).  Any words that the speller
X #	accepts will be written to the standard output for use in making
X #	an ispell dictionary.  Usually, you will want to run the output
X #	of this script through "munchlist" to get a final dictionary.
X #
X 
X # This program must produce a list of INCORRECTLY spelled words on standard
X # output, given a list of words on standard input.  If you don't have a
X # speller, but do have a lot of correctly-spelled files, try /bin/true.
X #
X SPELLPROG="${SPELLPROG:-spell}"
X 
X TMP=${TMPDIR:-/tmp}/mkdict$$
X 
X case "$#" in
X     0)
X 	set X -
X 	shift
X 	;;
X esac
X 
X trap "/bin/rm ${TMP}; exit 1" 1 2 15
X 
X cat "$@" | deroff | tr -cs "[A-Z][a-z]'" '[\012*]' | sort -uf -o ${TMP}
X $SPELLPROG < ${TMP} | comm -13 - ${TMP}
X /bin/rm ${TMP}
SHAR_EOF
chmod +x 'makedict.sh'
fi # end of overwriting check
#	End of shell archive
exit 0

-- 
Brandon S. Allbery	{decvax,cbatt,cbosgd}!cwruecmp!ncoast!allbery
Tridelta Industries	{ames,mit-eddie,talcott}!necntc!ncoast!allbery
7350 Corporate Blvd.	necntc!ncoast!allbery@harvard.HARVARD.EDU
Mentor, OH 44060	+01 216 255 1080	(also eddie.MIT.EDU)