~ubuntu-branches/ubuntu/lucid/x11-apps/lucid

« back to all changes in this revision

Viewing changes to xedit/ispell.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Cristau
  • Date: 2008-09-23 00:24:45 UTC
  • mfrom: (1.1.2 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080923002445-mb2rwkif45zz1vlj
Tags: 7.3+4
* Remove xedit from the package, it's unmaintained and broken
  (closes: #321434).
* Remove xedit's conffiles on upgrade.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 1999 by The XFree86 Project, Inc.
3
 
 *
4
 
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 
 * copy of this software and associated documentation files (the "Software"),
6
 
 * to deal in the Software without restriction, including without limitation
7
 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 
 * and/or sell copies of the Software, and to permit persons to whom the
9
 
 * Software is furnished to do so, subject to the following conditions:
10
 
 *
11
 
 * The above copyright notice and this permission notice shall be included in
12
 
 * all copies or substantial portions of the Software.
13
 
 *  
14
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17
 
 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
 
 * SOFTWARE.
21
 
 *
22
 
 * Except as contained in this notice, the name of the XFree86 Project shall
23
 
 * not be used in advertising or otherwise to promote the sale, use or other
24
 
 * dealings in this Software without prior written authorization from the
25
 
 * XFree86 Project.
26
 
 *
27
 
 * Author: Paulo César Pereira de Andrade
28
 
 */
29
 
 
30
 
/* $XdotOrg: app/xedit/ispell.c,v 1.7 2005/04/04 10:17:07 eich Exp $ */
31
 
/* $XFree86: xc/programs/xedit/ispell.c,v 1.19 2002/10/19 20:04:20 herrb Exp $ */
32
 
 
33
 
#include "xedit.h"
34
 
#include <stdlib.h>
35
 
#include <unistd.h>
36
 
#include <fcntl.h>
37
 
#include <signal.h>
38
 
#include <ctype.h>
39
 
#include <errno.h>
40
 
#include <sys/types.h>
41
 
#include <sys/wait.h>
42
 
#include <X11/Xaw/Toggle.h>
43
 
#include <X11/Xaw/MenuButton.h>
44
 
#include <X11/Xaw/SmeBSB.h>
45
 
#include <X11/Xaw/SimpleMenu.h>
46
 
#include <X11/Xos.h>
47
 
 
48
 
#define RECEIVE         1
49
 
#define SEND            2
50
 
 
51
 
#define CHECK           0
52
 
#define ADD             1
53
 
#define REMOVE          2
54
 
 
55
 
#define ASIS            1
56
 
#define UNCAP           2
57
 
 
58
 
/*
59
 
 * Types
60
 
 */
61
 
#define UNDO_DEPTH      16
62
 
typedef struct _ispell_undo {
63
 
    char *undo_str;
64
 
    int undo_count;
65
 
    XawTextPosition undo_pos;
66
 
    Boolean repeat;     /* two (misspelled?) words together */
67
 
    Boolean terse;
68
 
    int format;         /* remember text formatting style */
69
 
    struct _ispell_undo *next, *prev;
70
 
} ispell_undo;
71
 
 
72
 
typedef struct _ispell_dict {
73
 
    Widget sme;
74
 
    char *wchars;
75
 
    struct _ispell_dict *next;
76
 
} ispell_dict;
77
 
 
78
 
#define TEXT    0
79
 
#define HTML    1
80
 
struct _ispell_format {
81
 
    char *name;
82
 
    int value;
83
 
    Widget sme;
84
 
};
85
 
 
86
 
static struct _ispell_format ispell_format[] = {
87
 
    {"text",    TEXT},
88
 
    {"html",    HTML},
89
 
};
90
 
 
91
 
struct _ispell {
92
 
    Widget shell, form, mispelled, repeated, word, replacement, text,
93
 
           suggestions, viewport, list, commands, replace, status,
94
 
           replaceAll, undo, ignore, ignoreAll, add, addUncap, suspend,
95
 
           cancel, check, look, terse, options, dict, dictMenu,
96
 
           format, formatMenu;
97
 
 
98
 
    Widget ascii, source;
99
 
    XtInputId id;
100
 
    int pid, ifd[2], ofd[2];
101
 
    XawTextPosition left, right;
102
 
    char *item;
103
 
    Bool lock;
104
 
    Bool repeat;
105
 
    Bool checkit;
106
 
    int stat;
107
 
    char *buf;
108
 
    int bufsiz;
109
 
    int buflen;
110
 
    char sendbuf[1024];
111
 
    char sentbuf[1024];
112
 
 
113
 
    int undo_depth;
114
 
    ispell_undo *undo_head, *undo_base;
115
 
    char *undo_for;
116
 
 
117
 
    char *wchars;
118
 
    char *cmd;
119
 
    char *skip;
120
 
    char *command;
121
 
    Boolean terse_mode, undo_terse_mode;
122
 
    char *guess_label, *miss_label, *root_label, *none_label, *eof_label,
123
 
         *compound_label, *ok_label, *repeat_label, *working_label, *look_label;
124
 
    char *look_cmd;
125
 
    char *words_file;
126
 
 
127
 
    char *dictionary;
128
 
    char *dict_list;
129
 
    ispell_dict *dict_info;
130
 
 
131
 
    int format_mode;    /* to undo correctly */
132
 
    char *formatting;
133
 
    struct _ispell_format *format_info;
134
 
};
135
 
 
136
 
typedef struct _ReplaceList {
137
 
    char *word;
138
 
    char *replace;
139
 
    struct _ReplaceList *next;
140
 
} ReplaceList;
141
 
 
142
 
typedef struct _IgnoreList {
143
 
    char *word;
144
 
    int add;
145
 
    struct _IgnoreList *next;
146
 
} IgnoreList;
147
 
 
148
 
/*
149
 
 * Prototypes
150
 
 */
151
 
static void AddIspell(Widget, XtPointer, XtPointer);
152
 
static void ChangeDictionaryIspell(Widget, XtPointer, XtPointer);
153
 
static void ChangeFormatIspell(Widget, XtPointer, XtPointer);
154
 
static void CheckIspell(Widget, XtPointer, XtPointer);
155
 
static void IgnoreIspell(Widget, XtPointer, XtPointer);
156
 
static Bool InitIspell(void);
157
 
static void IspellCheckUndo(void);
158
 
static int IspellConvertHtmlAmp(char*);
159
 
static Bool IspellDoIgnoredWord(char*, int, int);
160
 
static Bool IspellIgnoredWord(char*, int, int);
161
 
static void IspellInputCallback(XtPointer, int*, XtInputId*);
162
 
static void IspellKillUndoBuffer(void);
163
 
static Bool IspellReceive(void);
164
 
static char *IspellReplacedWord(char*, char*);
165
 
static int IspellSend(void);
166
 
static void IspellSetSelection(XawTextPosition, XawTextPosition);
167
 
static void IspellSetRepeated(Bool);
168
 
static void IspellSetSensitive(Bool);
169
 
static void IspellSetStatus(char*);
170
 
static void IspellSetTerseMode(Bool);
171
 
static Bool IspellStartProcess(void);
172
 
static Bool IspellEndProcess(Bool, Bool);
173
 
static void LookIspell(Widget, XtPointer, XtPointer);
174
 
static void PopdownIspell(Widget, XtPointer, XtPointer);
175
 
static void ReplaceIspell(Widget, XtPointer, XtPointer);
176
 
static void RevertIspell(Widget, XtPointer, XtPointer);
177
 
static void SelectIspell(Widget, XtPointer, XtPointer);
178
 
static void ToggleTerseIspell(Widget, XtPointer, XtPointer);
179
 
#ifndef SIGNALRETURNSINT
180
 
static void timeout_signal(int);
181
 
static void (*old_timeout)(int);
182
 
#else
183
 
static int timeout_signal(int);
184
 
static int (*old_timeout)(int);
185
 
#endif
186
 
static void UndoIspell(Widget, XtPointer, XtPointer);
187
 
 
188
 
Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
189
 
 
190
 
/*
191
 
 * Initialization
192
 
 */
193
 
static struct _ispell ispell;
194
 
 
195
 
#define RSTRTBLSZ       23
196
 
#define ISTRTBLSZ       71
197
 
static ReplaceList *replace_list[RSTRTBLSZ];
198
 
static IgnoreList *ignore_list[ISTRTBLSZ];
199
 
 
200
 
#ifndef XtCStatus
201
 
#define XtCStatus       "Status"
202
 
#endif
203
 
 
204
 
#define Offset(field) XtOffsetOf(struct _ispell, field)
205
 
static XtResource resources[] = {
206
 
    {"wordChars", "Chars", XtRString, sizeof(char*),
207
 
        Offset(wchars), XtRString, ""},
208
 
    {"ispellCommand", "CommandLine", XtRString, sizeof(char*),
209
 
        Offset(cmd), XtRString, "/usr/local/bin/ispell"},
210
 
    {"terseMode", "Terse", XtRBoolean, sizeof(Boolean),
211
 
        Offset(terse_mode), XtRImmediate, (XtPointer)False},
212
 
    {"guessLabel", XtCStatus, XtRString, sizeof(String),
213
 
        Offset(guess_label), XtRString, "Guess"},
214
 
    {"missLabel", XtCStatus, XtRString, sizeof(String),
215
 
        Offset(miss_label), XtRString, "Miss"},
216
 
    {"rootLabel", XtCStatus, XtRString, sizeof(String),
217
 
        Offset(root_label), XtRString, "Root:"},
218
 
    {"noneLabel", XtCStatus, XtRString, sizeof(String),
219
 
        Offset(none_label), XtRString, "None"},
220
 
    {"compoundLabel", XtCStatus, XtRString, sizeof(String),
221
 
        Offset(compound_label), XtRString, "Compound"},
222
 
    {"okLabel", XtCStatus, XtRString, sizeof(String),
223
 
        Offset(ok_label), XtRString, "Ok"},
224
 
    {"eofLabel", XtCStatus, XtRString, sizeof(String),
225
 
        Offset(eof_label), XtRString, "End Of File"},
226
 
    {"repeatLabel", XtCStatus, XtRString, sizeof(String),
227
 
        Offset(repeat_label), XtRString, "Repeat"},
228
 
    {"workingLabel", XtCStatus, XtRString, sizeof(String),
229
 
        Offset(working_label), XtRString, "..."},
230
 
    {"lookLabel", XtCStatus, XtRString, sizeof(String),
231
 
        Offset(look_label), XtRString, "Look"},
232
 
    {"lookCommand", "CommandLine", XtRString, sizeof(char*),
233
 
        Offset(look_cmd), XtRString, "/usr/bin/egrep -i"},
234
 
    {"wordsFile", "Words", XtRString, sizeof(char*),
235
 
        Offset(words_file), XtRString, "/usr/share/dict/words"},
236
 
    {"dictionary", "Dictionary", XtRString, sizeof(char*),
237
 
        Offset(dictionary), XtRString, "american"},
238
 
    {"dictionaries", "Dictionary", XtRString, sizeof(char*),
239
 
        Offset(dict_list), XtRString, "american americanmed+ english"},
240
 
    {"formatting", "TextFormat", XtRString, sizeof(char*),
241
 
        Offset(formatting), XtRString, "text"},
242
 
};
243
 
#undef Offset
244
 
 
245
 
#ifdef NO_LIBC_I18N
246
 
static int
247
 
ToLower(int ch)
248
 
{
249
 
    char buf[2];
250
 
 
251
 
    *buf = ch;
252
 
    XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
253
 
 
254
 
    return (*buf);
255
 
}
256
 
 
257
 
static int
258
 
ToUpper(int ch)
259
 
{
260
 
    char buf[2];
261
 
 
262
 
    *buf = ch;
263
 
    XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
264
 
 
265
 
    return (*buf);
266
 
}
267
 
 
268
 
static int
269
 
IsLower(int ch)
270
 
{
271
 
    char upbuf[2];
272
 
    char lobuf[2];
273
 
 
274
 
    *upbuf = *lobuf = ch;
275
 
    XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
276
 
    XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
277
 
 
278
 
    return (*lobuf != *upbuf && ch == *lobuf);
279
 
}
280
 
 
281
 
static int
282
 
IsUpper(int ch)
283
 
{
284
 
    char upbuf[2];
285
 
    char lobuf[2];
286
 
 
287
 
    *upbuf = *lobuf = ch;
288
 
    XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
289
 
    XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
290
 
 
291
 
    return (*lobuf != *upbuf && ch == *upbuf);
292
 
}
293
 
#else
294
 
#define ToLower tolower
295
 
#define ToUpper toupper
296
 
#define IsLower islower
297
 
#define IsUpper isupper
298
 
#endif
299
 
 
300
 
/*
301
 
 * Implementation
302
 
 */
303
 
#ifdef STDERR_FILENO
304
 
# define WRITES(s) write(STDERR_FILENO, s, strlen(s))
305
 
#else
306
 
# define WRITES(s) write(fileno(stderr), s, strlen(s))
307
 
#endif
308
 
 
309
 
/*ARGSUSED*/
310
 
#ifndef SIGNALRETURNSINT
311
 
static void
312
 
timeout_signal(int unused)
313
 
{
314
 
    int olderrno = errno;
315
 
 
316
 
    WRITES("Warning: Timeout waiting ispell process to die.\n");
317
 
    kill(ispell.pid, SIGTERM);
318
 
    errno = olderrno;
319
 
}
320
 
#else
321
 
static int
322
 
timeout_signal(int unused)
323
 
{
324
 
    int olderrno = errno;
325
 
 
326
 
    WRITES("Warning: Timeout waiting ispell process to die.\n");
327
 
    kill(ispell.pid, SIGTERM);
328
 
    
329
 
    errno = olderrno;
330
 
    return (0);
331
 
}
332
 
#endif
333
 
 
334
 
static void
335
 
IspellSetSelection(XawTextPosition left, XawTextPosition right)
336
 
{
337
 
    /* Try to make sure the selected word is completely visible */
338
 
    XawTextSetInsertionPoint(ispell.ascii, right);
339
 
    XawTextSetInsertionPoint(ispell.ascii, left);
340
 
    XawTextSetSelection(ispell.ascii, left, right);
341
 
}
342
 
 
343
 
static void
344
 
IspellSetStatus(char *label)
345
 
{
346
 
    Arg args[1];
347
 
 
348
 
    XtSetArg(args[0], XtNlabel, label);
349
 
    XtSetValues(ispell.status, args, 1);
350
 
}
351
 
 
352
 
static void
353
 
IspellSetRepeated(Bool state)
354
 
{
355
 
    static char *mispelled, *repeated;
356
 
    Arg args[1];
357
 
 
358
 
    if (mispelled == NULL) {
359
 
        XtSetArg(args[0], XtNlabel, &mispelled);
360
 
        XtGetValues(ispell.mispelled, args, 1);
361
 
        mispelled = XtNewString(mispelled);
362
 
    }
363
 
    if (repeated == NULL) {
364
 
        XtSetArg(args[0], XtNlabel, &repeated);
365
 
        XtGetValues(ispell.repeated, args, 1);
366
 
        repeated = XtNewString(repeated);
367
 
    }
368
 
    XtSetSensitive(ispell.replaceAll, !state);
369
 
    XtSetSensitive(ispell.ignoreAll, !state);
370
 
    XtSetSensitive(ispell.add, !state);
371
 
    XtSetSensitive(ispell.addUncap, !state);
372
 
    if (!state) {
373
 
        XtSetArg(args[0], XtNlabel, mispelled);
374
 
        XtSetValues(ispell.mispelled, args, 1);
375
 
    }
376
 
    else {
377
 
        XtSetArg(args[0], XtNlabel, repeated);
378
 
        XtSetValues(ispell.mispelled, args, 1);
379
 
    }
380
 
}
381
 
 
382
 
static void
383
 
IspellSetSensitive(Bool state)
384
 
{
385
 
    XtSetSensitive(ispell.replace, state);
386
 
    XtSetSensitive(ispell.replaceAll, state);
387
 
    XtSetSensitive(ispell.ignore, state);
388
 
    XtSetSensitive(ispell.ignoreAll, state);
389
 
    XtSetSensitive(ispell.add, state);
390
 
    XtSetSensitive(ispell.addUncap, state);
391
 
}
392
 
 
393
 
static void
394
 
IspellSetTerseMode(Bool mode)
395
 
{
396
 
    Arg args[1];
397
 
 
398
 
    XtSetArg(args[0], XtNstate, ispell.terse_mode = mode);
399
 
    XtSetValues(ispell.terse, args, 1);
400
 
    write(ispell.ofd[1], mode ? "!\n" : "%\n", 2);
401
 
}
402
 
 
403
 
static void
404
 
IspellCheckUndo(void)
405
 
{
406
 
    ispell_undo *undo = XtNew(ispell_undo);
407
 
 
408
 
    if (ispell.undo_for && strcmp(ispell.undo_for, ispell.dictionary)) {
409
 
        XeditPrintf("Undo: Dictionary changed. Previous undo information lost.\n");
410
 
        IspellKillUndoBuffer();
411
 
        Feep();
412
 
    }
413
 
 
414
 
    undo->next = NULL;
415
 
    undo->repeat = False;
416
 
    undo->terse = ispell.undo_terse_mode;
417
 
    undo->format = ispell.format_mode;
418
 
    if ((undo->prev = ispell.undo_head) != NULL)
419
 
        undo->prev->next = undo;
420
 
    else
421
 
        undo->prev = NULL;
422
 
    ++ispell.undo_depth;
423
 
    if (!ispell.undo_base) {
424
 
        ispell.undo_base = undo;
425
 
        XtSetSensitive(ispell.undo, True);
426
 
    }
427
 
    else if (ispell.undo_depth > UNDO_DEPTH) {
428
 
        ispell_undo *tmp;
429
 
 
430
 
        if (ispell.undo_base->undo_str)
431
 
            XtFree(ispell.undo_base->undo_str);
432
 
        tmp = ispell.undo_base->next;
433
 
        XtFree((char*)ispell.undo_base);
434
 
        tmp->prev = NULL;
435
 
        ispell.undo_base = tmp;
436
 
        ispell.undo_depth = UNDO_DEPTH;
437
 
    }
438
 
    ispell.undo_head = undo;
439
 
}
440
 
 
441
 
static char *
442
 
IspellReplacedWord(char *word, char *replace)
443
 
{
444
 
    ReplaceList *list;
445
 
    int ii = 0;
446
 
    char *pp = word;
447
 
 
448
 
    while (*pp)
449
 
        ii = (ii << 1) ^ *pp++;
450
 
    if (ii < 0)
451
 
        ii = -ii;
452
 
    ii %= RSTRTBLSZ;
453
 
    for (list = replace_list[ii]; list; list = list->next)
454
 
        if (strcmp(list->word, word) == 0) {
455
 
            if (replace) {
456
 
                XtFree(list->replace);
457
 
                list->replace = XtNewString(replace);
458
 
            }
459
 
            return (list->replace);
460
 
        }
461
 
 
462
 
    if (!replace)
463
 
        return (NULL);
464
 
 
465
 
    list = XtNew(ReplaceList);
466
 
    list->word = XtNewString(word);
467
 
    list->replace = XtNewString(replace);
468
 
    list->next = replace_list[ii];
469
 
    replace_list[ii] = list;
470
 
 
471
 
    return (list->replace);
472
 
}
473
 
 
474
 
static Bool
475
 
IspellDoIgnoredWord(char *word, int cmd, int add)
476
 
{
477
 
    IgnoreList *list, *prev;
478
 
    int ii = 0;
479
 
    char *pp = word;
480
 
 
481
 
    while (*pp)
482
 
        ii = (ii << 1) ^ *pp++;
483
 
    if (ii < 0)
484
 
        ii = -ii;
485
 
    ii %= ISTRTBLSZ;
486
 
    for (prev = list = ignore_list[ii]; list; prev = list, list = list->next)
487
 
        if (strcmp(list->word, word) == 0) {
488
 
            if (cmd == REMOVE) {
489
 
                XtFree(list->word);
490
 
                prev->next = list->next;
491
 
                XtFree((char*)list);
492
 
                if (prev == list)
493
 
                    ignore_list[ii] = NULL;
494
 
                return (True);
495
 
            }
496
 
            return (cmd == CHECK);
497
 
        }
498
 
 
499
 
    if (cmd != ADD)
500
 
        return (False);
501
 
 
502
 
    list = XtNew(IgnoreList);
503
 
    list->word = XtNewString(word);
504
 
    list->add = add;
505
 
    list->next = ignore_list[ii];
506
 
    ignore_list[ii] = list;
507
 
 
508
 
    return (True);
509
 
}
510
 
 
511
 
static Bool
512
 
IspellIgnoredWord(char *word, int cmd, int add)
513
 
{
514
 
    if (add != UNCAP && IspellDoIgnoredWord(word, cmd, add))
515
 
        return (True);
516
 
 
517
 
    /* add/remove uncapped word to/of list,
518
 
     * or cheks for correct capitalization */
519
 
    if (add == UNCAP || cmd == CHECK) {
520
 
        unsigned char *str = (unsigned char*)word;
521
 
        unsigned char string[1024];
522
 
        Bool upper, status;
523
 
        int i;
524
 
 
525
 
        status = True;
526
 
        upper = IsUpper(*str);
527
 
        *string = upper ? ToLower(*str) : *str;
528
 
        if (*str)
529
 
            str++;
530
 
        if (IsLower(*str))
531
 
            upper = False;
532
 
        for (i = 1; *str && i < sizeof(string) - 1; i++, str++) {
533
 
            if (upper && IsLower(*str))
534
 
                status = False;
535
 
            else if (!upper && IsUpper(*str))
536
 
                status = False;
537
 
            string[i] = ToLower(*str);
538
 
        }
539
 
        string[i] = '\0';
540
 
 
541
 
        if ((cmd != CHECK || status) &&
542
 
            IspellDoIgnoredWord((char*)string, cmd, add))
543
 
            return (True);
544
 
    }
545
 
 
546
 
    return (False);
547
 
}
548
 
 
549
 
/*ARGSUSED*/
550
 
static Bool
551
 
IspellReceive(void)
552
 
{
553
 
    int i, len, old_len;
554
 
    Arg args[2];
555
 
    char *str, *end, **list, **old_list;
556
 
    char *tmp, word[1024];
557
 
    int j;
558
 
 
559
 
    if (ispell.lock || ispell.stat != RECEIVE)
560
 
        return (False);
561
 
 
562
 
    while (1) {         /* read the entire line */
563
 
        if (ispell.buflen >= ispell.bufsiz - 1)
564
 
            ispell.buf = XtRealloc(ispell.buf, ispell.bufsiz += BUFSIZ);
565
 
        if ((len = read(ispell.ifd[0], &ispell.buf[ispell.buflen],
566
 
                        ispell.bufsiz - ispell.buflen - 1)) <= 0)
567
 
            break;
568
 
        ispell.buflen += len;
569
 
    }
570
 
    if (ispell.buflen <= 0)
571
 
        return (False);
572
 
    len = 0;
573
 
    i = ispell.buflen - 1;
574
 
    while (i >= 0 && ispell.buf[i] == '\n') {
575
 
        ++len;
576
 
        --i;
577
 
    }
578
 
    if (len < 2 - ((ispell.terse_mode && i == -1) || ispell.buf[0] == '@'))
579
 
        return (False);
580
 
    ispell.buf[ispell.buflen - len] = '\0';
581
 
    ispell.buflen = 0;
582
 
 
583
 
    if ((tmp = strchr(ispell.sendbuf, '\n')) != NULL)
584
 
        *tmp = '\0';
585
 
 
586
 
    switch (ispell.buf[0]) {
587
 
        case '&':       /* MISS */
588
 
        case '?':       /* GUESS */
589
 
            str = strchr(&ispell.buf[2], ' ');
590
 
            if (!ispell.checkit) {
591
 
                *str = '\0';
592
 
                XtSetArg(args[0], XtNlabel, &ispell.buf[2]);
593
 
                XtSetValues(ispell.word, args, 1);
594
 
            }
595
 
            ++str;
596
 
            list = NULL;
597
 
            str = strchr(str, ':') + 1;
598
 
            for (i = 0; ; i++) {
599
 
                end = strchr(str, ',');
600
 
                if (end)        *end = '\0';
601
 
                if ((i % 16) == 0)
602
 
                    list = (char**)XtRealloc((char*)list, (i + 16) * sizeof(char*));
603
 
                tmp = word;
604
 
                for (j = 1; j < sizeof(word) && str[j]; j++) {
605
 
                    if (str[j] == '+')
606
 
                        continue;
607
 
                    else if (str[j] == '-' && str[j+1] != '-' && str[j-1] != '-') {
608
 
                        char *p, string[256];
609
 
                        int k, l;
610
 
 
611
 
                        for (l = 0, k = j + 1; str[k] != '+' && str[k] != '-'
612
 
                             && str[k] && l < sizeof(string) - 1; k++, l++)
613
 
                            string[l] = str[k];
614
 
                        string[l] = '\0';
615
 
                        *tmp = '\0';
616
 
                        if (l && (p = strstr(word, string)) != NULL) {
617
 
                            char *sav = p;
618
 
 
619
 
                            while ((p = strstr(p + l, string)) != NULL)
620
 
                                sav = p;
621
 
                            p = sav;
622
 
                            if (strcmp(p, string) == 0) {
623
 
                                tmp = p;
624
 
                                j = k - 1;
625
 
                            }
626
 
                            else
627
 
                                *tmp++ = '-';
628
 
                        }
629
 
                        else
630
 
                            *tmp++ = '-';
631
 
                    }
632
 
                    else
633
 
                        *tmp++ = str[j];
634
 
                }
635
 
                *tmp = '\0';
636
 
                list[i] = XtNewString(word);
637
 
 
638
 
                if (end)        str = end + 1;
639
 
                else            break;
640
 
            }
641
 
            len = i + 1;
642
 
 
643
 
            XtSetArg(args[0], XtNlist, &old_list);
644
 
            XtSetArg(args[1], XtNnumberStrings, &old_len);
645
 
            XtGetValues(ispell.list, args, 2);
646
 
 
647
 
            ispell.item = NULL;
648
 
            if ((str = IspellReplacedWord(&ispell.buf[2], NULL)) != NULL)
649
 
                for (i = 0; i < len; i++) {
650
 
                    if (strcmp(list[i], str) == 0) {
651
 
                        ispell.item = list[i];
652
 
                        break;
653
 
                    }
654
 
                }
655
 
            else
656
 
                ispell.item = list[i = 0];
657
 
            if (!ispell.item) {
658
 
                list = (char**)XtRealloc((char*)list, (len + 1) * sizeof(char*));
659
 
                ispell.item = list[i] = XtNewString(str);
660
 
                ++len;
661
 
            }
662
 
 
663
 
            XtSetArg(args[0], XtNlist, list);
664
 
            XtSetArg(args[1], XtNnumberStrings, len);
665
 
            XtSetValues(ispell.list, args, 2);
666
 
 
667
 
            XtSetSensitive(ispell.list, True);
668
 
            if (!ispell.checkit)
669
 
                XawListHighlight(ispell.list, i);
670
 
 
671
 
            if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
672
 
                while (--old_len > -1)
673
 
                    XtFree(old_list[old_len]);
674
 
                XtFree((char*)old_list);
675
 
            }
676
 
 
677
 
            if (!ispell.checkit) {
678
 
                XtSetArg(args[0], XtNstring, ispell.item);
679
 
                XtSetValues(ispell.text, args, 1);
680
 
                IspellSetSelection(ispell.left, ispell.right);
681
 
                if (ispell.repeat)
682
 
                    IspellSetRepeated(ispell.repeat = False);
683
 
            }
684
 
 
685
 
            IspellSetStatus(ispell.buf[0] == '?' ?
686
 
                            ispell.guess_label : ispell.miss_label);
687
 
            ispell.undo_terse_mode = ispell.terse_mode;
688
 
            ispell.format_mode = ispell.format_info->value;
689
 
            ispell.lock = True;
690
 
            break;
691
 
        case '#':       /* NONE */
692
 
        case '-':       /* COMPOUND */
693
 
        case '+':       /* ROOT */
694
 
        check_label:
695
 
            str = &ispell.sendbuf[1];
696
 
            if (!ispell.checkit) {
697
 
                XtSetArg(args[0], XtNlabel, str);
698
 
                XtSetValues(ispell.word, args, 1);
699
 
            }
700
 
 
701
 
            XtSetArg(args[0], XtNlist, &old_list);
702
 
            XtSetArg(args[1], XtNnumberStrings, &old_len);
703
 
            XtGetValues(ispell.list, args, 2);
704
 
            ispell.item = NULL;
705
 
 
706
 
            list = (char**)XtMalloc(sizeof(char**));
707
 
            if ((tmp = IspellReplacedWord(str, NULL)) != NULL)
708
 
                str = tmp;
709
 
            if (tmp == NULL && ispell.buf[0] == '#')
710
 
                list[0] = XtNewString("");
711
 
            else
712
 
                list[0] = XtNewString(str);
713
 
 
714
 
            XtSetArg(args[0], XtNlist, list);
715
 
            XtSetArg(args[1], XtNnumberStrings, 1);
716
 
            XtSetValues(ispell.list, args, 2);
717
 
 
718
 
            if (tmp == NULL && ispell.buf[0] == '#') {
719
 
                XawListUnhighlight(ispell.list);
720
 
                XtSetSensitive(ispell.list, False);
721
 
            }
722
 
            else {
723
 
                XtSetSensitive(ispell.list, True);
724
 
                if (!ispell.checkit)
725
 
                    XawListHighlight(ispell.list, 0);
726
 
            }
727
 
            if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
728
 
                while (--old_len > -1)
729
 
                    XtFree(old_list[old_len]);
730
 
                XtFree((char*)old_list);
731
 
            }
732
 
 
733
 
            if (!ispell.checkit) {
734
 
                XtSetArg(args[0], XtNstring, str);
735
 
                XtSetValues(ispell.text, args, 1);
736
 
                IspellSetSelection(ispell.left, ispell.right);
737
 
                if (ispell.repeat)
738
 
                    IspellSetRepeated(ispell.repeat = False);
739
 
            }
740
 
 
741
 
            ispell.undo_terse_mode = ispell.terse_mode;
742
 
            ispell.format_mode = ispell.format_info->value;
743
 
            ispell.lock = True;
744
 
            if (ispell.buf[0] == '+') {
745
 
                if ((tmp = strchr(&ispell.buf[2], '\n')) != NULL)
746
 
                    *tmp = '\0';
747
 
                XmuSnprintf(word, sizeof(word), "%s %s",
748
 
                            ispell.root_label, &ispell.buf[2]);
749
 
                IspellSetStatus(word);
750
 
            }
751
 
            else
752
 
                IspellSetStatus(ispell.buf[0] == '#' ? ispell.none_label :
753
 
                                ispell.buf[0] == '-' ? ispell.compound_label :
754
 
                                ispell.ok_label);
755
 
            break;
756
 
        case '*':       /* OK */
757
 
        case '\0':      /* when running in terse mode */
758
 
            if (!ispell.checkit)
759
 
                (void)IspellIgnoredWord(&ispell.sendbuf[1], ADD, 0);
760
 
            else
761
 
                goto check_label;
762
 
            ispell.lock = False;
763
 
            break;
764
 
        case '@':       /* Ispell banner */
765
 
            /* it only happens when the dictionary is changed */
766
 
            if (!ispell.repeat) {
767
 
                XawTextPosition left, right;
768
 
 
769
 
                ispell.stat = SEND;
770
 
                while (IspellSend() == 0)
771
 
                    ;
772
 
                /* word chars may have changed */
773
 
                XawTextGetSelectionPos(ispell.ascii, &left, &right);
774
 
                if (left != ispell.left || right != ispell.right) {
775
 
                    XtSetArg(args[0], XtNstring, &ispell.sendbuf[1]);
776
 
                    XtSetValues(ispell.text, args, 1);
777
 
                    IspellSetSelection(ispell.left, ispell.right);
778
 
                }
779
 
                ispell.checkit = True;
780
 
            }
781
 
            else {
782
 
                IspellSetStatus(ispell.repeat_label);
783
 
                ispell.undo_terse_mode = ispell.terse_mode;
784
 
                ispell.format_mode = ispell.format_info->value;
785
 
                ispell.lock = True;
786
 
                return (True);
787
 
            }
788
 
            break;
789
 
        default:
790
 
            fprintf(stderr, "Unknown ispell command '%c'\n", ispell.buf[0]);
791
 
            return (False);
792
 
    }
793
 
 
794
 
    if (!ispell.lock && !ispell.checkit) {
795
 
        ispell.stat = SEND;
796
 
        while (IspellSend() == 0)
797
 
            ;
798
 
    }
799
 
 
800
 
    return (True);
801
 
}
802
 
 
803
 
static int
804
 
IspellConvertHtmlAmp(char *buf)
805
 
{
806
 
    int len, ch = '?';
807
 
 
808
 
    /* this function is static, so I can do it */
809
 
    *strchr(++buf, ';') = '\0';
810
 
 
811
 
    len = strlen(buf);
812
 
    if (len == 0)
813
 
        return ('&');
814
 
    if (len > 1) {
815
 
        if (strcasecmp(&buf[1], "lt") == 0)
816
 
            ch = '<';
817
 
        else if (strcasecmp(&buf[1], "gt") == 0)
818
 
            ch = '>';
819
 
        else if (strcasecmp(&buf[1], "nbsp") == 0)
820
 
            ch = ' ';
821
 
        else if (strcasecmp(&buf[1], "amp") == 0)
822
 
            ch = '&';
823
 
        else if (strcasecmp(&buf[1], "quot") == 0)
824
 
            ch = '"';
825
 
        else if (*buf == '#') {
826
 
            char *tmp;
827
 
 
828
 
            if (len == 1)
829
 
                return ('?');
830
 
            ch = strtol(&buf[1], &tmp, 10);
831
 
            if (*tmp)
832
 
                fprintf(stderr, "Warning: bad html interpreting '&#' mark.\n");
833
 
        }
834
 
        else if (strcmp(&buf[1], "acute") == 0) {
835
 
            switch (*buf) {
836
 
                case 'a': ch = 0xe1; break;
837
 
                case 'e': ch = 0xe9; break;
838
 
                case 'i': ch = 0xed; break;
839
 
                case 'o': ch = 0xf3; break;
840
 
                case 'u': ch = 0xfa; break;
841
 
                case 'A': ch = 0xc1; break;
842
 
                case 'E': ch = 0xc9; break;
843
 
                case 'I': ch = 0xcd; break;
844
 
                case 'O': ch = 0xd3; break;
845
 
                case 'U': ch = 0xda; break;
846
 
            }
847
 
        }
848
 
        else if (strcmp(&buf[1], "grave") == 0) {
849
 
            switch (*buf) {
850
 
                case 'a': ch = 0xe0; break;
851
 
                case 'e': ch = 0xe8; break;
852
 
                case 'i': ch = 0xec; break;
853
 
                case 'o': ch = 0xf2; break;
854
 
                case 'u': ch = 0xf9; break;
855
 
                case 'A': ch = 0xc0; break;
856
 
                case 'E': ch = 0xc8; break;
857
 
                case 'I': ch = 0xcc; break;
858
 
                case 'O': ch = 0xd2; break;
859
 
                case 'U': ch = 0xd9; break;
860
 
            }
861
 
        }
862
 
        else if (strcmp(&buf[1], "tilde") == 0) {
863
 
            switch (*buf) {
864
 
                case 'a': ch = 0xe3; break;
865
 
                case 'o': ch = 0xf5; break;
866
 
                case 'n': ch = 0xf1; break;
867
 
                case 'A': ch = 0xe3; break;
868
 
                case 'O': ch = 0xd5; break;
869
 
                case 'N': ch = 0xd1; break;
870
 
            }
871
 
        }
872
 
        else if (strcmp(&buf[1], "circ") == 0) {
873
 
            switch (*buf) {
874
 
                case 'a': ch = 0xe2; break;
875
 
                case 'e': ch = 0xea; break;
876
 
                case 'i': ch = 0xee; break;
877
 
                case 'o': ch = 0xf4; break;
878
 
                case 'u': ch = 0xfb; break;
879
 
                case 'A': ch = 0xc2; break;
880
 
                case 'E': ch = 0xca; break;
881
 
                case 'I': ch = 0xce; break;
882
 
                case 'O': ch = 0xd4; break;
883
 
                case 'U': ch = 0xdb; break;
884
 
            }
885
 
        }
886
 
        else if (strcmp(&buf[1], "cedil") == 0) {
887
 
            switch (*buf) {
888
 
                case 'c': ch = 0xe7; break;
889
 
                case 'C': ch = 0xc7; break;
890
 
            }
891
 
        }
892
 
        /* add more cases here */
893
 
    }
894
 
 
895
 
    return (ch);
896
 
}
897
 
 
898
 
/*ARGSUSED*/
899
 
static int
900
 
IspellSend(void)
901
 
{
902
 
    XawTextPosition position, old_left, pos;
903
 
    XawTextBlock block;
904
 
    int i, len, spaces, nls;
905
 
    Bool nl, html, inside_html;
906
 
    char ampbuf[32];
907
 
    int amplen;
908
 
 
909
 
    if (ispell.lock || ispell.stat != SEND)
910
 
        return (-1);
911
 
 
912
 
    len = 1;
913
 
    ispell.sendbuf[0] = '^';    /* don't evaluate following characters as commands */
914
 
 
915
 
    spaces = nls = 0;
916
 
 
917
 
    html = ispell.format_info->value == HTML;
918
 
    inside_html = False;
919
 
    amplen = 0;
920
 
 
921
 
    /* skip non word characters */
922
 
    pos = position = ispell.right;
923
 
    nl = False;
924
 
    while (1) {
925
 
        Bool done = False;
926
 
        char mb[sizeof(wchar_t)];
927
 
 
928
 
        retry_html_space:
929
 
        position = XawTextSourceRead(ispell.source, position,
930
 
                                     &block, BUFSIZ);
931
 
        if (block.length == 0) {        /* end of file */
932
 
            ispell.stat = 0;
933
 
            ispell.lock = True;
934
 
            XawTextSetInsertionPoint(ispell.ascii, ispell.right);
935
 
            XawTextUnsetSelection(ispell.ascii);
936
 
            IspellSetSensitive(False);
937
 
            IspellSetStatus(ispell.eof_label);
938
 
            return (-1);
939
 
        }
940
 
        for (i = 0; i < block.length; i++) {
941
 
            wctomb(mb, ((wchar_t*)block.ptr)[i]);
942
 
            if (amplen) {
943
 
                if (amplen + 2 >= sizeof(ampbuf)) {
944
 
                    if (!ispell.terse_mode)
945
 
                        fprintf(stderr, "Warning: error interpreting '&' mark.\n");
946
 
                    amplen = 0;
947
 
                    position = pos + 1;
948
 
                    goto retry_html_space;
949
 
                }
950
 
                else if ((ampbuf[amplen++] = *mb) == ';') {
951
 
                    int ch;
952
 
 
953
 
                    ampbuf[amplen] = '\0';
954
 
                    ch = IspellConvertHtmlAmp(ampbuf);
955
 
                    amplen = 0;
956
 
                    if (isalpha(ch) ||
957
 
                        (ch && strchr(ispell.wchars, ch))) {
958
 
                        /* interpret it again */
959
 
                        ispell.right = pos;
960
 
                        i = 0;
961
 
                        done = True;
962
 
                        break;
963
 
                    }
964
 
                    else if ((ch == '\n' || isspace(ch)) && spaces >= 0)
965
 
                        ++spaces;
966
 
                    else
967
 
                        spaces = -1;
968
 
                }
969
 
            }
970
 
            else if (html && *mb == '&') {
971
 
                ampbuf[amplen++] = *mb;
972
 
                pos = block.firstPos + i;
973
 
                continue;
974
 
            }
975
 
            else if ((!html || !inside_html) && (isalpha(*mb) ||
976
 
                (*mb && strchr(ispell.wchars, *mb)))) {
977
 
                done = True;
978
 
                break;
979
 
            }
980
 
            else if (!html && *mb == '\n') {
981
 
                nl = True;
982
 
                if (++nls > 1 && (!html || !inside_html))
983
 
                    spaces = -1;
984
 
                else if (spaces >= 0)
985
 
                    ++spaces;
986
 
            }
987
 
            else if (nl) {
988
 
                nl = False;
989
 
                if (*mb && strchr(ispell.skip, *mb)) {
990
 
                    position = ispell.right =
991
 
                        XawTextSourceScan(ispell.source, ispell.right + i,
992
 
                                          XawstEOL, XawsdRight, 1, False);
993
 
                    i = 0;
994
 
                    break;
995
 
                }
996
 
                else if (spaces >= 0 && isspace(*mb))
997
 
                    ++spaces;
998
 
                else
999
 
                    spaces = -1;
1000
 
            }
1001
 
            else if (html && inside_html) {
1002
 
                if (*mb == '>')
1003
 
                    inside_html = False;
1004
 
            }
1005
 
            else if (html && *mb == '<')
1006
 
                inside_html = True;
1007
 
            else if (spaces >= 0 && (isspace(*mb) || (html && *mb == '\n')))
1008
 
                ++spaces;
1009
 
            else
1010
 
                spaces = -1;
1011
 
        }
1012
 
 
1013
 
        ispell.right += i;
1014
 
        if (done)
1015
 
            break;
1016
 
    }
1017
 
 
1018
 
    old_left = ispell.left;
1019
 
 
1020
 
    /* read a word */
1021
 
    position = ispell.left = ispell.right;
1022
 
    while (1) {
1023
 
        Bool done = False;
1024
 
        char mb[sizeof(wchar_t)];
1025
 
 
1026
 
        retry_html_word:
1027
 
        position = XawTextSourceRead(ispell.source, position,
1028
 
                                     &block, BUFSIZ);
1029
 
        if (block.length == 0 && len == 1) {    /* end of file */
1030
 
            ispell.stat = 0;
1031
 
            ispell.lock = True;
1032
 
            XawTextSetInsertionPoint(ispell.ascii, ispell.right);
1033
 
            XawTextUnsetSelection(ispell.ascii);
1034
 
            IspellSetSensitive(False);
1035
 
            IspellSetStatus(ispell.eof_label);
1036
 
            return (-1);
1037
 
        }
1038
 
        for (i = 0; i < block.length; i++) {
1039
 
            wctomb(mb, ((wchar_t*)block.ptr)[i]);
1040
 
            if (amplen) {
1041
 
                if (amplen + 2 >= sizeof(ampbuf)) {
1042
 
                    if (!ispell.terse_mode)
1043
 
                        fprintf(stderr, "Warning: error interpreting '&' mark.\n");
1044
 
                    amplen = 0;
1045
 
                    position = pos + 1;
1046
 
                    if (strchr(ispell.wchars, '&')) {
1047
 
                        if (len + 1 >= sizeof(ispell.sendbuf) - 1) {
1048
 
                            done = True;
1049
 
                            fprintf(stderr, "Warning: word is too large!\n");
1050
 
                            break;
1051
 
                        }
1052
 
                        ispell.sendbuf[len++] = '&';
1053
 
                        goto retry_html_word;
1054
 
                    }
1055
 
                    else {
1056
 
                        ispell.right = position;
1057
 
                        i = 0;
1058
 
                        done = True;
1059
 
                        break;
1060
 
                    }
1061
 
                }
1062
 
                else if ((ampbuf[amplen++] = *mb) == ';') {
1063
 
                    int ch;
1064
 
 
1065
 
                    ampbuf[amplen] = '\0';
1066
 
                    ch = IspellConvertHtmlAmp(ampbuf);
1067
 
                    amplen = 0;
1068
 
                    if (!isalpha(ch) &&
1069
 
                        (!ch || !strchr(ispell.wchars, ch))) {
1070
 
                        ispell.right = pos;
1071
 
                        i = 0;
1072
 
                        done = True;
1073
 
                        break;
1074
 
                    }
1075
 
                    *mb = ch;
1076
 
                }
1077
 
                else
1078
 
                    continue;
1079
 
            }
1080
 
            else if (html && *mb == '&') {
1081
 
                ampbuf[amplen++] = *mb;
1082
 
                pos = block.firstPos + i;
1083
 
                continue;
1084
 
            }
1085
 
            else if (!isalpha(*mb) && (!*mb || !strchr(ispell.wchars, *mb))) {
1086
 
                done = True;
1087
 
                break;
1088
 
            }
1089
 
            ispell.sendbuf[len] = *mb;
1090
 
            if (++len >= sizeof(ispell.sendbuf) - 1) {
1091
 
                done = True;
1092
 
                fprintf(stderr, "Warning: word is too large!\n");
1093
 
                break;
1094
 
            }
1095
 
        }
1096
 
        ispell.right += i;
1097
 
        if (done || block.length == 0)
1098
 
            break;
1099
 
    }
1100
 
 
1101
 
    ispell.sendbuf[len] = '\0';
1102
 
 
1103
 
    if (spaces > 0 && spaces <= 32 && strcmp(ispell.sendbuf, ispell.sentbuf) == 0) {
1104
 
        Arg args[2];
1105
 
        int old_len;    
1106
 
        char **list, **old_list;
1107
 
        char label[sizeof(ispell.sendbuf) + sizeof(ispell.sentbuf) + 32];
1108
 
 
1109
 
        strcpy(label, &ispell.sendbuf[1]);
1110
 
        for (i = 0; i < spaces; i++)
1111
 
            label[len + i - 1] = ' ';
1112
 
        strcpy(&label[len + i - 1], &ispell.sendbuf[1]);
1113
 
        XtSetArg(args[0], XtNlabel, label);
1114
 
        XtSetValues(ispell.word, args, 1);
1115
 
 
1116
 
        XtSetArg(args[0], XtNstring, &ispell.sendbuf[1]);
1117
 
        XtSetValues(ispell.text, args, 1);
1118
 
 
1119
 
        XtSetArg(args[0], XtNlist, &old_list);
1120
 
        XtSetArg(args[1], XtNnumberStrings, &old_len);
1121
 
        XtGetValues(ispell.list, args, 2);
1122
 
        list = (char**)XtMalloc(sizeof(char**));
1123
 
        list[0] = XtNewString(&ispell.sendbuf[1]);
1124
 
        XtSetArg(args[0], XtNlist, list);
1125
 
        XtSetArg(args[1], XtNnumberStrings, 1);
1126
 
        XtSetValues(ispell.list, args, 2);
1127
 
        XtSetSensitive(ispell.list, True);
1128
 
        XawListHighlight(ispell.list, 0);
1129
 
        if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
1130
 
            while (--old_len > -1)
1131
 
                XtFree(old_list[old_len]);
1132
 
            XtFree((char*)old_list);
1133
 
        }
1134
 
 
1135
 
        IspellSetRepeated(True);
1136
 
        IspellSetSelection(old_left, ispell.right);
1137
 
        IspellSetStatus(ispell.repeat_label);
1138
 
        ispell.repeat = ispell.lock = True;
1139
 
 
1140
 
        return (1);
1141
 
    }
1142
 
    strcpy(ispell.sentbuf, ispell.sendbuf);
1143
 
 
1144
 
    if (len <= 2 || IspellIgnoredWord(&ispell.sendbuf[1], CHECK, 0))
1145
 
        return (0);
1146
 
 
1147
 
    ispell.sendbuf[len++] = '\n';
1148
 
 
1149
 
    write(ispell.ofd[1], ispell.sendbuf, len);
1150
 
 
1151
 
    ispell.stat = RECEIVE;
1152
 
 
1153
 
    return (1);
1154
 
}
1155
 
 
1156
 
/*ARGSUSED*/
1157
 
static void
1158
 
IspellInputCallback(XtPointer closure, int *source, XtInputId *id)
1159
 
{
1160
 
    if (ispell.right < 0) {
1161
 
        int len;
1162
 
        char buf[1024];
1163
 
 
1164
 
        ispell.right = XawTextGetInsertionPoint(ispell.ascii);
1165
 
        ispell.right = XawTextSourceScan(ispell.source, ispell.right,
1166
 
                                              XawstEOL, XawsdLeft, 1, True);
1167
 
        len = read(ispell.ifd[0], buf, sizeof(buf));
1168
 
        if (strncmp(buf, "@(#)", 4) == 0) {
1169
 
            Arg args[1];
1170
 
 
1171
 
            buf[len - 1] = '\0';
1172
 
            XtSetArg(args[0], XtNtitle, &buf[5]);
1173
 
            XtSetValues(ispell.shell, args, 1);
1174
 
        }
1175
 
        else
1176
 
            fprintf(stderr, "Error: is ispell talking with me?\n");
1177
 
        IspellSetTerseMode(ispell.terse_mode);
1178
 
        while (IspellSend() == 0)
1179
 
            ;
1180
 
    }
1181
 
    else if (ispell.source)
1182
 
        IspellReceive();
1183
 
}
1184
 
 
1185
 
/*ARGSUSED*/
1186
 
void
1187
 
IspellCallback(Widget w, XtPointer client_data, XtPointer call_data)
1188
 
{
1189
 
    Cardinal zero = 0;
1190
 
 
1191
 
    IspellAction(textwindow, NULL, NULL, &zero);
1192
 
}
1193
 
 
1194
 
/*ARGSUSED*/
1195
 
void
1196
 
IspellAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
1197
 
{
1198
 
    Arg args[3];
1199
 
    Cardinal num_args;
1200
 
    char **strs, **list;
1201
 
    int n_strs;
1202
 
    Bool first_time = InitIspell();
1203
 
 
1204
 
    if (*num_params == 1 && (params[0][0] == 'e' || params[0][0] == 'E')) {
1205
 
        PopdownIspell(w, (XtPointer)True, NULL);
1206
 
        return;
1207
 
    }
1208
 
 
1209
 
    if (!XtIsSubclass(w, textWidgetClass) || ispell.source) {
1210
 
        Feep();
1211
 
        return;
1212
 
    }
1213
 
 
1214
 
    ispell.source = XawTextGetSource(ispell.ascii = w);
1215
 
 
1216
 
    if (first_time) {
1217
 
        /* let the user choose the better position for the ispell window */
1218
 
        Dimension width, height, b_width;
1219
 
        Position x, y, max_x, max_y;
1220
 
 
1221
 
        x = y = -1;
1222
 
        if (event) {
1223
 
            switch (event->type) {
1224
 
                case ButtonPress:
1225
 
                case ButtonRelease:
1226
 
                    x = event->xbutton.x_root;
1227
 
                    y = event->xbutton.y_root;
1228
 
                    break;
1229
 
                case KeyPress:
1230
 
                case KeyRelease:
1231
 
                    x = event->xkey.x_root;
1232
 
                    y = event->xkey.y_root;
1233
 
                    break;
1234
 
            }
1235
 
        }
1236
 
        if (x < 0 || y < 0) {
1237
 
            Window r, c;
1238
 
            int rx, ry, wx, wy;
1239
 
            unsigned mask;
1240
 
 
1241
 
            XQueryPointer(XtDisplay(ispell.shell), XtWindow(ispell.shell),
1242
 
                          &r, &c, &rx, &ry, &wx, &wy, &mask);
1243
 
            x = rx;
1244
 
            y = ry;
1245
 
        }
1246
 
 
1247
 
        num_args = 0;
1248
 
        XtSetArg(args[num_args], XtNwidth, &width);             num_args++;
1249
 
        XtSetArg(args[num_args], XtNheight, &height);           num_args++;
1250
 
        XtSetArg(args[num_args], XtNborderWidth, &b_width);     num_args++;
1251
 
        XtGetValues(ispell.shell, args, num_args);
1252
 
 
1253
 
        width += b_width << 1;
1254
 
        height += b_width << 1;
1255
 
 
1256
 
        x -= (Position)(width >> 1);
1257
 
        if (x < 0)
1258
 
            x = 0;
1259
 
        if (x > (max_x = (Position)(XtScreen(w)->width - width)))
1260
 
            x = max_x;
1261
 
 
1262
 
        y -= (Position)(height >> 1);
1263
 
        if (y < 0)
1264
 
            y = 0;
1265
 
        if (y > (max_y = (Position)(XtScreen(w)->height - height)))
1266
 
            y = max_y;
1267
 
 
1268
 
        num_args = 0;
1269
 
        XtSetArg(args[num_args], XtNx, x);      num_args++;
1270
 
        XtSetArg(args[num_args], XtNy, y);      num_args++;
1271
 
        XtSetValues(ispell.shell, args, num_args);
1272
 
    }
1273
 
 
1274
 
    if (ispell.repeat)
1275
 
        IspellSetRepeated(False);
1276
 
    ispell.lock = ispell.repeat = ispell.checkit = False;
1277
 
    ispell.stat = SEND;
1278
 
 
1279
 
    IspellSetSensitive(True);
1280
 
    XtSetSensitive(ispell.undo, False);
1281
 
 
1282
 
    XtSetArg(args[0], XtNlabel, "");
1283
 
    XtSetValues(ispell.word, args, 1);
1284
 
 
1285
 
    XtSetArg(args[0], XtNstring, "");
1286
 
    XtSetValues(ispell.text, args, 1);
1287
 
 
1288
 
    XtSetArg(args[0], XtNlist, &strs);
1289
 
    XtSetArg(args[1], XtNnumberStrings, &n_strs);
1290
 
    XtGetValues(ispell.list, args, 2);
1291
 
 
1292
 
    list = (char**)XtMalloc(sizeof(char**));
1293
 
    list[0] = XtNewString("");
1294
 
    XtSetArg(args[0], XtNlist, list);
1295
 
    XtSetArg(args[1], XtNnumberStrings, 1);
1296
 
    XtSetValues(ispell.list, args, 2);
1297
 
 
1298
 
    if (n_strs > 1 || (XtName(ispell.list) != strs[0])) {
1299
 
        while (--n_strs > -1)
1300
 
            XtFree(strs[n_strs]);
1301
 
        XtFree((char*)strs);
1302
 
    }
1303
 
 
1304
 
    IspellSetStatus(ispell.working_label);
1305
 
 
1306
 
    if (!ispell.pid)
1307
 
        (void)IspellStartProcess();
1308
 
    else {
1309
 
        ispell.right = XawTextGetInsertionPoint(ispell.ascii);
1310
 
        ispell.right = XawTextSourceScan(ispell.source, ispell.right,
1311
 
                                              XawstEOL, XawsdLeft, 1, True);
1312
 
        while (IspellSend() == 0)
1313
 
            ;
1314
 
    }
1315
 
 
1316
 
    XtPopup(ispell.shell, XtGrabExclusive);
1317
 
    XtSetKeyboardFocus(ispell.shell, ispell.text);
1318
 
}
1319
 
 
1320
 
static Bool
1321
 
IspellStartProcess(void)
1322
 
{
1323
 
    if (!ispell.pid) {
1324
 
        int len;
1325
 
        char *command;
1326
 
 
1327
 
        ispell.source = XawTextGetSource(ispell.ascii);
1328
 
 
1329
 
        len = strlen(ispell.cmd) + strlen(ispell.dictionary) +
1330
 
              strlen(ispell.wchars) + 16;
1331
 
        command = XtMalloc(len);
1332
 
        XmuSnprintf(command, len, "%s -a -d '%s' -w '%s'",
1333
 
                    ispell.cmd, ispell.dictionary, ispell.wchars);
1334
 
 
1335
 
        pipe(ispell.ifd);
1336
 
        pipe(ispell.ofd);
1337
 
        if ((ispell.pid = fork()) == 0) {
1338
 
            close(0);
1339
 
            close(1);
1340
 
            dup2(ispell.ofd[0], 0);
1341
 
            dup2(ispell.ifd[1], 1);
1342
 
            close(ispell.ofd[0]);
1343
 
            close(ispell.ofd[1]);
1344
 
            close(ispell.ifd[0]);
1345
 
            close(ispell.ifd[1]);
1346
 
            execl("/bin/sh", "sh", "-c", command, (void *)NULL);
1347
 
            exit(-127);
1348
 
        }
1349
 
        else if (ispell.pid < 0) {
1350
 
            fprintf(stderr, "Cannot fork\n");
1351
 
            exit(1);
1352
 
        }
1353
 
        ispell.buf = XtMalloc(ispell.bufsiz = BUFSIZ);
1354
 
        ispell.right = -1;
1355
 
        ispell.id = XtAppAddInput(XtWidgetToApplicationContext(ispell.shell),
1356
 
                                  ispell.ifd[0], (XtPointer)XtInputReadMask,
1357
 
                                  IspellInputCallback, NULL);
1358
 
        fcntl(ispell.ifd[0], F_SETFL, O_NONBLOCK);
1359
 
    }
1360
 
    else
1361
 
        return (False);
1362
 
 
1363
 
    return (True);
1364
 
}
1365
 
 
1366
 
/*ARGSUSED*/
1367
 
static void
1368
 
PopdownIspell(Widget w, XtPointer client_data, XtPointer call_data)
1369
 
{
1370
 
    (void)IspellEndProcess((Bool)(long)client_data, True);
1371
 
    XtPopdown(ispell.shell);
1372
 
    *ispell.sentbuf = '\0';
1373
 
}
1374
 
 
1375
 
static Bool
1376
 
IspellEndProcess(Bool killit, Bool killundo)
1377
 
{
1378
 
    ispell.source = NULL;
1379
 
 
1380
 
    if (ispell.pid) {
1381
 
        IgnoreList *il, *pil, *nil;
1382
 
        int i;
1383
 
 
1384
 
        /* insert added words in private dictionary */
1385
 
        for (i = 0; i < ISTRTBLSZ; i++) {
1386
 
            pil = il = ignore_list[i];
1387
 
            while (il) {
1388
 
                if (il->add) {
1389
 
                    nil = il->next;
1390
 
                    if (il == pil)
1391
 
                        ignore_list[i] = nil;
1392
 
                    else
1393
 
                        pil->next = nil;
1394
 
                    if (il->add == UNCAP)
1395
 
                        write(ispell.ofd[1], "&", 1);
1396
 
                    else
1397
 
                        write(ispell.ofd[1], "*", 1);
1398
 
                    write(ispell.ofd[1], il->word, strlen(il->word));
1399
 
                    write(ispell.ofd[1], "\n", 1);
1400
 
                    XtFree(il->word);
1401
 
                    XtFree((char*)il);
1402
 
                    il = nil;
1403
 
                }
1404
 
                else
1405
 
                    il = il->next;
1406
 
                pil = il;
1407
 
            }
1408
 
        }
1409
 
        write(ispell.ofd[1], "#\n", 2);         /* save dictionary */
1410
 
 
1411
 
        if (killit) {
1412
 
            ReplaceList *rl, *prl;
1413
 
 
1414
 
            XtRemoveInput(ispell.id);
1415
 
 
1416
 
            close(ispell.ofd[0]);
1417
 
            close(ispell.ofd[1]);
1418
 
            close(ispell.ifd[0]);
1419
 
            close(ispell.ifd[1]);
1420
 
 
1421
 
            /* if something goes wrong, we don't want to block here forever */
1422
 
            old_timeout = signal(SIGALRM, timeout_signal);
1423
 
            alarm(10);
1424
 
            waitpid(ispell.pid, NULL, 0);
1425
 
            alarm(0);
1426
 
            signal(SIGALRM, old_timeout);
1427
 
 
1428
 
            ispell.pid = 0;
1429
 
            if (ispell.buf)
1430
 
                XtFree(ispell.buf);
1431
 
            ispell.buf = NULL;
1432
 
 
1433
 
            for (i = 0; i < RSTRTBLSZ; i++) {
1434
 
                prl = rl = replace_list[i];
1435
 
                while (prl) {
1436
 
                    rl = rl->next;
1437
 
                    XtFree(prl->word);
1438
 
                    XtFree(prl->replace);
1439
 
                    XtFree((char*)prl);
1440
 
                    prl = rl;
1441
 
                }
1442
 
                replace_list[i] = NULL;
1443
 
            }
1444
 
            for (i = 0; i < ISTRTBLSZ; i++) {
1445
 
                pil = il = ignore_list[i];
1446
 
                while (pil) {
1447
 
                    il = il->next;
1448
 
                    XtFree(pil->word);
1449
 
                    XtFree((char*)pil);
1450
 
                    pil = il;
1451
 
                }
1452
 
                ignore_list[i] = NULL;
1453
 
            }
1454
 
        }
1455
 
 
1456
 
        if (killundo)
1457
 
            IspellKillUndoBuffer();
1458
 
    }
1459
 
    else
1460
 
        return (False);
1461
 
 
1462
 
    return (True);
1463
 
}
1464
 
 
1465
 
static void
1466
 
IspellKillUndoBuffer(void)
1467
 
{
1468
 
    ispell_undo *undo, *pundo;
1469
 
 
1470
 
    undo = pundo = ispell.undo_base;
1471
 
    while (undo) {
1472
 
        undo = undo->next;
1473
 
        if (pundo->undo_str)
1474
 
            XtFree(pundo->undo_str);
1475
 
        XtFree((char*)pundo);
1476
 
        pundo = undo;
1477
 
    }
1478
 
    ispell.undo_base = ispell.undo_head = NULL;
1479
 
    ispell.undo_for = NULL;
1480
 
    ispell.undo_depth = 0;
1481
 
    XtSetSensitive(ispell.undo, False);
1482
 
}
1483
 
 
1484
 
/*ARGSUSED*/
1485
 
static void
1486
 
RevertIspell(Widget w, XtPointer client_data, XtPointer call_data)
1487
 
{
1488
 
    Arg args[1];
1489
 
    char *string, *repstr = NULL;
1490
 
 
1491
 
    XtSetArg(args[0], XtNlabel, &string);
1492
 
    XtGetValues(ispell.word, args, 1);
1493
 
    if ((repstr = strchr(string, ' ')) != NULL) {
1494
 
        string = repstr = XtNewString(string);
1495
 
        *strchr(repstr, ' ') = '\0';
1496
 
    }
1497
 
    XtSetArg(args[0], XtNstring, string);
1498
 
    XtSetValues(ispell.text, args, 1);
1499
 
    if (repstr)
1500
 
        XtFree(repstr);
1501
 
}
1502
 
 
1503
 
/*ARGSUSED*/
1504
 
static void
1505
 
SelectIspell(Widget w, XtPointer client_data, XtPointer call_data)
1506
 
{
1507
 
    XawListReturnStruct *info = (XawListReturnStruct *)call_data;
1508
 
    Arg args[1];
1509
 
 
1510
 
    XtSetArg(args[0], XtNstring, ispell.item = info->string);
1511
 
    XtSetValues(ispell.text, args, 1);
1512
 
}
1513
 
 
1514
 
/*ARGSUSED*/
1515
 
void
1516
 
ReplaceIspell(Widget w, XtPointer client_data, XtPointer call_data)
1517
 
{
1518
 
    XawTextPosition pos = XawTextGetInsertionPoint(ispell.ascii);
1519
 
    XawTextBlock check, search, replace;
1520
 
    Arg args[1];
1521
 
    char *text;
1522
 
 
1523
 
    if (!ispell.lock)
1524
 
        return;
1525
 
 
1526
 
    XtSetArg(args[0], XtNlabel, &text);
1527
 
    XtGetValues(ispell.word, args, 1);
1528
 
    search.ptr = text;
1529
 
    search.format = XawFmt8Bit;
1530
 
    search.firstPos = 0;
1531
 
    search.length = ispell.right - pos;
1532
 
 
1533
 
    XtSetArg(args[0], XtNstring, &text);
1534
 
    XtGetValues(ispell.text, args, 1);
1535
 
    replace.ptr = text;
1536
 
    replace.format = XawFmt8Bit;
1537
 
    replace.firstPos = 0;
1538
 
    replace.length = strlen(text);
1539
 
 
1540
 
    if (strcmp(search.ptr, replace.ptr) != 0 &&
1541
 
        XawTextReplace(ispell.ascii, pos, pos + search.length,
1542
 
                       &replace) == XawEditDone) {
1543
 
        ispell.right += replace.length - search.length;
1544
 
        IspellCheckUndo();
1545
 
        ispell.undo_head->undo_str = NULL;
1546
 
        ispell.undo_head->undo_pos = pos;
1547
 
        ispell.undo_head->undo_count = 1;
1548
 
 
1549
 
        if (ispell.repeat) {
1550
 
            ispell.undo_head->repeat = 2; /* To recognize later it was replaced */
1551
 
            ispell.undo_head->undo_count = ispell.right;
1552
 
            ispell.undo_head->undo_str = XtNewString(search.ptr);
1553
 
        }
1554
 
        if (client_data && !ispell.repeat) {
1555
 
            XawTextDisableRedisplay(ispell.ascii);
1556
 
            pos = ispell.right;
1557
 
            while ((pos = XawTextSourceSearch(ispell.source, pos, XawsdRight, &search))
1558
 
                != XawTextSearchError) {
1559
 
                Bool do_replace = True;
1560
 
                char mb[sizeof(wchar_t)];
1561
 
 
1562
 
                if (XawTextSourceRead(ispell.source, pos - 1, &check, 1) > 0) {
1563
 
                    wctomb(mb, *(wchar_t*)check.ptr);
1564
 
                    do_replace = !isalpha(*mb) && *mb && !strchr(ispell.wchars, *mb);
1565
 
                }
1566
 
                if (do_replace &&
1567
 
                    XawTextSourceRead(ispell.source, pos + search.length, &check, 1) > 0) {
1568
 
                    wctomb(mb, *(wchar_t*)check.ptr);
1569
 
                    do_replace = !isalpha(*mb) && *mb && !strchr(ispell.wchars, *mb);
1570
 
                }
1571
 
                if (do_replace) {
1572
 
                    XawTextReplace(ispell.ascii, pos, pos + search.length, &replace);
1573
 
                    ++ispell.undo_head->undo_count;
1574
 
                }
1575
 
                pos += search.length;
1576
 
            }
1577
 
            XawTextEnableRedisplay(ispell.ascii);
1578
 
        }
1579
 
        (void)IspellReplacedWord(search.ptr, replace.ptr);
1580
 
 
1581
 
        strncpy(&ispell.sentbuf[1], replace.ptr, sizeof(ispell.sentbuf) - 2);
1582
 
        ispell.sentbuf[sizeof(ispell.sentbuf) - 1] = '\0';
1583
 
    }
1584
 
    else
1585
 
        Feep();
1586
 
 
1587
 
    if (ispell.repeat)
1588
 
        ispell.right = ispell.left = XawTextGetInsertionPoint(ispell.ascii);
1589
 
    else if (!ispell.terse_mode || !ispell.item ||
1590
 
             strcmp(ispell.item, replace.ptr))
1591
 
        ispell.right = ispell.left;     /* check it again! */
1592
 
 
1593
 
    ispell.lock = ispell.checkit = False;
1594
 
 
1595
 
    ispell.stat = SEND;
1596
 
    IspellSetStatus(ispell.working_label);
1597
 
    while (IspellSend() == 0)
1598
 
        ;
1599
 
}
1600
 
 
1601
 
/*ARGSUSED*/
1602
 
void
1603
 
IgnoreIspell(Widget w, XtPointer client_data, XtPointer call_data)
1604
 
{
1605
 
    Arg args[1];
1606
 
    char *text;
1607
 
 
1608
 
    if (!ispell.lock)
1609
 
        return;
1610
 
 
1611
 
    XtSetArg(args[0], XtNlabel, &text);
1612
 
    XtGetValues(ispell.word, args, 1);
1613
 
 
1614
 
    IspellCheckUndo();
1615
 
 
1616
 
    if ((ispell.undo_head->repeat = ispell.repeat) != False) {
1617
 
        ispell.undo_head->undo_count = ispell.right;
1618
 
        ispell.undo_head->undo_str = XtNewString(text);
1619
 
    }
1620
 
    else
1621
 
        ispell.undo_head->undo_count = 0;
1622
 
 
1623
 
    ispell.undo_head->undo_pos = XawTextGetInsertionPoint(ispell.ascii);
1624
 
 
1625
 
    if (!ispell.repeat) {
1626
 
        if (client_data) {
1627
 
            IspellIgnoredWord(text, ADD, 0);
1628
 
            ispell.undo_head->undo_str = XtNewString(text);
1629
 
        }
1630
 
        else 
1631
 
            ispell.undo_head->undo_str = NULL;
1632
 
    }
1633
 
 
1634
 
    ispell.lock = ispell.checkit = False;
1635
 
 
1636
 
    ispell.stat = SEND;
1637
 
    IspellSetStatus(ispell.working_label);
1638
 
    while (IspellSend() == 0)
1639
 
        ;
1640
 
}
1641
 
 
1642
 
/*ARGSUSED*/
1643
 
void
1644
 
AddIspell(Widget w, XtPointer client_data, XtPointer call_data)
1645
 
{
1646
 
    Arg args[1];
1647
 
    char *text;
1648
 
    int cmd = (long)client_data;
1649
 
 
1650
 
    if (!ispell.lock || ispell.repeat)
1651
 
        return;
1652
 
 
1653
 
    XtSetArg(args[0], XtNlabel, &text);
1654
 
    XtGetValues(ispell.word, args, 1);
1655
 
 
1656
 
    IspellCheckUndo();
1657
 
    ispell.undo_head->undo_str = XtNewString(text);
1658
 
    ispell.undo_head->undo_pos = XawTextGetInsertionPoint(ispell.ascii);
1659
 
    ispell.undo_head->undo_count = -cmd;
1660
 
 
1661
 
    (void)IspellIgnoredWord(text, ADD, cmd);
1662
 
 
1663
 
    ispell.lock = ispell.checkit = False;
1664
 
    ispell.stat = SEND;
1665
 
    IspellSetStatus(ispell.working_label);
1666
 
    while (IspellSend() == 0)
1667
 
        ;
1668
 
}
1669
 
 
1670
 
/*ARGSUSED*/
1671
 
static void
1672
 
UndoIspell(Widget w, XtPointer client_data, XtPointer call_data)
1673
 
{
1674
 
    Bool enable_redisplay = False;
1675
 
    ispell_undo *undo = ispell.undo_head;
1676
 
 
1677
 
    if ((!ispell.lock && ispell.stat) || !undo)
1678
 
        return;
1679
 
 
1680
 
    if (ispell.undo_for && strcmp(ispell.undo_for, ispell.dictionary)) {
1681
 
        XeditPrintf("Undo: Dictionary changed. Undo information was lost.\n");
1682
 
        IspellKillUndoBuffer();
1683
 
        Feep();
1684
 
        return;
1685
 
    }
1686
 
 
1687
 
    if (undo->terse != ispell.terse_mode)
1688
 
        IspellSetTerseMode(undo->terse);
1689
 
 
1690
 
    if (undo->format != ispell.format_info->value) {
1691
 
        struct _ispell_format *fmt = &ispell_format[undo->format];
1692
 
        ChangeFormatIspell(fmt->sme, (XtPointer)fmt, NULL);
1693
 
    }
1694
 
 
1695
 
    if (undo->undo_count > 0 && !undo->repeat) {
1696
 
        XawTextPosition tmp;
1697
 
 
1698
 
        enable_redisplay = undo->undo_count > 1;
1699
 
        if (enable_redisplay)
1700
 
            XawTextDisableRedisplay(ispell.ascii);
1701
 
        while (undo->undo_count--)
1702
 
            if (!_XawTextSrcUndo((TextSrcObject)ispell.source, &tmp)) {
1703
 
                Feep();
1704
 
                break;
1705
 
            }
1706
 
    }
1707
 
    else if (undo->undo_count < 0) {
1708
 
        if (undo->undo_str)
1709
 
            (void)IspellIgnoredWord(undo->undo_str, REMOVE, -undo->undo_count);
1710
 
    }
1711
 
    else if (undo->undo_str) {
1712
 
        if (!undo->repeat)
1713
 
            IspellIgnoredWord(undo->undo_str, REMOVE, 0);
1714
 
    }
1715
 
 
1716
 
    XawTextSetInsertionPoint(ispell.ascii,
1717
 
                             ispell.right = ispell.left = undo->undo_pos);
1718
 
    if (enable_redisplay)
1719
 
        XawTextEnableRedisplay(ispell.ascii);
1720
 
 
1721
 
    /* need to do it because may be two misspelled words together */
1722
 
    if (undo->repeat) {
1723
 
        char **list, **old_list;
1724
 
        int old_len;
1725
 
        Arg args[2];
1726
 
 
1727
 
        if (undo->repeat > 1) {
1728
 
            XawTextDisableRedisplay(ispell.ascii);
1729
 
            if (!_XawTextSrcUndo((TextSrcObject)ispell.source, &ispell.right))
1730
 
                Feep();
1731
 
            XawTextEnableRedisplay(ispell.ascii);
1732
 
        }
1733
 
        else
1734
 
            ispell.right = (XawTextPosition)undo->undo_count;
1735
 
        IspellSetRepeated(ispell.repeat = True);
1736
 
        XtSetArg(args[0], XtNlabel, undo->undo_str);
1737
 
        XtSetValues(ispell.word, args, 1);
1738
 
        XmuSnprintf(ispell.sentbuf, sizeof(ispell.sentbuf), "^%s",
1739
 
                    strrchr(undo->undo_str, ' ') + 1);
1740
 
        strcpy(ispell.sendbuf, ispell.sentbuf);
1741
 
        XtSetArg(args[0], XtNstring, &ispell.sentbuf[1]);
1742
 
        XtSetValues(ispell.text, args, 1);
1743
 
 
1744
 
        XtSetArg(args[0], XtNlist, &old_list);
1745
 
        XtSetArg(args[1], XtNnumberStrings, &old_len);
1746
 
        XtGetValues(ispell.list, args, 2);
1747
 
 
1748
 
        list = (char **)XtMalloc(sizeof(char*));
1749
 
        list[0] = XtNewString(&ispell.sentbuf[1]);
1750
 
        XtSetArg(args[0], XtNlist, list);
1751
 
        XtSetArg(args[1], XtNnumberStrings, 1);
1752
 
        XtSetValues(ispell.list, args, 2);
1753
 
        XtSetSensitive(ispell.list, True);
1754
 
        XawListHighlight(ispell.list, 0);
1755
 
 
1756
 
        if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
1757
 
            while (--old_len > -1)
1758
 
                XtFree(old_list[old_len]);
1759
 
            XtFree((char*)old_list);
1760
 
        }
1761
 
 
1762
 
        IspellSetSelection(ispell.left, ispell.right);
1763
 
        IspellSetStatus(ispell.repeat_label);
1764
 
        ispell.lock = True;
1765
 
        ispell.checkit = False;
1766
 
    }
1767
 
    else if (ispell.repeat) {
1768
 
        *ispell.sentbuf = '\0';
1769
 
        IspellSetRepeated(ispell.repeat = False);
1770
 
    }
1771
 
 
1772
 
    if (undo->prev)
1773
 
        undo->prev->next = NULL;
1774
 
    ispell.undo_head = undo->prev;
1775
 
    if (undo == ispell.undo_base) {
1776
 
        ispell.undo_base = NULL;
1777
 
        ispell.undo_for = NULL;
1778
 
        XtSetSensitive(ispell.undo, False);
1779
 
    }
1780
 
    if (undo->undo_str)
1781
 
        XtFree(undo->undo_str);
1782
 
    XtFree((char*)undo);
1783
 
    --ispell.undo_depth;
1784
 
 
1785
 
    if (!ispell.stat || ispell.checkit)
1786
 
        IspellSetSensitive(True);
1787
 
 
1788
 
    if (!ispell.repeat) {
1789
 
        ispell.lock = ispell.checkit = False;
1790
 
        ispell.stat = SEND;
1791
 
        IspellSetStatus(ispell.working_label);
1792
 
        while (IspellSend() == 0)
1793
 
            ;
1794
 
    }
1795
 
}
1796
 
 
1797
 
/*ARGSUSED*/
1798
 
static void
1799
 
CheckIspell(Widget w, XtPointer client_data, XtPointer call_data)
1800
 
{
1801
 
    Arg args[1];
1802
 
    char *text, *str, string[1024];
1803
 
    int i, len;
1804
 
 
1805
 
    if (!ispell.lock)
1806
 
        return;
1807
 
 
1808
 
    XtSetArg(args[0], XtNstring, &text);
1809
 
    XtGetValues(ispell.text, args, 1);
1810
 
 
1811
 
    /* Check only a word at a time */
1812
 
    len = 0;
1813
 
    str = text;
1814
 
    while (*str) {
1815
 
        if (isalpha(*str) || strchr(ispell.wchars, *str))
1816
 
            break;
1817
 
        ++str;
1818
 
        ++len;
1819
 
    }
1820
 
    i = 0;
1821
 
    while (*str) {
1822
 
        if (isalpha(*str) || strchr(ispell.wchars, *str))
1823
 
            string[i++] = *str++;
1824
 
        else
1825
 
            break;
1826
 
    }
1827
 
    string[i] = '\0';
1828
 
 
1829
 
    if (strcmp(text, string)) {
1830
 
        XawTextPosition pos = XawTextGetInsertionPoint(ispell.text) - len;
1831
 
 
1832
 
        XtSetArg(args[0], XtNstring, string);
1833
 
        XtSetValues(ispell.text, args, 1);
1834
 
        XawTextSetInsertionPoint(ispell.text, pos);
1835
 
        Feep();
1836
 
    }
1837
 
 
1838
 
    if (i == 0) {
1839
 
        Feep();
1840
 
        return;
1841
 
    }
1842
 
 
1843
 
    len = XmuSnprintf(ispell.sendbuf, sizeof(ispell.sendbuf), "^%s\n", string);
1844
 
 
1845
 
    ispell.sendbuf[sizeof(ispell.sendbuf) - 1] = '\n';
1846
 
 
1847
 
    write(ispell.ofd[1], ispell.sendbuf, len);
1848
 
 
1849
 
    ispell.lock = False;
1850
 
    ispell.checkit = True;
1851
 
    ispell.stat = RECEIVE;
1852
 
}
1853
 
 
1854
 
/*ARGSUSED*/
1855
 
static void
1856
 
LookIspell(Widget w, XtPointer client_data, XtPointer call_data)
1857
 
{
1858
 
    int len, old_len;
1859
 
    FILE *fd;
1860
 
    Arg args[2];
1861
 
    char *text, *str, **list, **old_list, command[1024], buffer[1024];
1862
 
    Bool sensitive = True;
1863
 
 
1864
 
    if (!ispell.lock)
1865
 
        return;
1866
 
 
1867
 
    XtSetArg(args[0], XtNstring, &text);
1868
 
    XtGetValues(ispell.text, args, 1);
1869
 
 
1870
 
    if (!*text) {
1871
 
        Feep();
1872
 
        return;
1873
 
    }
1874
 
 
1875
 
    if (strlen(ispell.look_cmd) + strlen(text) + strlen(ispell.words_file) + 8
1876
 
        > sizeof(command) - 1) {
1877
 
        fprintf(stderr, "Command line too large\n");
1878
 
        return;
1879
 
    }
1880
 
 
1881
 
    XmuSnprintf(command, sizeof(command), "%s '^%s.*$' %s",
1882
 
                ispell.look_cmd, text, ispell.words_file);
1883
 
 
1884
 
    if ((fd = popen(command, "r")) == NULL) {
1885
 
        fprintf(stderr, "Cannot popen '%s'\n", ispell.look_cmd);
1886
 
        return;
1887
 
    }
1888
 
 
1889
 
    list = NULL;
1890
 
    len = 0;
1891
 
 
1892
 
#define MAX_LOOK_RESULTS        256
1893
 
    while (fgets(buffer, sizeof(buffer), fd) != NULL) {
1894
 
        if ((str = strchr(buffer, '\n')) == NULL) {
1895
 
            fprintf(stderr, "String is too large\n");
1896
 
            break;
1897
 
        }
1898
 
        *str = '\0';
1899
 
        if ((len % 16) == 0)
1900
 
            list = (char**)XtRealloc((char*)list, sizeof(char*) * (len + 16));
1901
 
        list[len] = XtNewString(buffer);
1902
 
        if (++len >= MAX_LOOK_RESULTS) {
1903
 
            Feep();
1904
 
            break;
1905
 
        }
1906
 
    }
1907
 
#undef MAX_LOOK_RESULTS
1908
 
 
1909
 
    XtSetArg(args[0], XtNlist, &old_list);
1910
 
    XtSetArg(args[1], XtNnumberStrings, &old_len);
1911
 
    XtGetValues(ispell.list, args, 2);
1912
 
 
1913
 
    if (len == 0) {
1914
 
        list = (char**)XtMalloc(sizeof(char*));
1915
 
        list[0] = XtNewString("");
1916
 
        len = 1;
1917
 
        sensitive = False;
1918
 
    }
1919
 
 
1920
 
    XtSetArg(args[0], XtNlist, list);
1921
 
    XtSetArg(args[1], XtNnumberStrings, len);
1922
 
    XtSetValues(ispell.list, args, 2);
1923
 
 
1924
 
    XtSetSensitive(ispell.list, sensitive);
1925
 
    IspellSetStatus(sensitive ? ispell.look_label : ispell.none_label);
1926
 
 
1927
 
    if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
1928
 
        while (--old_len > -1)
1929
 
            XtFree(old_list[old_len]);
1930
 
        XtFree((char*)old_list);
1931
 
    }
1932
 
 
1933
 
    pclose(fd);
1934
 
}
1935
 
 
1936
 
/*ARGSUSED*/
1937
 
static void
1938
 
ToggleTerseIspell(Widget w, XtPointer client_data, XtPointer call_data)
1939
 
{
1940
 
    if (!ispell.lock)
1941
 
        return;
1942
 
 
1943
 
    ispell.terse_mode = !ispell.terse_mode;
1944
 
    write(ispell.ofd[1], ispell.terse_mode ? "!\n" : "%\n", 2);
1945
 
}
1946
 
 
1947
 
/*ARGSUSED*/
1948
 
static void
1949
 
ChangeDictionaryIspell(Widget w, XtPointer client_data, XtPointer call_data)
1950
 
{
1951
 
    ispell_dict *tmp, *dic = (ispell_dict*)client_data;
1952
 
    XawTextPosition pos = XawTextGetInsertionPoint(ispell.ascii);
1953
 
    XawTextPosition right = ispell.right;
1954
 
    Arg args[1];
1955
 
 
1956
 
    if (strcmp(XtName(dic->sme), ispell.dictionary) == 0)
1957
 
        return;
1958
 
 
1959
 
    if (!ispell.lock) {
1960
 
        Feep();
1961
 
        return;
1962
 
    }
1963
 
 
1964
 
    for (tmp = ispell.dict_info; tmp; tmp = tmp->next)
1965
 
        if (strcmp(XtName(tmp->sme), ispell.dictionary) == 0) {
1966
 
            XtSetArg(args[0], XtNleftBitmap, None);
1967
 
            XtSetValues(tmp->sme, args, 1);
1968
 
        }
1969
 
 
1970
 
    if (ispell.undo_base && !ispell.undo_for)
1971
 
        ispell.undo_for = ispell.dictionary;
1972
 
 
1973
 
    XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
1974
 
    XtSetValues(dic->sme, args, 1);
1975
 
    ispell.dictionary = XtName(dic->sme);
1976
 
    ispell.wchars = dic->wchars;
1977
 
    XtSetArg(args[0], XtNlabel, XtName(dic->sme));
1978
 
    XtSetValues(ispell.dict, args, 1);
1979
 
 
1980
 
    IspellSetStatus(ispell.working_label);
1981
 
 
1982
 
    (void)IspellEndProcess(True, False);
1983
 
    ispell.lock = ispell.checkit = False;
1984
 
    (void)IspellStartProcess();
1985
 
 
1986
 
    ispell.stat = RECEIVE;
1987
 
 
1988
 
    /* restart at the same selected word */
1989
 
    if (ispell.repeat == False)
1990
 
        ispell.left = ispell.right = pos;
1991
 
    else
1992
 
        ispell.right = right;
1993
 
}
1994
 
 
1995
 
/*ARGSUSED*/
1996
 
static void
1997
 
ChangeFormatIspell(Widget w, XtPointer client_data, XtPointer call_data)
1998
 
{
1999
 
    struct _ispell_format *fmt = (struct _ispell_format*)client_data;
2000
 
    Arg args[1];
2001
 
 
2002
 
    if (strcmp(fmt->name, ispell.formatting) == 0)
2003
 
        return;
2004
 
 
2005
 
    if (!ispell.lock) {
2006
 
        Feep();
2007
 
        return;
2008
 
    }
2009
 
 
2010
 
    XtSetArg(args[0], XtNleftBitmap, None);
2011
 
    XtSetValues(ispell.format_info->sme, args, 1);
2012
 
 
2013
 
    XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
2014
 
    XtSetValues(fmt->sme, args, 1);
2015
 
    ispell.formatting = fmt->name;
2016
 
    ispell.format_info = fmt;
2017
 
    XtSetArg(args[0], XtNlabel, fmt->name);
2018
 
    XtSetValues(ispell.format, args, 1);
2019
 
}
2020
 
 
2021
 
static Bool
2022
 
InitIspell(void)
2023
 
{
2024
 
    Atom delete_window;
2025
 
    char *str, *list;
2026
 
    XtResource dict_res;
2027
 
    int i;
2028
 
    static XtResource text_res[] = {
2029
 
        {"skipLines", "Skip", XtRString, sizeof(char*),
2030
 
         XtOffsetOf(struct _ispell, skip), XtRString, "#"},
2031
 
    };
2032
 
 
2033
 
    if (ispell.shell)
2034
 
        return (False);
2035
 
 
2036
 
    ispell.shell        = XtCreatePopupShell("ispell", transientShellWidgetClass,
2037
 
                                             topwindow, NULL, 0);
2038
 
 
2039
 
    XtGetApplicationResources(ispell.shell, (XtPointer)&ispell, resources,
2040
 
                              XtNumber(resources), NULL, 0);
2041
 
 
2042
 
    ispell.form         = XtCreateManagedWidget("form", formWidgetClass,
2043
 
                                                ispell.shell, NULL, 0);
2044
 
    ispell.mispelled    = XtCreateManagedWidget("mispelled", labelWidgetClass,
2045
 
                                                ispell.form, NULL, 0);
2046
 
    ispell.repeated     = XtCreateWidget("repeated", labelWidgetClass,
2047
 
                                         ispell.form, NULL, 0);
2048
 
    ispell.word         = XtCreateManagedWidget("word", commandWidgetClass,
2049
 
                                                ispell.form, NULL, 0);
2050
 
    XtAddCallback(ispell.word, XtNcallback, RevertIspell, NULL);
2051
 
    ispell.replacement  = XtCreateManagedWidget("replacement", labelWidgetClass,
2052
 
                                                ispell.form, NULL, 0);
2053
 
    ispell.text         = XtVaCreateManagedWidget("text", asciiTextWidgetClass,
2054
 
                                                ispell.form,
2055
 
                                                XtNeditType, XawtextEdit,
2056
 
                                                NULL);
2057
 
    ispell.suggestions  = XtCreateManagedWidget("suggestions", labelWidgetClass,
2058
 
                                                ispell.form, NULL, 0);
2059
 
    ispell.viewport     = XtCreateManagedWidget("viewport", viewportWidgetClass,
2060
 
                                                ispell.form, NULL, 0);
2061
 
    ispell.list         = XtCreateManagedWidget("list", listWidgetClass,
2062
 
                                                ispell.viewport, NULL, 0);
2063
 
    XtAddCallback(ispell.list, XtNcallback, SelectIspell, NULL);
2064
 
    ispell.commands     = XtCreateManagedWidget("commands", formWidgetClass,
2065
 
                                                ispell.form, NULL, 0);
2066
 
    ispell.check        = XtCreateManagedWidget("check", commandWidgetClass,
2067
 
                                                ispell.commands, NULL, 0);
2068
 
    XtAddCallback(ispell.check, XtNcallback, CheckIspell, NULL);
2069
 
    ispell.look         = XtCreateManagedWidget("look", commandWidgetClass,
2070
 
                                                ispell.commands, NULL, 0);
2071
 
    XtAddCallback(ispell.look, XtNcallback, LookIspell, NULL);
2072
 
    ispell.undo         = XtCreateManagedWidget("undo", commandWidgetClass,
2073
 
                                                ispell.commands, NULL, 0);
2074
 
    XtAddCallback(ispell.undo, XtNcallback, UndoIspell, NULL);
2075
 
    ispell.replace      = XtCreateManagedWidget("replace", commandWidgetClass,
2076
 
                                                ispell.commands, NULL, 0);
2077
 
    XtAddCallback(ispell.replace, XtNcallback, ReplaceIspell, (XtPointer)False);
2078
 
    ispell.replaceAll   = XtCreateManagedWidget("replaceAll", commandWidgetClass,
2079
 
                                                ispell.commands, NULL, 0);
2080
 
    XtAddCallback(ispell.replaceAll, XtNcallback, ReplaceIspell, (XtPointer)True);
2081
 
    ispell.ignore       = XtCreateManagedWidget("ignore", commandWidgetClass,
2082
 
                                                ispell.commands, NULL, 0);
2083
 
    XtAddCallback(ispell.ignore, XtNcallback, IgnoreIspell, (XtPointer)False);
2084
 
    ispell.ignoreAll    = XtCreateManagedWidget("ignoreAll", commandWidgetClass,
2085
 
                                                ispell.commands, NULL, 0);
2086
 
    XtAddCallback(ispell.ignoreAll, XtNcallback, IgnoreIspell, (XtPointer)True);
2087
 
    ispell.add          = XtCreateManagedWidget("add", commandWidgetClass,
2088
 
                                                ispell.commands, NULL, 0);
2089
 
    XtAddCallback(ispell.add, XtNcallback, AddIspell, (XtPointer)ASIS);
2090
 
    ispell.addUncap     = XtCreateManagedWidget("addUncap", commandWidgetClass,
2091
 
                                                ispell.commands, NULL, 0);
2092
 
    XtAddCallback(ispell.addUncap, XtNcallback, AddIspell, (XtPointer)UNCAP);
2093
 
    ispell.suspend      = XtCreateManagedWidget("suspend", commandWidgetClass,
2094
 
                                                ispell.commands, NULL, 0);
2095
 
    XtAddCallback(ispell.suspend, XtNcallback, PopdownIspell, (XtPointer)False);
2096
 
    ispell.cancel       = XtCreateManagedWidget("cancel", commandWidgetClass,
2097
 
                                                ispell.commands, NULL, 0);
2098
 
    XtAddCallback(ispell.cancel, XtNcallback, PopdownIspell, (XtPointer)True);
2099
 
    ispell.terse        = XtVaCreateManagedWidget("terse", toggleWidgetClass,
2100
 
                                                  ispell.commands,
2101
 
                                                  XtNstate, ispell.terse_mode,
2102
 
                                                  NULL);
2103
 
    XtAddCallback(ispell.terse, XtNcallback, ToggleTerseIspell, NULL);
2104
 
    ispell.status       = XtCreateManagedWidget("status", labelWidgetClass,
2105
 
                                                ispell.form, NULL, 0);
2106
 
    ispell.options      = XtCreateManagedWidget("options", formWidgetClass,
2107
 
                                                ispell.form, NULL, 0);
2108
 
    ispell.dict         = XtVaCreateManagedWidget("dict", menuButtonWidgetClass,
2109
 
                                                  ispell.options,
2110
 
                                                  XtNmenuName, "dictionaries",
2111
 
                                                  NULL);
2112
 
    ispell.dictMenu     = XtCreatePopupShell("dictionaries", simpleMenuWidgetClass,
2113
 
                                             ispell.options, NULL, 0);
2114
 
    XtRealizeWidget(ispell.dictMenu);
2115
 
 
2116
 
    ispell.format       = XtVaCreateManagedWidget("format", menuButtonWidgetClass,
2117
 
                                                  ispell.options,
2118
 
                                                  XtNmenuName, "formats",
2119
 
                                                  NULL);
2120
 
    ispell.formatMenu   = XtCreatePopupShell("formats", simpleMenuWidgetClass,
2121
 
                                             ispell.options, NULL, 0);
2122
 
    XtRealizeWidget(ispell.formatMenu);
2123
 
 
2124
 
    XtRealizeWidget(ispell.shell);
2125
 
 
2126
 
    for (i = 0; i < sizeof(ispell_format) / sizeof(ispell_format[0]); i++) {
2127
 
        struct _ispell_format *fmt = &ispell_format[i];
2128
 
 
2129
 
        fmt->sme = XtCreateManagedWidget(fmt->name, smeBSBObjectClass,
2130
 
                                         ispell.formatMenu, NULL, 0);
2131
 
        XtAddCallback(fmt->sme, XtNcallback, ChangeFormatIspell, (XtPointer)fmt);
2132
 
 
2133
 
        if (strcmp(fmt->name, ispell.formatting) == 0) {
2134
 
            Arg args[1];
2135
 
 
2136
 
            XtSetArg(args[0], XtNlabel, ispell.formatting);
2137
 
            XtSetValues(ispell.format, args, 1);
2138
 
            XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
2139
 
            XtSetValues(fmt->sme, args, 1);
2140
 
            ispell.format_info = fmt;
2141
 
        }
2142
 
    }
2143
 
    if (ispell.format_info == NULL) {
2144
 
        Arg args[1];
2145
 
        char msg[256];
2146
 
 
2147
 
        ispell.format_info = &ispell_format[TEXT];
2148
 
 
2149
 
        XmuSnprintf(msg, sizeof(msg),
2150
 
                    "Unrecognized formatting type \"%s\", will use \"%s\"",
2151
 
                    ispell.formatting, ispell.format_info->name);
2152
 
        XtAppWarning(XtWidgetToApplicationContext(ispell.shell), msg);
2153
 
        ispell.formatting = ispell.format_info->name;
2154
 
 
2155
 
        XtSetArg(args[0], XtNlabel, ispell.format_info->name);
2156
 
        XtSetValues(ispell.format, args, 1);
2157
 
        XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
2158
 
        XtSetValues(ispell.format_info->sme, args, 1);
2159
 
    }
2160
 
    XtGetApplicationResources(ispell_format[TEXT].sme, (XtPointer)&ispell,
2161
 
                              text_res, XtNumber(text_res), NULL, 0);
2162
 
 
2163
 
    dict_res.resource_name = "wordChars";
2164
 
    dict_res.resource_class = "Chars";
2165
 
    dict_res.resource_type = XtRString;
2166
 
    dict_res.resource_size = sizeof(char*);
2167
 
    dict_res.resource_offset = XtOffsetOf(ispell_dict, wchars);
2168
 
    dict_res.default_type = XtRString;
2169
 
    dict_res.default_addr = "";
2170
 
 
2171
 
    list = XtNewString(ispell.dict_list);
2172
 
    for (str = strtok(list, " \t,"); str; str = strtok(NULL, " \t,")) {
2173
 
        ispell_dict *dic = XtNew(ispell_dict);
2174
 
 
2175
 
        dic->sme = XtCreateManagedWidget(str, smeBSBObjectClass,
2176
 
                                         ispell.dictMenu, NULL, 0);
2177
 
        XtGetApplicationResources(dic->sme, (XtPointer)dic, &dict_res,
2178
 
                                  1, NULL, 0);
2179
 
        XtAddCallback(dic->sme, XtNcallback, ChangeDictionaryIspell,
2180
 
                      (XtPointer)dic);
2181
 
        dic->next = NULL;
2182
 
        if (!ispell.dict_info)
2183
 
            ispell.dict_info = dic;
2184
 
        else {
2185
 
            ispell_dict *tmp = ispell.dict_info;
2186
 
 
2187
 
            for (; tmp->next; tmp = tmp->next)
2188
 
                ;
2189
 
            tmp->next = dic;
2190
 
        }
2191
 
        if (strcmp(str, ispell.dictionary) == 0) {
2192
 
            Arg args[1];
2193
 
 
2194
 
            XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
2195
 
            XtSetValues(dic->sme, args, 1);
2196
 
            XtSetArg(args[0], XtNlabel, str);
2197
 
            XtSetValues(ispell.dict, args, 1);
2198
 
            ispell.wchars = dic->wchars;
2199
 
        }
2200
 
    }
2201
 
    XtFree(list);
2202
 
 
2203
 
    delete_window = XInternAtom(XtDisplay(ispell.shell), "WM_DELETE_WINDOW", False);
2204
 
    XSetWMProtocols(XtDisplay(ispell.shell), XtWindow(ispell.shell), &delete_window, 1);
2205
 
 
2206
 
    return (True);
2207
 
}