* New alpha version 2.24.1
[alpine.git] / pico / osdep / spell.c
blob7988daad43db34e38e01c9f2911f52a9a2ccb408
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: spell.c 854 2007-12-07 17:44:43Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2021 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
18 * Program: spell.c
22 #include <system.h>
23 #include <general.h>
25 #include "../headers.h"
27 #include "../estruct.h"
28 #include "../mode.h"
29 #include "../pico.h"
30 #include "../edef.h"
31 #include "../efunc.h"
32 #include "../keydefs.h"
35 #include "../../pith/charconv/filesys.h"
37 #include "popen.h"
38 #include "altedit.h"
39 #include "spell.h"
42 #ifdef SPELLER
44 int movetoword(UCS *);
47 static char *spellhelp[] = {
48 /* TRANSLATORS: Some help text. The ~ characters cause
49 the characters they are in front of to be bold. */
50 N_("Spell Check Help"),
51 " ",
52 N_(" The spell checker examines all words in the text. It then"),
53 N_(" offers each misspelled word for correction while simultaneously"),
54 N_(" highlighting it in the text. To leave a word unchanged simply"),
55 N_("~ hit ~R~e~t~u~r~n at the edit prompt. If a word has been corrected,"),
56 N_(" each occurrence of the incorrect word is offered for replacement."),
57 " ",
58 N_("~ Spell checking can be cancelled at any time by typing ~^~C (~F~3)"),
59 N_(" after exiting help."),
60 " ",
61 N_("End of Spell Check Help"),
62 " ",
63 NULL
67 static char *pinespellhelp[] = {
68 N_("Spell Check Help"),
69 " ",
70 N_("\tThe spell checker examines all words in the text. It then"),
71 N_("\toffers each misspelled word for correction while simultaneously"),
72 N_("\thighlighting it in the text. To leave a word unchanged simply"),
73 N_("\thit Return at the edit prompt. If a word has been corrected,"),
74 N_("\teach occurrence of the incorrect word is offered for replacement."),
75 " ",
76 N_("\tSpell checking can be cancelled at any time by typing ^C (F3)"),
77 N_("\tafter exiting help."),
78 " ",
79 N_("End of Spell Check Help"),
80 " ",
81 NULL
84 #ifndef _WINDOWS
86 * spell() - check for potentially missspelled words and offer them for
87 * correction
89 int
90 spell(int f, int n)
92 int status, next, ret;
93 char ccb[NLINE], *sp, *fn, *lp, *wsp, c, spc[NLINE];
94 UCS *b;
95 UCS wb[NLINE], cb[NLINE];
96 EML eml;
98 setimark(0, 1);
99 emlwrite(_("Checking spelling..."), NULL); /* greetings */
101 if(alt_speller)
102 return(alt_editor(1, 0)); /* f == 1 means fork speller */
104 if((fn = writetmp(0, NULL)) == NULL){
105 emlwrite(_("Can't write temp file for spell checker"), NULL);
106 return(-1);
109 if((sp = (char *)getenv("SPELL")) == NULL)
110 sp = SPELLER;
112 /* exists? */
113 ret = (strlen(sp) + 1);
114 snprintf(spc, sizeof(spc), "%s", sp);
116 for(lp = spc, ret = FIOERR; *lp; lp++){
117 if((wsp = strpbrk(lp, " \t")) != NULL){
118 c = *wsp;
119 *wsp = '\0';
122 if(strchr(lp, '/')){
123 ret = fexist(lp, "x", (off_t *)NULL);
125 else{
126 char *path, fname[MAXPATH+1];
128 if(!(path = getenv("PATH")))
129 path = ":/bin:/usr/bin";
131 ret = ~FIOSUC;
132 while(ret != FIOSUC && *path && pathcat(fname, &path, lp))
133 ret = fexist(fname, "x", (off_t *)NULL);
136 if(wsp)
137 *wsp = c;
139 if(ret == FIOSUC)
140 break;
143 if(ret != FIOSUC){
144 eml.s = sp;
145 emlwwrite(_("Spell-checking file \"%s\" not found"), &eml);
146 return(-1);
149 snprintf(ccb, sizeof(ccb), "( %s ) < %s", sp, fn);
150 if(P_open(ccb) != FIOSUC){ /* read output from command */
151 our_unlink(fn);
152 emlwrite(_("Can't fork spell checker"), NULL);
153 return(-1);
156 ret = 1;
157 while(ffgetline(wb, NLINE, NULL, 0) == FIOSUC && ret){
158 if((b = ucs4_strchr(wb, (UCS) '\n')) != NULL)
159 *b = '\0';
161 ucs4_strncpy(cb, wb, NLINE);
162 cb[NLINE-1] = '\0';
164 gotobob(0, 1);
166 status = TRUE;
167 next = 1;
169 while(status){
170 if(next++)
171 if(movetoword(wb) != TRUE)
172 break;
174 update();
175 (*term.t_rev)(1);
176 pputs(wb, 1); /* highlight word */
177 (*term.t_rev)(0);
179 if(ucs4_strcmp(cb, wb)){
180 char prompt[2*NLINE + 32];
181 char *wbu, *cbu;
183 wbu = ucs4_to_utf8_cpystr(wb);
184 cbu = ucs4_to_utf8_cpystr(cb);
186 snprintf(prompt, sizeof(prompt), _("Replace \"%s\" with \"%s\""), wbu, cbu);
187 status=mlyesno_utf8(prompt, TRUE);
188 if(wbu)
189 fs_give((void **) &wbu);
190 if(cbu)
191 fs_give((void **) &cbu);
193 else{
194 UCS *p;
196 p = utf8_to_ucs4_cpystr(_("Edit a replacement: "));
197 status=mlreplyd(p, cb, NLINE, QDEFLT, NULL);
198 if(p)
199 fs_give((void **) &p);
203 curwp->w_flag |= WFMOVE; /* put cursor back */
204 sgarbk = 0; /* fake no-keymenu-change! */
205 update();
206 pputs(wb, 0); /* un-highlight */
208 switch(status){
209 case TRUE:
210 chword(wb, cb, 0); /* correct word */
211 case FALSE:
212 update(); /* place cursor */
213 break;
214 case ABORT:
215 emlwrite(_("Spell Checking Cancelled"), NULL);
216 ret = FALSE;
217 status = FALSE;
218 break;
219 case HELPCH:
220 if(Pmaster){
221 VARS_TO_SAVE *saved_state;
223 saved_state = save_pico_state();
224 (*Pmaster->helper)(pinespellhelp,
225 _("Help with Spelling Checker"), 1);
226 if(saved_state){
227 restore_pico_state(saved_state);
228 free_pico_state(saved_state);
231 else
232 pico_help(spellhelp, _("Help with Spelling Checker"), 1);
234 case (CTRL|'L'):
235 next = 0; /* don't get next word */
236 sgarbf = TRUE; /* repaint full screen */
237 update();
238 status = TRUE;
239 continue;
240 default:
241 emlwrite("Huh?", NULL); /* shouldn't get here, but.. */
242 status = TRUE;
243 sleep(1);
244 break;
247 forwword(0, 1); /* goto next word */
251 P_close(); /* clean up */
252 our_unlink(fn);
253 swapimark(0, 1);
254 curwp->w_flag |= WFHARD|WFMODE;
255 sgarbk = TRUE;
257 if(ret)
258 emlwrite(_("Done checking spelling"), NULL);
260 return(ret);
264 #endif /* UNIX */
268 * movetoword() - move to the first occurance of the word w
270 * returns:
271 * TRUE upon success
272 * FALSE otherwise
275 movetoword(UCS *w)
277 int i;
278 int ret = FALSE;
279 int olddoto;
280 LINE *olddotp;
281 register int off; /* curwp offset */
282 register LINE *lp; /* curwp line */
284 olddoto = curwp->w_doto; /* save where we are */
285 olddotp = curwp->w_dotp;
287 curwp->w_bufp->b_mode |= MDEXACT; /* case sensitive */
288 while(forscan(&i, w, SR_FORWARD, NULL, 0, 1) == TRUE){
289 if(i)
290 break; /* wrap NOT allowed! */
292 lp = curwp->w_dotp; /* for convenience */
293 off = curwp->w_doto;
296 * We want to minimize the number of substrings that we report
297 * as matching a misspelled word...
299 if(off == 0 || !ucs4_isalpha(lgetc(lp, off - 1).c)){
300 off += ucs4_strlen(w);
301 if((!ucs4_isalpha(lgetc(lp, off).c) || off == llength(lp))
302 && lgetc(lp, 0).c != '>'){
303 ret = TRUE;
304 break;
308 forwchar(0, 1); /* move on... */
311 curwp->w_bufp->b_mode ^= MDEXACT; /* case insensitive */
313 if(ret == FALSE){
314 curwp->w_dotp = olddotp;
315 curwp->w_doto = olddoto;
317 else
318 curwp->w_flag |= WFHARD;
320 return(ret);
323 #endif /* SPELLER */