* New version 2.26
[alpine.git] / pico / osdep / spell.c
blob63aa243450cd4aec666a214f1fbefe23e243cca1
1 /*
2 * ========================================================================
3 * Copyright 2006-2007 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
14 * Program: spell.c
18 #include <system.h>
19 #include <general.h>
21 #include "../headers.h"
23 #include "../estruct.h"
24 #include "../mode.h"
25 #include "../pico.h"
26 #include "../edef.h"
27 #include "../efunc.h"
28 #include "../keydefs.h"
31 #include "../../pith/charconv/filesys.h"
33 #include "popen.h"
34 #include "altedit.h"
35 #include "spell.h"
38 #ifdef SPELLER
40 int movetoword(UCS *);
43 static char *spellhelp[] = {
44 /* TRANSLATORS: Some help text. The ~ characters cause
45 the characters they are in front of to be bold. */
46 N_("Spell Check Help"),
47 " ",
48 N_(" The spell checker examines all words in the text. It then"),
49 N_(" offers each misspelled word for correction while simultaneously"),
50 N_(" highlighting it in the text. To leave a word unchanged simply"),
51 N_("~ hit ~R~e~t~u~r~n at the edit prompt. If a word has been corrected,"),
52 N_(" each occurrence of the incorrect word is offered for replacement."),
53 " ",
54 N_("~ Spell checking can be cancelled at any time by typing ~^~C (~F~3)"),
55 N_(" after exiting help."),
56 " ",
57 N_("End of Spell Check Help"),
58 " ",
59 NULL
63 static char *pinespellhelp[] = {
64 N_("Spell Check Help"),
65 " ",
66 N_("\tThe spell checker examines all words in the text. It then"),
67 N_("\toffers each misspelled word for correction while simultaneously"),
68 N_("\thighlighting it in the text. To leave a word unchanged simply"),
69 N_("\thit Return at the edit prompt. If a word has been corrected,"),
70 N_("\teach occurrence of the incorrect word is offered for replacement."),
71 " ",
72 N_("\tSpell checking can be cancelled at any time by typing ^C (F3)"),
73 N_("\tafter exiting help."),
74 " ",
75 N_("End of Spell Check Help"),
76 " ",
77 NULL
80 #ifndef _WINDOWS
82 * spell() - check for potentially missspelled words and offer them for
83 * correction
85 int
86 spell(int f, int n)
88 int status, next, ret;
89 char ccb[NLINE], *sp, *fn, *lp, *wsp, c, spc[NLINE];
90 UCS *b;
91 UCS wb[NLINE], cb[NLINE];
92 EML eml;
94 setimark(0, 1);
95 emlwrite(_("Checking spelling..."), NULL); /* greetings */
97 if(alt_speller)
98 return(alt_editor(1, 0)); /* f == 1 means fork speller */
100 if((fn = writetmp(0, NULL)) == NULL){
101 emlwrite(_("Can't write temp file for spell checker"), NULL);
102 return(-1);
105 if((sp = (char *)getenv("SPELL")) == NULL)
106 sp = SPELLER;
108 /* exists? */
109 ret = (strlen(sp) + 1);
110 snprintf(spc, sizeof(spc), "%s", sp);
112 for(lp = spc, ret = FIOERR; *lp; lp++){
113 if((wsp = strpbrk(lp, " \t")) != NULL){
114 c = *wsp;
115 *wsp = '\0';
118 if(strchr(lp, '/')){
119 ret = fexist(lp, "x", (off_t *)NULL);
121 else{
122 char *path, fname[MAXPATH+1];
124 if(!(path = getenv("PATH")))
125 path = ":/bin:/usr/bin";
127 ret = ~FIOSUC;
128 while(ret != FIOSUC && *path && pathcat(fname, &path, lp))
129 ret = fexist(fname, "x", (off_t *)NULL);
132 if(wsp)
133 *wsp = c;
135 if(ret == FIOSUC)
136 break;
139 if(ret != FIOSUC){
140 eml.s = sp;
141 emlwwrite(_("Spell-checking file \"%s\" not found"), &eml);
142 return(-1);
145 snprintf(ccb, sizeof(ccb), "( %s ) < %s", sp, fn);
146 if(P_open(ccb) != FIOSUC){ /* read output from command */
147 our_unlink(fn);
148 emlwrite(_("Can't fork spell checker"), NULL);
149 return(-1);
152 ret = 1;
153 while(ffgetline(wb, NLINE, NULL, 0) == FIOSUC && ret){
154 if((b = ucs4_strchr(wb, (UCS) '\n')) != NULL)
155 *b = '\0';
157 ucs4_strncpy(cb, wb, NLINE);
158 cb[NLINE-1] = '\0';
160 gotobob(0, 1);
162 status = TRUE;
163 next = 1;
165 while(status){
166 if(next++)
167 if(movetoword(wb) != TRUE)
168 break;
170 update();
171 (*term.t_rev)(1);
172 pputs(wb, 1); /* highlight word */
173 (*term.t_rev)(0);
175 if(ucs4_strcmp(cb, wb)){
176 char prompt[2*NLINE + 32];
177 char *wbu, *cbu;
179 wbu = ucs4_to_utf8_cpystr(wb);
180 cbu = ucs4_to_utf8_cpystr(cb);
182 snprintf(prompt, sizeof(prompt), _("Replace \"%s\" with \"%s\""), wbu, cbu);
183 status=mlyesno_utf8(prompt, TRUE);
184 if(wbu)
185 fs_give((void **) &wbu);
186 if(cbu)
187 fs_give((void **) &cbu);
189 else{
190 UCS *p;
192 p = utf8_to_ucs4_cpystr(_("Edit a replacement: "));
193 status=mlreplyd(p, cb, NLINE, QDEFLT, NULL);
194 if(p)
195 fs_give((void **) &p);
199 curwp->w_flag |= WFMOVE; /* put cursor back */
200 sgarbk = 0; /* fake no-keymenu-change! */
201 update();
202 pputs(wb, 0); /* un-highlight */
204 switch(status){
205 case TRUE:
206 chword(wb, cb, 0); /* correct word */
207 case FALSE:
208 update(); /* place cursor */
209 break;
210 case ABORT:
211 emlwrite(_("Spell Checking Cancelled"), NULL);
212 ret = FALSE;
213 status = FALSE;
214 break;
215 case HELPCH:
216 if(Pmaster){
217 VARS_TO_SAVE *saved_state;
219 saved_state = save_pico_state();
220 (*Pmaster->helper)(pinespellhelp,
221 _("Help with Spelling Checker"), 1);
222 if(saved_state){
223 restore_pico_state(saved_state);
224 free_pico_state(saved_state);
227 else
228 pico_help(spellhelp, _("Help with Spelling Checker"), 1);
230 case (CTRL|'L'):
231 next = 0; /* don't get next word */
232 sgarbf = TRUE; /* repaint full screen */
233 update();
234 status = TRUE;
235 continue;
236 default:
237 emlwrite("Huh?", NULL); /* shouldn't get here, but.. */
238 status = TRUE;
239 sleep(1);
240 break;
243 forwword(0, 1); /* goto next word */
247 P_close(); /* clean up */
248 our_unlink(fn);
249 swapimark(0, 1);
250 curwp->w_flag |= WFHARD|WFMODE;
251 sgarbk = TRUE;
253 if(ret)
254 emlwrite(_("Done checking spelling"), NULL);
256 return(ret);
260 #endif /* UNIX */
264 * movetoword() - move to the first occurance of the word w
266 * returns:
267 * TRUE upon success
268 * FALSE otherwise
271 movetoword(UCS *w)
273 int i;
274 int ret = FALSE;
275 int olddoto;
276 LINE *olddotp;
277 register int off; /* curwp offset */
278 register LINE *lp; /* curwp line */
280 olddoto = curwp->w_doto; /* save where we are */
281 olddotp = curwp->w_dotp;
283 curwp->w_bufp->b_mode |= MDEXACT; /* case sensitive */
284 while(forscan(&i, w, SR_FORWARD, NULL, 0, 1) == TRUE){
285 if(i)
286 break; /* wrap NOT allowed! */
288 lp = curwp->w_dotp; /* for convenience */
289 off = curwp->w_doto;
292 * We want to minimize the number of substrings that we report
293 * as matching a misspelled word...
295 if(off == 0 || !ucs4_isalpha(lgetc(lp, off - 1).c)){
296 off += ucs4_strlen(w);
297 if((!ucs4_isalpha(lgetc(lp, off).c) || off == llength(lp))
298 && lgetc(lp, 0).c != '>'){
299 ret = TRUE;
300 break;
304 forwchar(0, 1); /* move on... */
307 curwp->w_bufp->b_mode ^= MDEXACT; /* case insensitive */
309 if(ret == FALSE){
310 curwp->w_dotp = olddotp;
311 curwp->w_doto = olddoto;
313 else
314 curwp->w_flag |= WFHARD;
316 return(ret);
319 #endif /* SPELLER */