/* EPSHeader File: spell.e Author: J. Kercheval Created: Mon, 09/16/1991 22:46:44 */ /* EPSRevision History J. Kercheval Mon, 09/16/1991 22:46:52 creation J. Kercheval Sun, 09/22/1991 22:20:02 add automatic word file search and load J. Kercheval Sun, 06/21/1992 00:29:35 modify for V6.0 highlighted regions E. L. Olsen 4/21/93 1) Set point to begining of newly entered words so that they are spell checked again, after they are entered. 2) Made change so that the word currently being checked is hilighted, rather than displaying the percent complete. 3) The ignore buffer loaded from file "ignore.lst", if it exists. 4) Made ignore buffer visible so that it can be saved as a file. 5) It used to be that all ignored words were added to the ignore list. Now you must enter a space space to causes a word to be added to the ignore list. Entering a carriage return still causes words to be ignored, but they are not added to the list. E. L. Olsen 12/19/94 Fixed bug in do_spell_region that caused word not to be rechecked if user entered the same spelling. E. L. Olsen 03/09/95 Fixed two bugs in spell_region: Test of return value from lookpath wordfile was incorrect (it was dereferenced) and call to gripe was incorrect. Call to gripe was replaced with call to say. E. L. Olsen 06/06/95 Fixed a bug in do_spell_region that became apparent in epsilon 7.0. Replaced use of matchstart with mark. */ /* This file implements a basic spelling checker which relies upon an external list of correctly spelled, sorted words in an ascii format and delimited by newlines. Case is ignored in this speller. The basic algorithm is brute force and simple marches through every word in the input region (or buffer) and checks that word against the wordlist. If the word in not contained in the word list then an ignore buffer which is being maintained is looked at and if the word is not there then the user is presented with the word and allowed to change it. Entering a space will cause the word to be placed in the ignore buffer for future occurances of that word. Entering just a carriage return will cause just the current occurance of the word to be ignored. There are two commands implemented, spell_region and spell_buffer (spell_buffer is just a call to spell_region with the values of point and mark as 0 and size() respectively. The search of the word in the dictionary is done via a binary search. This brute force method is considerably slower than a trie or dictionary method but is sufficient for a programmer's editor and is quite a bit more flexible and easier to write. A new buffer is created by the name of "-words" which is not deleted upon completion to allow for faster response on later spell checks. This code is dedicated to the public domain with the caveat that Lugaru is welcome to use this within their distribution source code which is supplied with Epsilon. John Kercheval 15563 10th Ave NE Seattle, WA 98155-6209 INTERNET: jbk@wrq.com Compu$erve: 72450,3702 jbk@wrq.com */ #include #ifndef BOOLEAN #define BOOLEAN int #define TRUE 1 #define FALSE 0 #endif /*---------------------------------------------------------------------------- * * SpellIsSpecial() is a helper function to determine if a particular word * contains one of the special chars (ie. a number or underscore) * ---------------------------------------------------------------------------*/ BOOLEAN SpellIsSpecial(s) char *s; { while (*s) { if (isdigit(*s)) return TRUE; if (*s == '_') return TRUE; s++; } return FALSE; } /*---------------------------------------------------------------------------- * * do_spell_region() sets up the needed buffers initializes the point in the * input buffer and repeatedly calls spell_check to actually perform the * binary search for the element * ---------------------------------------------------------------------------*/ do_spell_region(inbuf, wordbuf, ignorebuf) char *inbuf; char *wordbuf; char *ignorebuf; { char elem[256]; char res[256]; spot end = alloc_spot(); /* store the old point, mark and buffer, store and turn of highlight */ save_spot point, mark; save_var bufname; save_var _highlight_control = 0; /* move to buffer */ bufname = inbuf; /* set point and end location */ if (point > mark) { *end = point; point = mark; } else { *end = mark; } note("Working..."); highlight_on (); /* run through the region */ while (point < *end) { /* get next word to check */ if (! re_search(1, "[a-zA-Z0-9_']+")) break; grab(matchstart, point, elem); /* highlight the region (and thus the word) */ mark = matchstart; refresh(); /* check if special */ if (SpellIsSpecial(elem)) { bufname = inbuf; continue; } /* check ignore list */ bufname = ignorebuf; point = 0; if (search(1, elem)) { bufname = inbuf; continue; } /* check dictionary */ bufname = wordbuf; if (do_binary_search(elem)) { bufname = inbuf; continue; } /* get user input */ bufname = inbuf; get_strnone(res, "=add =ignore or correct: ", elem); if (strcmp(" ", res) == 0) { /* ignore all instances of this word */ bufname = ignorebuf; point = 0; stuff(elem); stuff("\n"); bufname = inbuf; } else if (strcmp("", res) != 0) { /* user changed the elem */ delete(mark, point); /* matchstart was used instead of mark */ stuff(res); /* set point to begining of user's new word */ point = mark; /* matchstart was used instead of mark */ /* turn highlighting back on */ highlight_on (); } note("Working..."); } /* end while */ /* clean up */ note("Done."); free_spot(end); } #define WORD_LIST_BUFFER "-words" #define WORD_FILE_NAME "words.lst" #define IGNORE_BUFFER "ignore.lst" command spell_region() { char *ignorebuf = IGNORE_BUFFER; char *wordbuf = WORD_LIST_BUFFER; char *wordfile = WORD_FILE_NAME; char *oldbuf = bufname; char *words; int file_error; note("Loading dictionary..."); if (!exist(wordbuf)) { /* obtain the word file */ words = lookpath(wordfile); if (words) { create(wordbuf); bufname = wordbuf; file_error = file_read(words, strip_returns); bufname = oldbuf; if (file_error) { say("Error reading word file."); return; } } else { say("Word file '%s' not found in EPSPATH", wordfile); return; } } note("Loading ignore.lst..."); /* create ignore buffer */ if (!exist(ignorebuf)) { create(ignorebuf); bufname = ignorebuf; file_error = file_read(ignorebuf, strip_returns); filename = ignorebuf; bufname = oldbuf; } /* run the spell checker */ do_spell_region(bufname, wordbuf, ignorebuf); } command spell_buffer() { /* store the old point and mark */ save_spot point, mark; /* set the region */ mark = 0; point = size(); /* run the spell checker */ spell_region(); }