15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 1999 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
30f14f4646Smrg/* $XdotOrg: xc/programs/xedit/ispell.c,v 1.6 2004/12/04 00:43:13 kuhn Exp $ */
315dfecf96Smrg/* $XFree86: xc/programs/xedit/ispell.c,v 1.19 2002/10/19 20:04:20 herrb Exp $ */
325dfecf96Smrg
335dfecf96Smrg#include "xedit.h"
34f14f4646Smrg#include "util.h"
355dfecf96Smrg#include <stdlib.h>
365dfecf96Smrg#include <unistd.h>
375dfecf96Smrg#include <fcntl.h>
385dfecf96Smrg#include <signal.h>
395dfecf96Smrg#include <ctype.h>
40f14f4646Smrg#include <locale.h>
415dfecf96Smrg#include <errno.h>
425dfecf96Smrg#include <sys/types.h>
435dfecf96Smrg#include <sys/wait.h>
445dfecf96Smrg#include <X11/Xaw/Toggle.h>
455dfecf96Smrg#include <X11/Xaw/MenuButton.h>
465dfecf96Smrg#include <X11/Xaw/SmeBSB.h>
475dfecf96Smrg#include <X11/Xaw/SimpleMenu.h>
485dfecf96Smrg#include <X11/Xos.h>
495dfecf96Smrg
505dfecf96Smrg#define RECEIVE		1
515dfecf96Smrg#define SEND		2
525dfecf96Smrg
535dfecf96Smrg#define CHECK		0
545dfecf96Smrg#define	ADD		1
555dfecf96Smrg#define REMOVE		2
565dfecf96Smrg
575dfecf96Smrg#define	ASIS		1
585dfecf96Smrg#define UNCAP		2
595dfecf96Smrg
605dfecf96Smrg/*
615dfecf96Smrg * Types
625dfecf96Smrg */
635dfecf96Smrg#define UNDO_DEPTH	16
645dfecf96Smrgtypedef struct _ispell_undo {
655dfecf96Smrg    char *undo_str;
665dfecf96Smrg    int undo_count;
675dfecf96Smrg    XawTextPosition undo_pos;
685dfecf96Smrg    Boolean repeat;	/* two (misspelled?) words together */
695dfecf96Smrg    Boolean terse;
705dfecf96Smrg    int format;		/* remember text formatting style */
715dfecf96Smrg    struct _ispell_undo *next, *prev;
725dfecf96Smrg} ispell_undo;
735dfecf96Smrg
745dfecf96Smrgtypedef struct _ispell_dict {
755dfecf96Smrg    Widget sme;
765dfecf96Smrg    char *wchars;
775dfecf96Smrg    struct _ispell_dict *next;
785dfecf96Smrg} ispell_dict;
795dfecf96Smrg
805dfecf96Smrg#define	TEXT	0
815dfecf96Smrg#define HTML	1
825dfecf96Smrgstruct _ispell_format {
835dfecf96Smrg    char *name;
845dfecf96Smrg    int value;
855dfecf96Smrg    Widget sme;
865dfecf96Smrg};
875dfecf96Smrg
885dfecf96Smrgstatic struct _ispell_format ispell_format[] = {
895dfecf96Smrg    {"text",	TEXT},
905dfecf96Smrg    {"html",	HTML},
915dfecf96Smrg};
925dfecf96Smrg
935dfecf96Smrgstruct _ispell {
945dfecf96Smrg    Widget shell, form, mispelled, repeated, word, replacement, text,
955dfecf96Smrg	   suggestions, viewport, list, commands, replace, status,
965dfecf96Smrg	   replaceAll, undo, ignore, ignoreAll, add, addUncap, suspend,
975dfecf96Smrg	   cancel, check, look, terse, options, dict, dictMenu,
985dfecf96Smrg	   format, formatMenu;
995dfecf96Smrg
1005dfecf96Smrg    Widget ascii, source;
1015dfecf96Smrg    XtInputId id;
1025dfecf96Smrg    int pid, ifd[2], ofd[2];
1035dfecf96Smrg    XawTextPosition left, right;
1045dfecf96Smrg    char *item;
1055dfecf96Smrg    Bool lock;
1065dfecf96Smrg    Bool repeat;
1075dfecf96Smrg    Bool checkit;
1085dfecf96Smrg    int stat;
1095dfecf96Smrg    char *buf;
1105dfecf96Smrg    int bufsiz;
1115dfecf96Smrg    int buflen;
1125dfecf96Smrg    char sendbuf[1024];
1135dfecf96Smrg    char sentbuf[1024];
1145dfecf96Smrg
1155dfecf96Smrg    int undo_depth;
1165dfecf96Smrg    ispell_undo *undo_head, *undo_base;
1175dfecf96Smrg    char *undo_for;
1185dfecf96Smrg
1195dfecf96Smrg    char *wchars;
1205dfecf96Smrg    char *cmd;
1215dfecf96Smrg    char *skip;
1225dfecf96Smrg    char *command;
1235dfecf96Smrg    Boolean terse_mode, undo_terse_mode;
1245dfecf96Smrg    char *guess_label, *miss_label, *root_label, *none_label, *eof_label,
1255dfecf96Smrg	 *compound_label, *ok_label, *repeat_label, *working_label, *look_label;
1265dfecf96Smrg    char *look_cmd;
1275dfecf96Smrg    char *words_file;
1285dfecf96Smrg
1295dfecf96Smrg    char *dictionary;
1305dfecf96Smrg    char *dict_list;
1315dfecf96Smrg    ispell_dict *dict_info;
1325dfecf96Smrg
1335dfecf96Smrg    int format_mode;	/* to undo correctly */
1345dfecf96Smrg    char *formatting;
1355dfecf96Smrg    struct _ispell_format *format_info;
1365dfecf96Smrg};
1375dfecf96Smrg
138f14f4646Smrgtypedef struct _ReplaceEntry ReplaceEntry;
139f14f4646Smrgstruct _ReplaceEntry {
140f14f4646Smrg    hash_key	*word;
141f14f4646Smrg    ReplaceEntry*next;
142f14f4646Smrg    char	*replace;
143f14f4646Smrg};
1445dfecf96Smrg
145f14f4646Smrgtypedef struct _IgnoreEntry IgnoreEntry;
146f14f4646Smrgstruct _IgnoreEntry {
147f14f4646Smrg    hash_key	*word;
148f14f4646Smrg    IgnoreEntry	*next;
149f14f4646Smrg    int		add;
150f14f4646Smrg};
1515dfecf96Smrg
1525dfecf96Smrg/*
1535dfecf96Smrg * Prototypes
1545dfecf96Smrg */
1555dfecf96Smrgstatic void AddIspell(Widget, XtPointer, XtPointer);
1565dfecf96Smrgstatic void ChangeDictionaryIspell(Widget, XtPointer, XtPointer);
1575dfecf96Smrgstatic void ChangeFormatIspell(Widget, XtPointer, XtPointer);
1585dfecf96Smrgstatic void CheckIspell(Widget, XtPointer, XtPointer);
1595dfecf96Smrgstatic void IgnoreIspell(Widget, XtPointer, XtPointer);
1605dfecf96Smrgstatic Bool InitIspell(void);
1615dfecf96Smrgstatic void IspellCheckUndo(void);
1625dfecf96Smrgstatic int IspellConvertHtmlAmp(char*);
1635dfecf96Smrgstatic Bool IspellDoIgnoredWord(char*, int, int);
1645dfecf96Smrgstatic Bool IspellIgnoredWord(char*, int, int);
1655dfecf96Smrgstatic void IspellInputCallback(XtPointer, int*, XtInputId*);
1665dfecf96Smrgstatic void IspellKillUndoBuffer(void);
1675dfecf96Smrgstatic Bool IspellReceive(void);
1685dfecf96Smrgstatic char *IspellReplacedWord(char*, char*);
1695dfecf96Smrgstatic int IspellSend(void);
1705dfecf96Smrgstatic void IspellSetSelection(XawTextPosition, XawTextPosition);
1715dfecf96Smrgstatic void IspellSetRepeated(Bool);
1725dfecf96Smrgstatic void IspellSetSensitive(Bool);
1735dfecf96Smrgstatic void IspellSetStatus(char*);
1745dfecf96Smrgstatic void IspellSetTerseMode(Bool);
1755dfecf96Smrgstatic Bool IspellStartProcess(void);
176f14f4646Smrgstatic Bool IspellCheckProcess(void);
1775dfecf96Smrgstatic Bool IspellEndProcess(Bool, Bool);
1785dfecf96Smrgstatic void LookIspell(Widget, XtPointer, XtPointer);
1795dfecf96Smrgstatic void PopdownIspell(Widget, XtPointer, XtPointer);
1805dfecf96Smrgstatic void ReplaceIspell(Widget, XtPointer, XtPointer);
1815dfecf96Smrgstatic void RevertIspell(Widget, XtPointer, XtPointer);
1825dfecf96Smrgstatic void SelectIspell(Widget, XtPointer, XtPointer);
1835dfecf96Smrgstatic void ToggleTerseIspell(Widget, XtPointer, XtPointer);
1845dfecf96Smrgstatic void timeout_signal(int);
1855dfecf96Smrgstatic void (*old_timeout)(int);
1865dfecf96Smrgstatic void UndoIspell(Widget, XtPointer, XtPointer);
1875dfecf96Smrg
1885dfecf96SmrgBool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
1895dfecf96Smrg
1905dfecf96Smrg/*
1915dfecf96Smrg * Initialization
1925dfecf96Smrg */
1935dfecf96Smrgstatic struct _ispell ispell;
1945dfecf96Smrg
1955dfecf96Smrg#define RSTRTBLSZ	23
1965dfecf96Smrg#define ISTRTBLSZ	71
197f14f4646Smrgstatic hash_table *replace_hash;
198f14f4646Smrgstatic hash_table *ignore_hash;
1995dfecf96Smrg
2005dfecf96Smrg#ifndef XtCStatus
2015dfecf96Smrg#define XtCStatus	"Status"
2025dfecf96Smrg#endif
2035dfecf96Smrg
2045dfecf96Smrg#define Offset(field) XtOffsetOf(struct _ispell, field)
2055dfecf96Smrgstatic XtResource resources[] = {
2065dfecf96Smrg    {"wordChars", "Chars", XtRString, sizeof(char*),
2075dfecf96Smrg	Offset(wchars), XtRString, ""},
2085dfecf96Smrg    {"ispellCommand", "CommandLine", XtRString, sizeof(char*),
2095dfecf96Smrg	Offset(cmd), XtRString, "/usr/local/bin/ispell"},
2105dfecf96Smrg    {"terseMode", "Terse", XtRBoolean, sizeof(Boolean),
2115dfecf96Smrg	Offset(terse_mode), XtRImmediate, (XtPointer)False},
2125dfecf96Smrg    {"guessLabel", XtCStatus, XtRString, sizeof(String),
2135dfecf96Smrg	Offset(guess_label), XtRString, "Guess"},
2145dfecf96Smrg    {"missLabel", XtCStatus, XtRString, sizeof(String),
2155dfecf96Smrg	Offset(miss_label), XtRString, "Miss"},
2165dfecf96Smrg    {"rootLabel", XtCStatus, XtRString, sizeof(String),
2175dfecf96Smrg	Offset(root_label), XtRString, "Root:"},
2185dfecf96Smrg    {"noneLabel", XtCStatus, XtRString, sizeof(String),
2195dfecf96Smrg	Offset(none_label), XtRString, "None"},
2205dfecf96Smrg    {"compoundLabel", XtCStatus, XtRString, sizeof(String),
2215dfecf96Smrg	Offset(compound_label), XtRString, "Compound"},
2225dfecf96Smrg    {"okLabel", XtCStatus, XtRString, sizeof(String),
2235dfecf96Smrg	Offset(ok_label), XtRString, "Ok"},
2245dfecf96Smrg    {"eofLabel", XtCStatus, XtRString, sizeof(String),
2255dfecf96Smrg	Offset(eof_label), XtRString, "End Of File"},
2265dfecf96Smrg    {"repeatLabel", XtCStatus, XtRString, sizeof(String),
2275dfecf96Smrg	Offset(repeat_label), XtRString, "Repeat"},
2285dfecf96Smrg    {"workingLabel", XtCStatus, XtRString, sizeof(String),
2295dfecf96Smrg	Offset(working_label), XtRString, "..."},
2305dfecf96Smrg    {"lookLabel", XtCStatus, XtRString, sizeof(String),
2315dfecf96Smrg	Offset(look_label), XtRString, "Look"},
2325dfecf96Smrg    {"lookCommand", "CommandLine", XtRString, sizeof(char*),
2335dfecf96Smrg	Offset(look_cmd), XtRString, "/usr/bin/egrep -i"},
2345dfecf96Smrg    {"wordsFile", "Words", XtRString, sizeof(char*),
2355dfecf96Smrg	Offset(words_file), XtRString, "/usr/share/dict/words"},
2365dfecf96Smrg    {"dictionary", "Dictionary", XtRString, sizeof(char*),
2375dfecf96Smrg	Offset(dictionary), XtRString, "american"},
2385dfecf96Smrg    {"dictionaries", "Dictionary", XtRString, sizeof(char*),
2395dfecf96Smrg	Offset(dict_list), XtRString, "american americanmed+ english"},
2405dfecf96Smrg    {"formatting", "TextFormat", XtRString, sizeof(char*),
2415dfecf96Smrg	Offset(formatting), XtRString, "text"},
2425dfecf96Smrg};
2435dfecf96Smrg#undef Offset
2445dfecf96Smrg
2455dfecf96Smrg#ifdef NO_LIBC_I18N
2465dfecf96Smrgstatic int
2475dfecf96SmrgToLower(int ch)
2485dfecf96Smrg{
2495dfecf96Smrg    char buf[2];
2505dfecf96Smrg
2515dfecf96Smrg    *buf = ch;
2525dfecf96Smrg    XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
2535dfecf96Smrg
2545dfecf96Smrg    return (*buf);
2555dfecf96Smrg}
2565dfecf96Smrg
2575dfecf96Smrgstatic int
2585dfecf96SmrgToUpper(int ch)
2595dfecf96Smrg{
2605dfecf96Smrg    char buf[2];
2615dfecf96Smrg
2625dfecf96Smrg    *buf = ch;
2635dfecf96Smrg    XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
2645dfecf96Smrg
2655dfecf96Smrg    return (*buf);
2665dfecf96Smrg}
2675dfecf96Smrg
2685dfecf96Smrgstatic int
2695dfecf96SmrgIsLower(int ch)
2705dfecf96Smrg{
2715dfecf96Smrg    char upbuf[2];
2725dfecf96Smrg    char lobuf[2];
2735dfecf96Smrg
2745dfecf96Smrg    *upbuf = *lobuf = ch;
2755dfecf96Smrg    XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
2765dfecf96Smrg    XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
2775dfecf96Smrg
2785dfecf96Smrg    return (*lobuf != *upbuf && ch == *lobuf);
2795dfecf96Smrg}
2805dfecf96Smrg
2815dfecf96Smrgstatic int
2825dfecf96SmrgIsUpper(int ch)
2835dfecf96Smrg{
2845dfecf96Smrg    char upbuf[2];
2855dfecf96Smrg    char lobuf[2];
2865dfecf96Smrg
2875dfecf96Smrg    *upbuf = *lobuf = ch;
2885dfecf96Smrg    XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
2895dfecf96Smrg    XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
2905dfecf96Smrg
2915dfecf96Smrg    return (*lobuf != *upbuf && ch == *upbuf);
2925dfecf96Smrg}
2935dfecf96Smrg#else
2945dfecf96Smrg#define	ToLower	tolower
2955dfecf96Smrg#define ToUpper	toupper
2965dfecf96Smrg#define IsLower islower
2975dfecf96Smrg#define IsUpper isupper
2985dfecf96Smrg#endif
2995dfecf96Smrg
3005dfecf96Smrg/*
3015dfecf96Smrg * Implementation
3025dfecf96Smrg */
3035dfecf96Smrg#ifdef STDERR_FILENO
3045dfecf96Smrg# define WRITES(s) write(STDERR_FILENO, s, strlen(s))
3055dfecf96Smrg#else
3065dfecf96Smrg# define WRITES(s) write(fileno(stderr), s, strlen(s))
3075dfecf96Smrg#endif
3085dfecf96Smrg
3095dfecf96Smrg/*ARGSUSED*/
3105dfecf96Smrgstatic void
3115dfecf96Smrgtimeout_signal(int unused)
3125dfecf96Smrg{
3135dfecf96Smrg    int olderrno = errno;
3145dfecf96Smrg
3155dfecf96Smrg    WRITES("Warning: Timeout waiting ispell process to die.\n");
3165dfecf96Smrg    kill(ispell.pid, SIGTERM);
3175dfecf96Smrg    errno = olderrno;
3185dfecf96Smrg}
3195dfecf96Smrg
3205dfecf96Smrgstatic void
3215dfecf96SmrgIspellSetSelection(XawTextPosition left, XawTextPosition right)
3225dfecf96Smrg{
3235dfecf96Smrg    /* Try to make sure the selected word is completely visible */
3245dfecf96Smrg    XawTextSetInsertionPoint(ispell.ascii, right);
3255dfecf96Smrg    XawTextSetInsertionPoint(ispell.ascii, left);
3265dfecf96Smrg    XawTextSetSelection(ispell.ascii, left, right);
3275dfecf96Smrg}
3285dfecf96Smrg
3295dfecf96Smrgstatic void
3305dfecf96SmrgIspellSetStatus(char *label)
3315dfecf96Smrg{
3325dfecf96Smrg    Arg args[1];
3335dfecf96Smrg
3345dfecf96Smrg    XtSetArg(args[0], XtNlabel, label);
3355dfecf96Smrg    XtSetValues(ispell.status, args, 1);
3365dfecf96Smrg}
3375dfecf96Smrg
3385dfecf96Smrgstatic void
3395dfecf96SmrgIspellSetRepeated(Bool state)
3405dfecf96Smrg{
3415dfecf96Smrg    static char *mispelled, *repeated;
3425dfecf96Smrg    Arg args[1];
3435dfecf96Smrg
3445dfecf96Smrg    if (mispelled == NULL) {
3455dfecf96Smrg	XtSetArg(args[0], XtNlabel, &mispelled);
3465dfecf96Smrg	XtGetValues(ispell.mispelled, args, 1);
3475dfecf96Smrg	mispelled = XtNewString(mispelled);
3485dfecf96Smrg    }
3495dfecf96Smrg    if (repeated == NULL) {
3505dfecf96Smrg	XtSetArg(args[0], XtNlabel, &repeated);
3515dfecf96Smrg	XtGetValues(ispell.repeated, args, 1);
3525dfecf96Smrg	repeated = XtNewString(repeated);
3535dfecf96Smrg    }
3545dfecf96Smrg    XtSetSensitive(ispell.replaceAll, !state);
3555dfecf96Smrg    XtSetSensitive(ispell.ignoreAll, !state);
3565dfecf96Smrg    XtSetSensitive(ispell.add, !state);
3575dfecf96Smrg    XtSetSensitive(ispell.addUncap, !state);
3585dfecf96Smrg    if (!state) {
3595dfecf96Smrg	XtSetArg(args[0], XtNlabel, mispelled);
3605dfecf96Smrg	XtSetValues(ispell.mispelled, args, 1);
3615dfecf96Smrg    }
3625dfecf96Smrg    else {
3635dfecf96Smrg	XtSetArg(args[0], XtNlabel, repeated);
3645dfecf96Smrg	XtSetValues(ispell.mispelled, args, 1);
3655dfecf96Smrg    }
3665dfecf96Smrg}
3675dfecf96Smrg
3685dfecf96Smrgstatic void
3695dfecf96SmrgIspellSetSensitive(Bool state)
3705dfecf96Smrg{
3715dfecf96Smrg    XtSetSensitive(ispell.replace, state);
3725dfecf96Smrg    XtSetSensitive(ispell.replaceAll, state);
3735dfecf96Smrg    XtSetSensitive(ispell.ignore, state);
3745dfecf96Smrg    XtSetSensitive(ispell.ignoreAll, state);
3755dfecf96Smrg    XtSetSensitive(ispell.add, state);
3765dfecf96Smrg    XtSetSensitive(ispell.addUncap, state);
3775dfecf96Smrg}
3785dfecf96Smrg
3795dfecf96Smrgstatic void
3805dfecf96SmrgIspellSetTerseMode(Bool mode)
3815dfecf96Smrg{
3825dfecf96Smrg    Arg args[1];
3835dfecf96Smrg
3845dfecf96Smrg    XtSetArg(args[0], XtNstate, ispell.terse_mode = mode);
3855dfecf96Smrg    XtSetValues(ispell.terse, args, 1);
3865dfecf96Smrg    write(ispell.ofd[1], mode ? "!\n" : "%\n", 2);
3875dfecf96Smrg}
3885dfecf96Smrg
3895dfecf96Smrgstatic void
3905dfecf96SmrgIspellCheckUndo(void)
3915dfecf96Smrg{
3925dfecf96Smrg    ispell_undo *undo = XtNew(ispell_undo);
3935dfecf96Smrg
3945dfecf96Smrg    if (ispell.undo_for && strcmp(ispell.undo_for, ispell.dictionary)) {
3955dfecf96Smrg	XeditPrintf("Undo: Dictionary changed. Previous undo information lost.\n");
3965dfecf96Smrg	IspellKillUndoBuffer();
3975dfecf96Smrg	Feep();
3985dfecf96Smrg    }
3995dfecf96Smrg
4005dfecf96Smrg    undo->next = NULL;
4015dfecf96Smrg    undo->repeat = False;
4025dfecf96Smrg    undo->terse = ispell.undo_terse_mode;
4035dfecf96Smrg    undo->format = ispell.format_mode;
4045dfecf96Smrg    if ((undo->prev = ispell.undo_head) != NULL)
4055dfecf96Smrg	undo->prev->next = undo;
4065dfecf96Smrg    else
4075dfecf96Smrg	undo->prev = NULL;
4085dfecf96Smrg    ++ispell.undo_depth;
4095dfecf96Smrg    if (!ispell.undo_base) {
4105dfecf96Smrg	ispell.undo_base = undo;
4115dfecf96Smrg	XtSetSensitive(ispell.undo, True);
4125dfecf96Smrg    }
4135dfecf96Smrg    else if (ispell.undo_depth > UNDO_DEPTH) {
4145dfecf96Smrg	ispell_undo *tmp;
4155dfecf96Smrg
4165dfecf96Smrg	if (ispell.undo_base->undo_str)
4175dfecf96Smrg	    XtFree(ispell.undo_base->undo_str);
4185dfecf96Smrg	tmp = ispell.undo_base->next;
4195dfecf96Smrg	XtFree((char*)ispell.undo_base);
4205dfecf96Smrg	tmp->prev = NULL;
4215dfecf96Smrg	ispell.undo_base = tmp;
4225dfecf96Smrg	ispell.undo_depth = UNDO_DEPTH;
4235dfecf96Smrg    }
4245dfecf96Smrg    ispell.undo_head = undo;
4255dfecf96Smrg}
4265dfecf96Smrg
4275dfecf96Smrgstatic char *
4285dfecf96SmrgIspellReplacedWord(char *word, char *replace)
4295dfecf96Smrg{
430f14f4646Smrg    int			word_len;
431f14f4646Smrg    hash_key		*word_key;
432f14f4646Smrg    ReplaceEntry	*entry;
433f14f4646Smrg
434f14f4646Smrg    word_len = strlen(word);
435f14f4646Smrg    entry = (ReplaceEntry *)hash_check(replace_hash, word, word_len);
436f14f4646Smrg    if (entry == NULL) {
437f14f4646Smrg	word_key = XtNew(hash_key);
438f14f4646Smrg	word_key->value = XtNewString(word);
439f14f4646Smrg	word_key->length = word_len;
440f14f4646Smrg	entry = XtNew(ReplaceEntry);
441f14f4646Smrg	entry->word = word_key;
442f14f4646Smrg	entry->replace = NULL;
443f14f4646Smrg	entry->next = NULL;
444f14f4646Smrg	hash_put(replace_hash, (hash_entry *)entry);
445f14f4646Smrg    }
4465dfecf96Smrg
447f14f4646Smrg    if (replace) {
448f14f4646Smrg	XtFree(entry->replace);
449f14f4646Smrg	entry->replace = XtNewString(replace);
450f14f4646Smrg    }
4515dfecf96Smrg
452f14f4646Smrg    return (entry->replace);
4535dfecf96Smrg}
4545dfecf96Smrg
4555dfecf96Smrgstatic Bool
4565dfecf96SmrgIspellDoIgnoredWord(char *word, int cmd, int add)
4575dfecf96Smrg{
458f14f4646Smrg    int		word_len;
459f14f4646Smrg    hash_key	*word_key;
460f14f4646Smrg    IgnoreEntry	*entry;
461f14f4646Smrg
462f14f4646Smrg    word_len = strlen(word);
463f14f4646Smrg    entry = (IgnoreEntry *)hash_check(ignore_hash, word, word_len);
464f14f4646Smrg    if (entry == NULL) {
465f14f4646Smrg	if (cmd != ADD)
466f14f4646Smrg	    return (False);
4675dfecf96Smrg
468f14f4646Smrg	word_key = XtNew(hash_key);
469f14f4646Smrg	word_key->value = XtNewString(word);
470f14f4646Smrg	word_key->length = word_len;
471f14f4646Smrg	entry = XtNew(IgnoreEntry);
472f14f4646Smrg	entry->word = word_key;
473f14f4646Smrg	entry->add = add;
474f14f4646Smrg	entry->next = NULL;
475f14f4646Smrg	hash_put(ignore_hash, (hash_entry *)entry);
4765dfecf96Smrg
477f14f4646Smrg	return (True);
478f14f4646Smrg    }
479f14f4646Smrg    else if (cmd == REMOVE)
480f14f4646Smrg	hash_rem(ignore_hash, (hash_entry *)entry);
4815dfecf96Smrg
482f14f4646Smrg    return (cmd == CHECK);
4835dfecf96Smrg}
4845dfecf96Smrg
4855dfecf96Smrgstatic Bool
4865dfecf96SmrgIspellIgnoredWord(char *word, int cmd, int add)
4875dfecf96Smrg{
4885dfecf96Smrg    if (add != UNCAP && IspellDoIgnoredWord(word, cmd, add))
4895dfecf96Smrg	return (True);
4905dfecf96Smrg
4915dfecf96Smrg    /* add/remove uncapped word to/of list,
4925dfecf96Smrg     * or cheks for correct capitalization */
4935dfecf96Smrg    if (add == UNCAP || cmd == CHECK) {
4945dfecf96Smrg	unsigned char *str = (unsigned char*)word;
4955dfecf96Smrg	unsigned char string[1024];
4965dfecf96Smrg	Bool upper, status;
4975dfecf96Smrg	int i;
4985dfecf96Smrg
4995dfecf96Smrg	status = True;
5005dfecf96Smrg	upper = IsUpper(*str);
5015dfecf96Smrg	*string = upper ? ToLower(*str) : *str;
5025dfecf96Smrg	if (*str)
5035dfecf96Smrg	    str++;
5045dfecf96Smrg	if (IsLower(*str))
5055dfecf96Smrg	    upper = False;
5065dfecf96Smrg	for (i = 1; *str && i < sizeof(string) - 1; i++, str++) {
5075dfecf96Smrg	    if (upper && IsLower(*str))
5085dfecf96Smrg		status = False;
5095dfecf96Smrg	    else if (!upper && IsUpper(*str))
5105dfecf96Smrg		status = False;
5115dfecf96Smrg	    string[i] = ToLower(*str);
5125dfecf96Smrg	}
5135dfecf96Smrg	string[i] = '\0';
5145dfecf96Smrg
5155dfecf96Smrg	if ((cmd != CHECK || status) &&
5165dfecf96Smrg	    IspellDoIgnoredWord((char*)string, cmd, add))
5175dfecf96Smrg	    return (True);
5185dfecf96Smrg    }
5195dfecf96Smrg
5205dfecf96Smrg    return (False);
5215dfecf96Smrg}
5225dfecf96Smrg
5235dfecf96Smrg/*ARGSUSED*/
5245dfecf96Smrgstatic Bool
5255dfecf96SmrgIspellReceive(void)
5265dfecf96Smrg{
5275dfecf96Smrg    int i, len, old_len;
5285dfecf96Smrg    Arg args[2];
5295dfecf96Smrg    char *str, *end, **list, **old_list;
5305dfecf96Smrg    char *tmp, word[1024];
5315dfecf96Smrg    int j;
5325dfecf96Smrg
5335dfecf96Smrg    if (ispell.lock || ispell.stat != RECEIVE)
5345dfecf96Smrg	return (False);
5355dfecf96Smrg
5365dfecf96Smrg    while (1) {		/* read the entire line */
5375dfecf96Smrg	if (ispell.buflen >= ispell.bufsiz - 1)
5385dfecf96Smrg	    ispell.buf = XtRealloc(ispell.buf, ispell.bufsiz += BUFSIZ);
5395dfecf96Smrg	if ((len = read(ispell.ifd[0], &ispell.buf[ispell.buflen],
5405dfecf96Smrg			ispell.bufsiz - ispell.buflen - 1)) <= 0)
5415dfecf96Smrg	    break;
5425dfecf96Smrg	ispell.buflen += len;
5435dfecf96Smrg    }
5445dfecf96Smrg    if (ispell.buflen <= 0)
5455dfecf96Smrg	return (False);
5465dfecf96Smrg    len = 0;
5475dfecf96Smrg    i = ispell.buflen - 1;
5485dfecf96Smrg    while (i >= 0 && ispell.buf[i] == '\n') {
5495dfecf96Smrg	++len;
5505dfecf96Smrg	--i;
5515dfecf96Smrg    }
5525dfecf96Smrg    if (len < 2 - ((ispell.terse_mode && i == -1) || ispell.buf[0] == '@'))
5535dfecf96Smrg	return (False);
5545dfecf96Smrg    ispell.buf[ispell.buflen - len] = '\0';
5555dfecf96Smrg    ispell.buflen = 0;
5565dfecf96Smrg
5575dfecf96Smrg    if ((tmp = strchr(ispell.sendbuf, '\n')) != NULL)
5585dfecf96Smrg	*tmp = '\0';
5595dfecf96Smrg
5605dfecf96Smrg    switch (ispell.buf[0]) {
5615dfecf96Smrg	case '&':	/* MISS */
5625dfecf96Smrg	case '?':	/* GUESS */
5635dfecf96Smrg	    str = strchr(&ispell.buf[2], ' ');
5645dfecf96Smrg	    if (!ispell.checkit) {
5655dfecf96Smrg		*str = '\0';
5665dfecf96Smrg		XtSetArg(args[0], XtNlabel, &ispell.buf[2]);
5675dfecf96Smrg		XtSetValues(ispell.word, args, 1);
5685dfecf96Smrg	    }
5695dfecf96Smrg	    ++str;
5705dfecf96Smrg	    list = NULL;
5715dfecf96Smrg	    str = strchr(str, ':') + 1;
5725dfecf96Smrg	    for (i = 0; ; i++) {
5735dfecf96Smrg		end = strchr(str, ',');
5745dfecf96Smrg		if (end)	*end = '\0';
5755dfecf96Smrg		if ((i % 16) == 0)
5765dfecf96Smrg		    list = (char**)XtRealloc((char*)list, (i + 16) * sizeof(char*));
5775dfecf96Smrg		tmp = word;
5785dfecf96Smrg		for (j = 1; j < sizeof(word) && str[j]; j++) {
5795dfecf96Smrg		    if (str[j] == '+')
5805dfecf96Smrg			continue;
5815dfecf96Smrg		    else if (str[j] == '-' && str[j+1] != '-' && str[j-1] != '-') {
5825dfecf96Smrg			char *p, string[256];
5835dfecf96Smrg			int k, l;
5845dfecf96Smrg
5855dfecf96Smrg			for (l = 0, k = j + 1; str[k] != '+' && str[k] != '-'
5865dfecf96Smrg			     && str[k] && l < sizeof(string) - 1; k++, l++)
5875dfecf96Smrg			    string[l] = str[k];
5885dfecf96Smrg			string[l] = '\0';
5895dfecf96Smrg			*tmp = '\0';
5905dfecf96Smrg			if (l && (p = strstr(word, string)) != NULL) {
5915dfecf96Smrg			    char *sav = p;
5925dfecf96Smrg
5935dfecf96Smrg			    while ((p = strstr(p + l, string)) != NULL)
5945dfecf96Smrg				sav = p;
5955dfecf96Smrg			    p = sav;
5965dfecf96Smrg			    if (strcmp(p, string) == 0) {
5975dfecf96Smrg				tmp = p;
5985dfecf96Smrg				j = k - 1;
5995dfecf96Smrg			    }
6005dfecf96Smrg			    else
6015dfecf96Smrg				*tmp++ = '-';
6025dfecf96Smrg			}
6035dfecf96Smrg			else
6045dfecf96Smrg			    *tmp++ = '-';
6055dfecf96Smrg		    }
6065dfecf96Smrg		    else
6075dfecf96Smrg			*tmp++ = str[j];
6085dfecf96Smrg		}
6095dfecf96Smrg		*tmp = '\0';
6105dfecf96Smrg		list[i] = XtNewString(word);
6115dfecf96Smrg
6125dfecf96Smrg		if (end)	str = end + 1;
6135dfecf96Smrg		else		break;
6145dfecf96Smrg	    }
6155dfecf96Smrg	    len = i + 1;
6165dfecf96Smrg
6175dfecf96Smrg	    XtSetArg(args[0], XtNlist, &old_list);
6185dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, &old_len);
6195dfecf96Smrg	    XtGetValues(ispell.list, args, 2);
6205dfecf96Smrg
6215dfecf96Smrg	    ispell.item = NULL;
6225dfecf96Smrg	    if ((str = IspellReplacedWord(&ispell.buf[2], NULL)) != NULL)
6235dfecf96Smrg		for (i = 0; i < len; i++) {
6245dfecf96Smrg		    if (strcmp(list[i], str) == 0) {
6255dfecf96Smrg			ispell.item = list[i];
6265dfecf96Smrg			break;
6275dfecf96Smrg		    }
6285dfecf96Smrg		}
6295dfecf96Smrg	    else
6305dfecf96Smrg		ispell.item = list[i = 0];
6315dfecf96Smrg	    if (!ispell.item) {
6325dfecf96Smrg		list = (char**)XtRealloc((char*)list, (len + 1) * sizeof(char*));
6335dfecf96Smrg		ispell.item = list[i] = XtNewString(str);
6345dfecf96Smrg		++len;
6355dfecf96Smrg	    }
6365dfecf96Smrg
6375dfecf96Smrg	    XtSetArg(args[0], XtNlist, list);
6385dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, len);
6395dfecf96Smrg	    XtSetValues(ispell.list, args, 2);
6405dfecf96Smrg
6415dfecf96Smrg	    XtSetSensitive(ispell.list, True);
6425dfecf96Smrg	    if (!ispell.checkit)
6435dfecf96Smrg		XawListHighlight(ispell.list, i);
6445dfecf96Smrg
6455dfecf96Smrg	    if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
6465dfecf96Smrg		while (--old_len > -1)
6475dfecf96Smrg		    XtFree(old_list[old_len]);
6485dfecf96Smrg		XtFree((char*)old_list);
6495dfecf96Smrg	    }
6505dfecf96Smrg
6515dfecf96Smrg	    if (!ispell.checkit) {
6525dfecf96Smrg		XtSetArg(args[0], XtNstring, ispell.item);
6535dfecf96Smrg		XtSetValues(ispell.text, args, 1);
6545dfecf96Smrg		IspellSetSelection(ispell.left, ispell.right);
6555dfecf96Smrg		if (ispell.repeat)
6565dfecf96Smrg		    IspellSetRepeated(ispell.repeat = False);
6575dfecf96Smrg	    }
6585dfecf96Smrg
6595dfecf96Smrg	    IspellSetStatus(ispell.buf[0] == '?' ?
6605dfecf96Smrg			    ispell.guess_label : ispell.miss_label);
6615dfecf96Smrg	    ispell.undo_terse_mode = ispell.terse_mode;
6625dfecf96Smrg	    ispell.format_mode = ispell.format_info->value;
6635dfecf96Smrg	    ispell.lock = True;
6645dfecf96Smrg	    break;
6655dfecf96Smrg	case '#':	/* NONE */
6665dfecf96Smrg	case '-':	/* COMPOUND */
6675dfecf96Smrg	case '+':	/* ROOT */
6685dfecf96Smrg	check_label:
6695dfecf96Smrg	    str = &ispell.sendbuf[1];
6705dfecf96Smrg	    if (!ispell.checkit) {
6715dfecf96Smrg		XtSetArg(args[0], XtNlabel, str);
6725dfecf96Smrg		XtSetValues(ispell.word, args, 1);
6735dfecf96Smrg	    }
6745dfecf96Smrg
6755dfecf96Smrg	    XtSetArg(args[0], XtNlist, &old_list);
6765dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, &old_len);
6775dfecf96Smrg	    XtGetValues(ispell.list, args, 2);
6785dfecf96Smrg	    ispell.item = NULL;
6795dfecf96Smrg
6805dfecf96Smrg	    list = (char**)XtMalloc(sizeof(char**));
6815dfecf96Smrg	    if ((tmp = IspellReplacedWord(str, NULL)) != NULL)
6825dfecf96Smrg		str = tmp;
6835dfecf96Smrg	    if (tmp == NULL && ispell.buf[0] == '#')
6845dfecf96Smrg		list[0] = XtNewString("");
6855dfecf96Smrg	    else
6865dfecf96Smrg		list[0] = XtNewString(str);
6875dfecf96Smrg
6885dfecf96Smrg	    XtSetArg(args[0], XtNlist, list);
6895dfecf96Smrg	    XtSetArg(args[1], XtNnumberStrings, 1);
6905dfecf96Smrg	    XtSetValues(ispell.list, args, 2);
6915dfecf96Smrg
6925dfecf96Smrg	    if (tmp == NULL && ispell.buf[0] == '#') {
6935dfecf96Smrg		XawListUnhighlight(ispell.list);
6945dfecf96Smrg		XtSetSensitive(ispell.list, False);
6955dfecf96Smrg	    }
6965dfecf96Smrg	    else {
6975dfecf96Smrg		XtSetSensitive(ispell.list, True);
6985dfecf96Smrg		if (!ispell.checkit)
6995dfecf96Smrg		    XawListHighlight(ispell.list, 0);
7005dfecf96Smrg	    }
7015dfecf96Smrg	    if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
7025dfecf96Smrg		while (--old_len > -1)
7035dfecf96Smrg		    XtFree(old_list[old_len]);
7045dfecf96Smrg		XtFree((char*)old_list);
7055dfecf96Smrg	    }
7065dfecf96Smrg
7075dfecf96Smrg	    if (!ispell.checkit) {
7085dfecf96Smrg		XtSetArg(args[0], XtNstring, str);
7095dfecf96Smrg		XtSetValues(ispell.text, args, 1);
7105dfecf96Smrg		IspellSetSelection(ispell.left, ispell.right);
7115dfecf96Smrg		if (ispell.repeat)
7125dfecf96Smrg		    IspellSetRepeated(ispell.repeat = False);
7135dfecf96Smrg	    }
7145dfecf96Smrg
7155dfecf96Smrg	    ispell.undo_terse_mode = ispell.terse_mode;
7165dfecf96Smrg	    ispell.format_mode = ispell.format_info->value;
7175dfecf96Smrg	    ispell.lock = True;
7185dfecf96Smrg	    if (ispell.buf[0] == '+') {
7195dfecf96Smrg		if ((tmp = strchr(&ispell.buf[2], '\n')) != NULL)
7205dfecf96Smrg		    *tmp = '\0';
7215dfecf96Smrg		XmuSnprintf(word, sizeof(word), "%s %s",
7225dfecf96Smrg			    ispell.root_label, &ispell.buf[2]);
7235dfecf96Smrg		IspellSetStatus(word);
7245dfecf96Smrg	    }
7255dfecf96Smrg	    else
7265dfecf96Smrg		IspellSetStatus(ispell.buf[0] == '#' ? ispell.none_label :
7275dfecf96Smrg				ispell.buf[0] == '-' ? ispell.compound_label :
7285dfecf96Smrg				ispell.ok_label);
7295dfecf96Smrg	    break;
7305dfecf96Smrg	case '*':	/* OK */
7315dfecf96Smrg	case '\0':	/* when running in terse mode */
7325dfecf96Smrg	    if (!ispell.checkit)
7335dfecf96Smrg		(void)IspellIgnoredWord(&ispell.sendbuf[1], ADD, 0);
7345dfecf96Smrg	    else
7355dfecf96Smrg		goto check_label;
7365dfecf96Smrg	    ispell.lock = False;
7375dfecf96Smrg	    break;
7385dfecf96Smrg	case '@':	/* Ispell banner */
7395dfecf96Smrg	    /* it only happens when the dictionary is changed */
7405dfecf96Smrg	    if (!ispell.repeat) {
7415dfecf96Smrg		XawTextPosition left, right;
7425dfecf96Smrg
7435dfecf96Smrg		ispell.stat = SEND;
7445dfecf96Smrg		while (IspellSend() == 0)
7455dfecf96Smrg		    ;
7465dfecf96Smrg		/* word chars may have changed */
7475dfecf96Smrg		XawTextGetSelectionPos(ispell.ascii, &left, &right);
7485dfecf96Smrg		if (left != ispell.left || right != ispell.right) {
7495dfecf96Smrg		    XtSetArg(args[0], XtNstring, &ispell.sendbuf[1]);
7505dfecf96Smrg		    XtSetValues(ispell.text, args, 1);
7515dfecf96Smrg		    IspellSetSelection(ispell.left, ispell.right);
7525dfecf96Smrg		}
7535dfecf96Smrg		ispell.checkit = True;
7545dfecf96Smrg	    }
7555dfecf96Smrg	    else {
7565dfecf96Smrg		IspellSetStatus(ispell.repeat_label);
7575dfecf96Smrg		ispell.undo_terse_mode = ispell.terse_mode;
7585dfecf96Smrg		ispell.format_mode = ispell.format_info->value;
7595dfecf96Smrg		ispell.lock = True;
7605dfecf96Smrg		return (True);
7615dfecf96Smrg	    }
7625dfecf96Smrg	    break;
7635dfecf96Smrg	default:
7645dfecf96Smrg	    fprintf(stderr, "Unknown ispell command '%c'\n", ispell.buf[0]);
7655dfecf96Smrg	    return (False);
7665dfecf96Smrg    }
7675dfecf96Smrg
7685dfecf96Smrg    if (!ispell.lock && !ispell.checkit) {
7695dfecf96Smrg	ispell.stat = SEND;
7705dfecf96Smrg	while (IspellSend() == 0)
7715dfecf96Smrg	    ;
7725dfecf96Smrg    }
7735dfecf96Smrg
7745dfecf96Smrg    return (True);
7755dfecf96Smrg}
7765dfecf96Smrg
7775dfecf96Smrgstatic int
7785dfecf96SmrgIspellConvertHtmlAmp(char *buf)
7795dfecf96Smrg{
7805dfecf96Smrg    int len, ch = '?';
7815dfecf96Smrg
7825dfecf96Smrg    /* this function is static, so I can do it */
7835dfecf96Smrg    *strchr(++buf, ';') = '\0';
7845dfecf96Smrg
7855dfecf96Smrg    len = strlen(buf);
7865dfecf96Smrg    if (len == 0)
7875dfecf96Smrg	return ('&');
7885dfecf96Smrg    if (len > 1) {
7895dfecf96Smrg	if (strcasecmp(&buf[1], "lt") == 0)
7905dfecf96Smrg	    ch = '<';
7915dfecf96Smrg	else if (strcasecmp(&buf[1], "gt") == 0)
7925dfecf96Smrg	    ch = '>';
7935dfecf96Smrg	else if (strcasecmp(&buf[1], "nbsp") == 0)
7945dfecf96Smrg	    ch = ' ';
7955dfecf96Smrg	else if (strcasecmp(&buf[1], "amp") == 0)
7965dfecf96Smrg	    ch = '&';
7975dfecf96Smrg	else if (strcasecmp(&buf[1], "quot") == 0)
7985dfecf96Smrg	    ch = '"';
7995dfecf96Smrg	else if (*buf == '#') {
8005dfecf96Smrg	    char *tmp;
8015dfecf96Smrg
8025dfecf96Smrg	    if (len == 1)
8035dfecf96Smrg		return ('?');
8045dfecf96Smrg	    ch = strtol(&buf[1], &tmp, 10);
8055dfecf96Smrg	    if (*tmp)
8065dfecf96Smrg		fprintf(stderr, "Warning: bad html interpreting '&#' mark.\n");
8075dfecf96Smrg	}
8085dfecf96Smrg	else if (strcmp(&buf[1], "acute") == 0) {
8095dfecf96Smrg	    switch (*buf) {
8105dfecf96Smrg		case 'a': ch = 0xe1; break;
8115dfecf96Smrg		case 'e': ch = 0xe9; break;
8125dfecf96Smrg		case 'i': ch = 0xed; break;
8135dfecf96Smrg		case 'o': ch = 0xf3; break;
8145dfecf96Smrg		case 'u': ch = 0xfa; break;
8155dfecf96Smrg		case 'A': ch = 0xc1; break;
8165dfecf96Smrg		case 'E': ch = 0xc9; break;
8175dfecf96Smrg		case 'I': ch = 0xcd; break;
8185dfecf96Smrg		case 'O': ch = 0xd3; break;
8195dfecf96Smrg		case 'U': ch = 0xda; break;
8205dfecf96Smrg	    }
8215dfecf96Smrg	}
8225dfecf96Smrg	else if (strcmp(&buf[1], "grave") == 0) {
8235dfecf96Smrg	    switch (*buf) {
8245dfecf96Smrg		case 'a': ch = 0xe0; break;
8255dfecf96Smrg		case 'e': ch = 0xe8; break;
8265dfecf96Smrg		case 'i': ch = 0xec; break;
8275dfecf96Smrg		case 'o': ch = 0xf2; break;
8285dfecf96Smrg		case 'u': ch = 0xf9; break;
8295dfecf96Smrg		case 'A': ch = 0xc0; break;
8305dfecf96Smrg		case 'E': ch = 0xc8; break;
8315dfecf96Smrg		case 'I': ch = 0xcc; break;
8325dfecf96Smrg		case 'O': ch = 0xd2; break;
8335dfecf96Smrg		case 'U': ch = 0xd9; break;
8345dfecf96Smrg	    }
8355dfecf96Smrg	}
8365dfecf96Smrg	else if (strcmp(&buf[1], "tilde") == 0) {
8375dfecf96Smrg	    switch (*buf) {
8385dfecf96Smrg		case 'a': ch = 0xe3; break;
8395dfecf96Smrg		case 'o': ch = 0xf5; break;
8405dfecf96Smrg		case 'n': ch = 0xf1; break;
8415dfecf96Smrg		case 'A': ch = 0xe3; break;
8425dfecf96Smrg		case 'O': ch = 0xd5; break;
8435dfecf96Smrg		case 'N': ch = 0xd1; break;
8445dfecf96Smrg	    }
8455dfecf96Smrg	}
8465dfecf96Smrg	else if (strcmp(&buf[1], "circ") == 0) {
8475dfecf96Smrg	    switch (*buf) {
8485dfecf96Smrg		case 'a': ch = 0xe2; break;
8495dfecf96Smrg		case 'e': ch = 0xea; break;
8505dfecf96Smrg		case 'i': ch = 0xee; break;
8515dfecf96Smrg		case 'o': ch = 0xf4; break;
8525dfecf96Smrg		case 'u': ch = 0xfb; break;
8535dfecf96Smrg		case 'A': ch = 0xc2; break;
8545dfecf96Smrg		case 'E': ch = 0xca; break;
8555dfecf96Smrg		case 'I': ch = 0xce; break;
8565dfecf96Smrg		case 'O': ch = 0xd4; break;
8575dfecf96Smrg		case 'U': ch = 0xdb; break;
8585dfecf96Smrg	    }
8595dfecf96Smrg	}
8605dfecf96Smrg	else if (strcmp(&buf[1], "cedil") == 0) {
8615dfecf96Smrg	    switch (*buf) {
8625dfecf96Smrg		case 'c': ch = 0xe7; break;
8635dfecf96Smrg		case 'C': ch = 0xc7; break;
8645dfecf96Smrg	    }
8655dfecf96Smrg	}
8665dfecf96Smrg	/* add more cases here */
8675dfecf96Smrg    }
8685dfecf96Smrg
8695dfecf96Smrg    return (ch);
8705dfecf96Smrg}
8715dfecf96Smrg
8725dfecf96Smrg/*ARGSUSED*/
8735dfecf96Smrgstatic int
8745dfecf96SmrgIspellSend(void)
8755dfecf96Smrg{
8765dfecf96Smrg    XawTextPosition position, old_left, pos;
8775dfecf96Smrg    XawTextBlock block;
8785dfecf96Smrg    int i, len, spaces, nls;
8795dfecf96Smrg    Bool nl, html, inside_html;
8805dfecf96Smrg    char ampbuf[32];
8815dfecf96Smrg    int amplen;
8825dfecf96Smrg
8835dfecf96Smrg    if (ispell.lock || ispell.stat != SEND)
8845dfecf96Smrg	return (-1);
8855dfecf96Smrg
8865dfecf96Smrg    len = 1;
8875dfecf96Smrg    ispell.sendbuf[0] = '^';	/* don't evaluate following characters as commands */
8885dfecf96Smrg
8895dfecf96Smrg    spaces = nls = 0;
8905dfecf96Smrg
8915dfecf96Smrg    html = ispell.format_info->value == HTML;
8925dfecf96Smrg    inside_html = False;
8935dfecf96Smrg    amplen = 0;
8945dfecf96Smrg
8955dfecf96Smrg    /* skip non word characters */
8965dfecf96Smrg    pos = position = ispell.right;
8975dfecf96Smrg    nl = False;
8985dfecf96Smrg    while (1) {
8995dfecf96Smrg	Bool done = False;
9005dfecf96Smrg	char mb[sizeof(wchar_t)];
9015dfecf96Smrg
9025dfecf96Smrg	retry_html_space:
9035dfecf96Smrg	position = XawTextSourceRead(ispell.source, position,
9045dfecf96Smrg				     &block, BUFSIZ);
9055dfecf96Smrg	if (block.length == 0) {	/* end of file */
9065dfecf96Smrg	    ispell.stat = 0;
9075dfecf96Smrg	    ispell.lock = True;
9085dfecf96Smrg	    XawTextSetInsertionPoint(ispell.ascii, ispell.right);
9095dfecf96Smrg	    XawTextUnsetSelection(ispell.ascii);
9105dfecf96Smrg	    IspellSetSensitive(False);
9115dfecf96Smrg	    IspellSetStatus(ispell.eof_label);
9125dfecf96Smrg	    return (-1);
9135dfecf96Smrg	}
9145dfecf96Smrg	for (i = 0; i < block.length; i++) {
915f14f4646Smrg	    if (international)
916f14f4646Smrg		wctomb(mb, ((wchar_t*)block.ptr)[i]);
917f14f4646Smrg	    else
918f14f4646Smrg		mb[0] = block.ptr[i];
9195dfecf96Smrg	    if (amplen) {
9205dfecf96Smrg		if (amplen + 2 >= sizeof(ampbuf)) {
9215dfecf96Smrg		    if (!ispell.terse_mode)
9225dfecf96Smrg			fprintf(stderr, "Warning: error interpreting '&' mark.\n");
9235dfecf96Smrg		    amplen = 0;
9245dfecf96Smrg		    position = pos + 1;
9255dfecf96Smrg		    goto retry_html_space;
9265dfecf96Smrg		}
9275dfecf96Smrg		else if ((ampbuf[amplen++] = *mb) == ';') {
9285dfecf96Smrg		    int ch;
9295dfecf96Smrg
9305dfecf96Smrg		    ampbuf[amplen] = '\0';
9315dfecf96Smrg		    ch = IspellConvertHtmlAmp(ampbuf);
9325dfecf96Smrg		    amplen = 0;
9335dfecf96Smrg		    if (isalpha(ch) ||
9345dfecf96Smrg			(ch && strchr(ispell.wchars, ch))) {
9355dfecf96Smrg			/* interpret it again */
9365dfecf96Smrg			ispell.right = pos;
9375dfecf96Smrg			i = 0;
9385dfecf96Smrg			done = True;
9395dfecf96Smrg			break;
9405dfecf96Smrg		    }
9415dfecf96Smrg		    else if ((ch == '\n' || isspace(ch)) && spaces >= 0)
9425dfecf96Smrg			++spaces;
9435dfecf96Smrg		    else
9445dfecf96Smrg			spaces = -1;
9455dfecf96Smrg		}
9465dfecf96Smrg	    }
9475dfecf96Smrg	    else if (html && *mb == '&') {
9485dfecf96Smrg		ampbuf[amplen++] = *mb;
9495dfecf96Smrg		pos = block.firstPos + i;
9505dfecf96Smrg		continue;
9515dfecf96Smrg	    }
9525dfecf96Smrg	    else if ((!html || !inside_html) && (isalpha(*mb) ||
9535dfecf96Smrg		(*mb && strchr(ispell.wchars, *mb)))) {
9545dfecf96Smrg		done = True;
9555dfecf96Smrg		break;
9565dfecf96Smrg	    }
9575dfecf96Smrg	    else if (!html && *mb == '\n') {
9585dfecf96Smrg		nl = True;
9595dfecf96Smrg		if (++nls > 1 && (!html || !inside_html))
9605dfecf96Smrg		    spaces = -1;
9615dfecf96Smrg		else if (spaces >= 0)
9625dfecf96Smrg		    ++spaces;
9635dfecf96Smrg	    }
9645dfecf96Smrg	    else if (nl) {
9655dfecf96Smrg		nl = False;
9665dfecf96Smrg		if (*mb && strchr(ispell.skip, *mb)) {
9675dfecf96Smrg		    position = ispell.right =
9685dfecf96Smrg			XawTextSourceScan(ispell.source, ispell.right + i,
9695dfecf96Smrg					  XawstEOL, XawsdRight, 1, False);
9705dfecf96Smrg		    i = 0;
9715dfecf96Smrg		    break;
9725dfecf96Smrg		}
9735dfecf96Smrg		else if (spaces >= 0 && isspace(*mb))
9745dfecf96Smrg		    ++spaces;
9755dfecf96Smrg		else
9765dfecf96Smrg		    spaces = -1;
9775dfecf96Smrg	    }
9785dfecf96Smrg	    else if (html && inside_html) {
9795dfecf96Smrg		if (*mb == '>')
9805dfecf96Smrg		    inside_html = False;
9815dfecf96Smrg	    }
9825dfecf96Smrg	    else if (html && *mb == '<')
9835dfecf96Smrg		inside_html = True;
9845dfecf96Smrg	    else if (spaces >= 0 && (isspace(*mb) || (html && *mb == '\n')))
9855dfecf96Smrg		++spaces;
9865dfecf96Smrg	    else
9875dfecf96Smrg		spaces = -1;
9885dfecf96Smrg	}
9895dfecf96Smrg
9905dfecf96Smrg	ispell.right += i;
9915dfecf96Smrg	if (done)
9925dfecf96Smrg	    break;
9935dfecf96Smrg    }
9945dfecf96Smrg
9955dfecf96Smrg    old_left = ispell.left;
9965dfecf96Smrg
9975dfecf96Smrg    /* read a word */
9985dfecf96Smrg    position = ispell.left = ispell.right;
9995dfecf96Smrg    while (1) {
10005dfecf96Smrg	Bool done = False;
10015dfecf96Smrg	char mb[sizeof(wchar_t)];
10025dfecf96Smrg
10035dfecf96Smrg	retry_html_word:
10045dfecf96Smrg	position = XawTextSourceRead(ispell.source, position,
10055dfecf96Smrg				     &block, BUFSIZ);
10065dfecf96Smrg	if (block.length == 0 && len == 1) {	/* end of file */
10075dfecf96Smrg	    ispell.stat = 0;
10085dfecf96Smrg	    ispell.lock = True;
10095dfecf96Smrg	    XawTextSetInsertionPoint(ispell.ascii, ispell.right);
10105dfecf96Smrg	    XawTextUnsetSelection(ispell.ascii);
10115dfecf96Smrg	    IspellSetSensitive(False);
10125dfecf96Smrg	    IspellSetStatus(ispell.eof_label);
10135dfecf96Smrg	    return (-1);
10145dfecf96Smrg	}
10155dfecf96Smrg	for (i = 0; i < block.length; i++) {
1016f14f4646Smrg	    if (international)
1017f14f4646Smrg		wctomb(mb, ((wchar_t*)block.ptr)[i]);
1018f14f4646Smrg	    else
1019f14f4646Smrg		mb[0] = block.ptr[i];
10205dfecf96Smrg	    if (amplen) {
10215dfecf96Smrg		if (amplen + 2 >= sizeof(ampbuf)) {
10225dfecf96Smrg		    if (!ispell.terse_mode)
10235dfecf96Smrg			fprintf(stderr, "Warning: error interpreting '&' mark.\n");
10245dfecf96Smrg		    amplen = 0;
10255dfecf96Smrg		    position = pos + 1;
10265dfecf96Smrg		    if (strchr(ispell.wchars, '&')) {
10275dfecf96Smrg			if (len + 1 >= sizeof(ispell.sendbuf) - 1) {
10285dfecf96Smrg			    done = True;
10295dfecf96Smrg			    fprintf(stderr, "Warning: word is too large!\n");
10305dfecf96Smrg			    break;
10315dfecf96Smrg			}
10325dfecf96Smrg			ispell.sendbuf[len++] = '&';
10335dfecf96Smrg			goto retry_html_word;
10345dfecf96Smrg		    }
10355dfecf96Smrg		    else {
10365dfecf96Smrg			ispell.right = position;
10375dfecf96Smrg			i = 0;
10385dfecf96Smrg			done = True;
10395dfecf96Smrg			break;
10405dfecf96Smrg		    }
10415dfecf96Smrg		}
10425dfecf96Smrg		else if ((ampbuf[amplen++] = *mb) == ';') {
10435dfecf96Smrg		    int ch;
10445dfecf96Smrg
10455dfecf96Smrg		    ampbuf[amplen] = '\0';
10465dfecf96Smrg		    ch = IspellConvertHtmlAmp(ampbuf);
10475dfecf96Smrg		    amplen = 0;
10485dfecf96Smrg		    if (!isalpha(ch) &&
10495dfecf96Smrg			(!ch || !strchr(ispell.wchars, ch))) {
10505dfecf96Smrg			ispell.right = pos;
10515dfecf96Smrg			i = 0;
10525dfecf96Smrg			done = True;
10535dfecf96Smrg			break;
10545dfecf96Smrg		    }
10555dfecf96Smrg		    *mb = ch;
10565dfecf96Smrg		}
10575dfecf96Smrg		else
10585dfecf96Smrg		    continue;
10595dfecf96Smrg	    }
10605dfecf96Smrg	    else if (html && *mb == '&') {
10615dfecf96Smrg		ampbuf[amplen++] = *mb;
10625dfecf96Smrg		pos = block.firstPos + i;
10635dfecf96Smrg		continue;
10645dfecf96Smrg	    }
10655dfecf96Smrg	    else if (!isalpha(*mb) && (!*mb || !strchr(ispell.wchars, *mb))) {
10665dfecf96Smrg		done = True;
10675dfecf96Smrg		break;
10685dfecf96Smrg	    }
10695dfecf96Smrg	    ispell.sendbuf[len] = *mb;
10705dfecf96Smrg	    if (++len >= sizeof(ispell.sendbuf) - 1) {
10715dfecf96Smrg		done = True;
10725dfecf96Smrg		fprintf(stderr, "Warning: word is too large!\n");
10735dfecf96Smrg		break;
10745dfecf96Smrg	    }
10755dfecf96Smrg	}
10765dfecf96Smrg	ispell.right += i;
10775dfecf96Smrg	if (done || block.length == 0)
10785dfecf96Smrg	    break;
10795dfecf96Smrg    }
10805dfecf96Smrg
10815dfecf96Smrg    ispell.sendbuf[len] = '\0';
10825dfecf96Smrg
10835dfecf96Smrg    if (spaces > 0 && spaces <= 32 && strcmp(ispell.sendbuf, ispell.sentbuf) == 0) {
10845dfecf96Smrg	Arg args[2];
10855dfecf96Smrg	int old_len;
10865dfecf96Smrg	char **list, **old_list;
10875dfecf96Smrg	char label[sizeof(ispell.sendbuf) + sizeof(ispell.sentbuf) + 32];
10885dfecf96Smrg
10895dfecf96Smrg	strcpy(label, &ispell.sendbuf[1]);
10905dfecf96Smrg	for (i = 0; i < spaces; i++)
10915dfecf96Smrg	    label[len + i - 1] = ' ';
10925dfecf96Smrg	strcpy(&label[len + i - 1], &ispell.sendbuf[1]);
10935dfecf96Smrg	XtSetArg(args[0], XtNlabel, label);
10945dfecf96Smrg	XtSetValues(ispell.word, args, 1);
10955dfecf96Smrg
10965dfecf96Smrg	XtSetArg(args[0], XtNstring, &ispell.sendbuf[1]);
10975dfecf96Smrg	XtSetValues(ispell.text, args, 1);
10985dfecf96Smrg
10995dfecf96Smrg	XtSetArg(args[0], XtNlist, &old_list);
11005dfecf96Smrg	XtSetArg(args[1], XtNnumberStrings, &old_len);
11015dfecf96Smrg	XtGetValues(ispell.list, args, 2);
11025dfecf96Smrg	list = (char**)XtMalloc(sizeof(char**));
11035dfecf96Smrg	list[0] = XtNewString(&ispell.sendbuf[1]);
11045dfecf96Smrg	XtSetArg(args[0], XtNlist, list);
11055dfecf96Smrg	XtSetArg(args[1], XtNnumberStrings, 1);
11065dfecf96Smrg	XtSetValues(ispell.list, args, 2);
11075dfecf96Smrg	XtSetSensitive(ispell.list, True);
11085dfecf96Smrg	XawListHighlight(ispell.list, 0);
11095dfecf96Smrg	if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
11105dfecf96Smrg	    while (--old_len > -1)
11115dfecf96Smrg		XtFree(old_list[old_len]);
11125dfecf96Smrg	    XtFree((char*)old_list);
11135dfecf96Smrg	}
11145dfecf96Smrg
11155dfecf96Smrg	IspellSetRepeated(True);
11165dfecf96Smrg	IspellSetSelection(old_left, ispell.right);
11175dfecf96Smrg	IspellSetStatus(ispell.repeat_label);
11185dfecf96Smrg	ispell.repeat = ispell.lock = True;
11195dfecf96Smrg
11205dfecf96Smrg	return (1);
11215dfecf96Smrg    }
11225dfecf96Smrg    strcpy(ispell.sentbuf, ispell.sendbuf);
11235dfecf96Smrg
11245dfecf96Smrg    if (len <= 2 || IspellIgnoredWord(&ispell.sendbuf[1], CHECK, 0))
11255dfecf96Smrg	return (0);
11265dfecf96Smrg
11275dfecf96Smrg    ispell.sendbuf[len++] = '\n';
11285dfecf96Smrg
11295dfecf96Smrg    write(ispell.ofd[1], ispell.sendbuf, len);
11305dfecf96Smrg
11315dfecf96Smrg    ispell.stat = RECEIVE;
11325dfecf96Smrg
11335dfecf96Smrg    return (1);
11345dfecf96Smrg}
11355dfecf96Smrg
11365dfecf96Smrg/*ARGSUSED*/
11375dfecf96Smrgstatic void
11385dfecf96SmrgIspellInputCallback(XtPointer closure, int *source, XtInputId *id)
11395dfecf96Smrg{
11405dfecf96Smrg    if (ispell.right < 0) {
11415dfecf96Smrg	int len;
11425dfecf96Smrg	char buf[1024];
11435dfecf96Smrg
11445dfecf96Smrg	ispell.right = XawTextGetInsertionPoint(ispell.ascii);
11455dfecf96Smrg	ispell.right = XawTextSourceScan(ispell.source, ispell.right,
11465dfecf96Smrg					      XawstEOL, XawsdLeft, 1, True);
11475dfecf96Smrg	len = read(ispell.ifd[0], buf, sizeof(buf));
11485dfecf96Smrg	if (strncmp(buf, "@(#)", 4) == 0) {
11495dfecf96Smrg	    Arg args[1];
11505dfecf96Smrg
11515dfecf96Smrg	    buf[len - 1] = '\0';
11525dfecf96Smrg	    XtSetArg(args[0], XtNtitle, &buf[5]);
11535dfecf96Smrg	    XtSetValues(ispell.shell, args, 1);
11545dfecf96Smrg	}
11555dfecf96Smrg	else
11565dfecf96Smrg	    fprintf(stderr, "Error: is ispell talking with me?\n");
11575dfecf96Smrg	IspellSetTerseMode(ispell.terse_mode);
11585dfecf96Smrg	while (IspellSend() == 0)
11595dfecf96Smrg	    ;
11605dfecf96Smrg    }
11615dfecf96Smrg    else if (ispell.source)
11625dfecf96Smrg	IspellReceive();
11635dfecf96Smrg}
11645dfecf96Smrg
11655dfecf96Smrg/*ARGSUSED*/
11665dfecf96Smrgvoid
11675dfecf96SmrgIspellCallback(Widget w, XtPointer client_data, XtPointer call_data)
11685dfecf96Smrg{
11695dfecf96Smrg    Cardinal zero = 0;
11705dfecf96Smrg
11715dfecf96Smrg    IspellAction(textwindow, NULL, NULL, &zero);
11725dfecf96Smrg}
11735dfecf96Smrg
11745dfecf96Smrg/*ARGSUSED*/
11755dfecf96Smrgvoid
11765dfecf96SmrgIspellAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
11775dfecf96Smrg{
11785dfecf96Smrg    Arg args[3];
11795dfecf96Smrg    Cardinal num_args;
11805dfecf96Smrg    char **strs, **list;
11815dfecf96Smrg    int n_strs;
11825dfecf96Smrg    Bool first_time = InitIspell();
11835dfecf96Smrg
11845dfecf96Smrg    if (*num_params == 1 && (params[0][0] == 'e' || params[0][0] == 'E')) {
11855dfecf96Smrg	PopdownIspell(w, (XtPointer)True, NULL);
11865dfecf96Smrg	return;
11875dfecf96Smrg    }
11885dfecf96Smrg
11895dfecf96Smrg    if (!XtIsSubclass(w, textWidgetClass) || ispell.source) {
11905dfecf96Smrg	Feep();
11915dfecf96Smrg	return;
11925dfecf96Smrg    }
11935dfecf96Smrg
11945dfecf96Smrg    ispell.source = XawTextGetSource(ispell.ascii = w);
11955dfecf96Smrg
11965dfecf96Smrg    if (first_time) {
11975dfecf96Smrg	/* let the user choose the better position for the ispell window */
11985dfecf96Smrg	Dimension width, height, b_width;
11995dfecf96Smrg	Position x, y, max_x, max_y;
12005dfecf96Smrg
12015dfecf96Smrg	x = y = -1;
12025dfecf96Smrg	if (event) {
12035dfecf96Smrg	    switch (event->type) {
12045dfecf96Smrg		case ButtonPress:
12055dfecf96Smrg		case ButtonRelease:
12065dfecf96Smrg		    x = event->xbutton.x_root;
12075dfecf96Smrg		    y = event->xbutton.y_root;
12085dfecf96Smrg		    break;
12095dfecf96Smrg		case KeyPress:
12105dfecf96Smrg		case KeyRelease:
12115dfecf96Smrg		    x = event->xkey.x_root;
12125dfecf96Smrg		    y = event->xkey.y_root;
12135dfecf96Smrg		    break;
12145dfecf96Smrg	    }
12155dfecf96Smrg	}
12165dfecf96Smrg	if (x < 0 || y < 0) {
12175dfecf96Smrg	    Window r, c;
12185dfecf96Smrg	    int rx, ry, wx, wy;
12195dfecf96Smrg	    unsigned mask;
12205dfecf96Smrg
12215dfecf96Smrg	    XQueryPointer(XtDisplay(ispell.shell), XtWindow(ispell.shell),
12225dfecf96Smrg			  &r, &c, &rx, &ry, &wx, &wy, &mask);
12235dfecf96Smrg	    x = rx;
12245dfecf96Smrg	    y = ry;
12255dfecf96Smrg	}
12265dfecf96Smrg
12275dfecf96Smrg	num_args = 0;
12285dfecf96Smrg	XtSetArg(args[num_args], XtNwidth, &width);		num_args++;
12295dfecf96Smrg	XtSetArg(args[num_args], XtNheight, &height);		num_args++;
12305dfecf96Smrg	XtSetArg(args[num_args], XtNborderWidth, &b_width);	num_args++;
12315dfecf96Smrg	XtGetValues(ispell.shell, args, num_args);
12325dfecf96Smrg
12335dfecf96Smrg	width += b_width << 1;
12345dfecf96Smrg	height += b_width << 1;
12355dfecf96Smrg
12365dfecf96Smrg	x -= (Position)(width >> 1);
12375dfecf96Smrg	if (x < 0)
12385dfecf96Smrg	    x = 0;
12395dfecf96Smrg	if (x > (max_x = (Position)(XtScreen(w)->width - width)))
12405dfecf96Smrg	    x = max_x;
12415dfecf96Smrg
12425dfecf96Smrg	y -= (Position)(height >> 1);
12435dfecf96Smrg	if (y < 0)
12445dfecf96Smrg	    y = 0;
12455dfecf96Smrg	if (y > (max_y = (Position)(XtScreen(w)->height - height)))
12465dfecf96Smrg	    y = max_y;
12475dfecf96Smrg
12485dfecf96Smrg	num_args = 0;
12495dfecf96Smrg	XtSetArg(args[num_args], XtNx, x);	num_args++;
12505dfecf96Smrg	XtSetArg(args[num_args], XtNy, y);	num_args++;
12515dfecf96Smrg	XtSetValues(ispell.shell, args, num_args);
12525dfecf96Smrg    }
12535dfecf96Smrg
12545dfecf96Smrg    if (ispell.repeat)
12555dfecf96Smrg	IspellSetRepeated(False);
12565dfecf96Smrg    ispell.lock = ispell.repeat = ispell.checkit = False;
12575dfecf96Smrg    ispell.stat = SEND;
12585dfecf96Smrg
12595dfecf96Smrg    IspellSetSensitive(True);
12605dfecf96Smrg    XtSetSensitive(ispell.undo, False);
12615dfecf96Smrg
12625dfecf96Smrg    XtSetArg(args[0], XtNlabel, "");
12635dfecf96Smrg    XtSetValues(ispell.word, args, 1);
12645dfecf96Smrg
12655dfecf96Smrg    XtSetArg(args[0], XtNstring, "");
12665dfecf96Smrg    XtSetValues(ispell.text, args, 1);
12675dfecf96Smrg
12685dfecf96Smrg    XtSetArg(args[0], XtNlist, &strs);
12695dfecf96Smrg    XtSetArg(args[1], XtNnumberStrings, &n_strs);
12705dfecf96Smrg    XtGetValues(ispell.list, args, 2);
12715dfecf96Smrg
12725dfecf96Smrg    list = (char**)XtMalloc(sizeof(char**));
12735dfecf96Smrg    list[0] = XtNewString("");
12745dfecf96Smrg    XtSetArg(args[0], XtNlist, list);
12755dfecf96Smrg    XtSetArg(args[1], XtNnumberStrings, 1);
12765dfecf96Smrg    XtSetValues(ispell.list, args, 2);
12775dfecf96Smrg
12785dfecf96Smrg    if (n_strs > 1 || (XtName(ispell.list) != strs[0])) {
12795dfecf96Smrg	while (--n_strs > -1)
12805dfecf96Smrg	    XtFree(strs[n_strs]);
12815dfecf96Smrg	XtFree((char*)strs);
12825dfecf96Smrg    }
12835dfecf96Smrg
12845dfecf96Smrg    IspellSetStatus(ispell.working_label);
12855dfecf96Smrg
12865dfecf96Smrg    if (!ispell.pid)
12875dfecf96Smrg	(void)IspellStartProcess();
12885dfecf96Smrg    else {
12895dfecf96Smrg	ispell.right = XawTextGetInsertionPoint(ispell.ascii);
12905dfecf96Smrg	ispell.right = XawTextSourceScan(ispell.source, ispell.right,
12915dfecf96Smrg					      XawstEOL, XawsdLeft, 1, True);
12925dfecf96Smrg	while (IspellSend() == 0)
12935dfecf96Smrg	    ;
12945dfecf96Smrg    }
12955dfecf96Smrg
12965dfecf96Smrg    XtPopup(ispell.shell, XtGrabExclusive);
12975dfecf96Smrg    XtSetKeyboardFocus(ispell.shell, ispell.text);
12985dfecf96Smrg}
12995dfecf96Smrg
13005dfecf96Smrgstatic Bool
13015dfecf96SmrgIspellStartProcess(void)
13025dfecf96Smrg{
13035dfecf96Smrg    if (!ispell.pid) {
13045dfecf96Smrg	int len;
1305f14f4646Smrg	char format[32];
1306f14f4646Smrg	static char *command;
13075dfecf96Smrg
13085dfecf96Smrg	ispell.source = XawTextGetSource(ispell.ascii);
13095dfecf96Smrg
1310f14f4646Smrg	if (command)
1311f14f4646Smrg	    XtFree(command);
1312f14f4646Smrg
1313f14f4646Smrg	strcpy(format, "%s -a");
1314f14f4646Smrg	len = strlen(ispell.cmd) + 4;
1315f14f4646Smrg	if (ispell.dictionary && *ispell.dictionary) {
1316f14f4646Smrg	    len += strlen(ispell.dictionary) + 6;
1317f14f4646Smrg	    strcat(format, " -d '%s'");
1318f14f4646Smrg	    if (ispell.wchars && *ispell.wchars) {
1319f14f4646Smrg		len += strlen(ispell.wchars + 6);
1320f14f4646Smrg		strcat(format, " -w '%s'");
1321f14f4646Smrg	    }
1322f14f4646Smrg	}
13235dfecf96Smrg	command = XtMalloc(len);
1324f14f4646Smrg	XmuSnprintf(command, len, format,
13255dfecf96Smrg		    ispell.cmd, ispell.dictionary, ispell.wchars);
13265dfecf96Smrg
13275dfecf96Smrg	pipe(ispell.ifd);
13285dfecf96Smrg	pipe(ispell.ofd);
13295dfecf96Smrg	if ((ispell.pid = fork()) == 0) {
13305dfecf96Smrg	    close(0);
13315dfecf96Smrg	    close(1);
13325dfecf96Smrg	    dup2(ispell.ofd[0], 0);
13335dfecf96Smrg	    dup2(ispell.ifd[1], 1);
13345dfecf96Smrg	    close(ispell.ofd[0]);
13355dfecf96Smrg	    close(ispell.ofd[1]);
13365dfecf96Smrg	    close(ispell.ifd[0]);
13375dfecf96Smrg	    close(ispell.ifd[1]);
1338f14f4646Smrg	    if (!international)
1339f14f4646Smrg		setlocale(LC_ALL, "ISO-8859-1");
1340f14f4646Smrg	    execl("/bin/sh", "sh", "-c", command, NULL);
13415dfecf96Smrg	    exit(-127);
13425dfecf96Smrg	}
13435dfecf96Smrg	else if (ispell.pid < 0) {
13445dfecf96Smrg	    fprintf(stderr, "Cannot fork\n");
13455dfecf96Smrg	    exit(1);
13465dfecf96Smrg	}
13475dfecf96Smrg	ispell.buf = XtMalloc(ispell.bufsiz = BUFSIZ);
13485dfecf96Smrg	ispell.right = -1;
13495dfecf96Smrg	ispell.id = XtAppAddInput(XtWidgetToApplicationContext(ispell.shell),
13505dfecf96Smrg				  ispell.ifd[0], (XtPointer)XtInputReadMask,
13515dfecf96Smrg				  IspellInputCallback, NULL);
13525dfecf96Smrg	fcntl(ispell.ifd[0], F_SETFL, O_NONBLOCK);
13535dfecf96Smrg    }
13545dfecf96Smrg    else
13555dfecf96Smrg	return (False);
13565dfecf96Smrg
13575dfecf96Smrg    return (True);
13585dfecf96Smrg}
13595dfecf96Smrg
13605dfecf96Smrg/*ARGSUSED*/
13615dfecf96Smrgstatic void
13625dfecf96SmrgPopdownIspell(Widget w, XtPointer client_data, XtPointer call_data)
13635dfecf96Smrg{
13645dfecf96Smrg    (void)IspellEndProcess((Bool)(long)client_data, True);
13655dfecf96Smrg    XtPopdown(ispell.shell);
13665dfecf96Smrg    *ispell.sentbuf = '\0';
13675dfecf96Smrg}
13685dfecf96Smrg
1369f14f4646Smrgstatic Bool
1370f14f4646SmrgIspellCheckProcess(void)
1371f14f4646Smrg{
1372f14f4646Smrg    int status;
1373f14f4646Smrg
1374f14f4646Smrg    if (ispell.pid) {
1375f14f4646Smrg	waitpid(ispell.pid, &status, WNOHANG);
1376f14f4646Smrg	if (WIFEXITED(status)) {
1377f14f4646Smrg	    ispell.pid = 0;
1378f14f4646Smrg	}
1379f14f4646Smrg	else
1380f14f4646Smrg	    return (True);
1381f14f4646Smrg    }
1382f14f4646Smrg
1383f14f4646Smrg    return (False);
1384f14f4646Smrg}
1385f14f4646Smrg
13865dfecf96Smrgstatic Bool
13875dfecf96SmrgIspellEndProcess(Bool killit, Bool killundo)
13885dfecf96Smrg{
13895dfecf96Smrg    ispell.source = NULL;
13905dfecf96Smrg
13915dfecf96Smrg    if (ispell.pid) {
1392f14f4646Smrg	IgnoreEntry	*ientry;
1393f14f4646Smrg	ReplaceEntry	*rentry;
13945dfecf96Smrg
13955dfecf96Smrg	/* insert added words in private dictionary */
1396f14f4646Smrg	for (ientry = (IgnoreEntry *)hash_iter_first(ignore_hash);
1397f14f4646Smrg	     ientry;
1398f14f4646Smrg	     ientry = (IgnoreEntry *)hash_iter_next(ignore_hash)) {
1399f14f4646Smrg	    if (ientry->add) {
1400f14f4646Smrg		if (ientry->add == UNCAP)
1401f14f4646Smrg		    write(ispell.ofd[1], "&", 1);
14025dfecf96Smrg		else
1403f14f4646Smrg		    write(ispell.ofd[1], "*", 1);
1404f14f4646Smrg		write(ispell.ofd[1], ientry->word->value, ientry->word->length);
1405f14f4646Smrg		write(ispell.ofd[1], "\n", 1);
14065dfecf96Smrg	    }
14075dfecf96Smrg	}
14085dfecf96Smrg	write(ispell.ofd[1], "#\n", 2);		/* save dictionary */
1409f14f4646Smrg	hash_clr(ignore_hash);
14105dfecf96Smrg
14115dfecf96Smrg	if (killit) {
14125dfecf96Smrg	    XtRemoveInput(ispell.id);
14135dfecf96Smrg
14145dfecf96Smrg	    close(ispell.ofd[0]);
14155dfecf96Smrg	    close(ispell.ofd[1]);
14165dfecf96Smrg	    close(ispell.ifd[0]);
14175dfecf96Smrg	    close(ispell.ifd[1]);
14185dfecf96Smrg
14195dfecf96Smrg	    /* if something goes wrong, we don't want to block here forever */
14205dfecf96Smrg	    old_timeout = signal(SIGALRM, timeout_signal);
14215dfecf96Smrg	    alarm(10);
14225dfecf96Smrg	    waitpid(ispell.pid, NULL, 0);
14235dfecf96Smrg	    alarm(0);
14245dfecf96Smrg	    signal(SIGALRM, old_timeout);
14255dfecf96Smrg
14265dfecf96Smrg	    ispell.pid = 0;
14275dfecf96Smrg	    if (ispell.buf)
14285dfecf96Smrg		XtFree(ispell.buf);
14295dfecf96Smrg	    ispell.buf = NULL;
14305dfecf96Smrg
1431f14f4646Smrg	    /* forget about replace matches */
1432f14f4646Smrg	    for (rentry = (ReplaceEntry *)hash_iter_first(replace_hash);
1433f14f4646Smrg		 rentry;
1434f14f4646Smrg		 rentry = (ReplaceEntry *)hash_iter_next(replace_hash)) {
1435f14f4646Smrg		XtFree(rentry->replace);
14365dfecf96Smrg	    }
1437f14f4646Smrg	    hash_clr(replace_hash);
14385dfecf96Smrg	}
14395dfecf96Smrg
14405dfecf96Smrg	if (killundo)
14415dfecf96Smrg	    IspellKillUndoBuffer();
14425dfecf96Smrg    }
14435dfecf96Smrg    else
14445dfecf96Smrg	return (False);
14455dfecf96Smrg
14465dfecf96Smrg    return (True);
14475dfecf96Smrg}
14485dfecf96Smrg
14495dfecf96Smrgstatic void
14505dfecf96SmrgIspellKillUndoBuffer(void)
14515dfecf96Smrg{
14525dfecf96Smrg    ispell_undo *undo, *pundo;
14535dfecf96Smrg
14545dfecf96Smrg    undo = pundo = ispell.undo_base;
14555dfecf96Smrg    while (undo) {
14565dfecf96Smrg	undo = undo->next;
14575dfecf96Smrg	if (pundo->undo_str)
14585dfecf96Smrg	    XtFree(pundo->undo_str);
14595dfecf96Smrg	XtFree((char*)pundo);
14605dfecf96Smrg	pundo = undo;
14615dfecf96Smrg    }
14625dfecf96Smrg    ispell.undo_base = ispell.undo_head = NULL;
14635dfecf96Smrg    ispell.undo_for = NULL;
14645dfecf96Smrg    ispell.undo_depth = 0;
14655dfecf96Smrg    XtSetSensitive(ispell.undo, False);
14665dfecf96Smrg}
14675dfecf96Smrg
14685dfecf96Smrg/*ARGSUSED*/
14695dfecf96Smrgstatic void
14705dfecf96SmrgRevertIspell(Widget w, XtPointer client_data, XtPointer call_data)
14715dfecf96Smrg{
14725dfecf96Smrg    Arg args[1];
14735dfecf96Smrg    char *string, *repstr = NULL;
14745dfecf96Smrg
14755dfecf96Smrg    XtSetArg(args[0], XtNlabel, &string);
14765dfecf96Smrg    XtGetValues(ispell.word, args, 1);
14775dfecf96Smrg    if ((repstr = strchr(string, ' ')) != NULL) {
14785dfecf96Smrg	string = repstr = XtNewString(string);
14795dfecf96Smrg	*strchr(repstr, ' ') = '\0';
14805dfecf96Smrg    }
14815dfecf96Smrg    XtSetArg(args[0], XtNstring, string);
14825dfecf96Smrg    XtSetValues(ispell.text, args, 1);
14835dfecf96Smrg    if (repstr)
14845dfecf96Smrg	XtFree(repstr);
14855dfecf96Smrg}
14865dfecf96Smrg
14875dfecf96Smrg/*ARGSUSED*/
14885dfecf96Smrgstatic void
14895dfecf96SmrgSelectIspell(Widget w, XtPointer client_data, XtPointer call_data)
14905dfecf96Smrg{
14915dfecf96Smrg    XawListReturnStruct *info = (XawListReturnStruct *)call_data;
14925dfecf96Smrg    Arg args[1];
14935dfecf96Smrg
14945dfecf96Smrg    XtSetArg(args[0], XtNstring, ispell.item = info->string);
14955dfecf96Smrg    XtSetValues(ispell.text, args, 1);
14965dfecf96Smrg}
14975dfecf96Smrg
14985dfecf96Smrg/*ARGSUSED*/
14995dfecf96Smrgvoid
15005dfecf96SmrgReplaceIspell(Widget w, XtPointer client_data, XtPointer call_data)
15015dfecf96Smrg{
15025dfecf96Smrg    XawTextPosition pos = XawTextGetInsertionPoint(ispell.ascii);
15035dfecf96Smrg    XawTextBlock check, search, replace;
15045dfecf96Smrg    Arg args[1];
15055dfecf96Smrg    char *text;
15065dfecf96Smrg
15075dfecf96Smrg    if (!ispell.lock)
15085dfecf96Smrg	return;
15095dfecf96Smrg
15105dfecf96Smrg    XtSetArg(args[0], XtNlabel, &text);
15115dfecf96Smrg    XtGetValues(ispell.word, args, 1);
15125dfecf96Smrg    search.ptr = text;
15135dfecf96Smrg    search.format = XawFmt8Bit;
15145dfecf96Smrg    search.firstPos = 0;
15155dfecf96Smrg    search.length = ispell.right - pos;
15165dfecf96Smrg
15175dfecf96Smrg    XtSetArg(args[0], XtNstring, &text);
15185dfecf96Smrg    XtGetValues(ispell.text, args, 1);
15195dfecf96Smrg    replace.ptr = text;
15205dfecf96Smrg    replace.format = XawFmt8Bit;
15215dfecf96Smrg    replace.firstPos = 0;
15225dfecf96Smrg    replace.length = strlen(text);
15235dfecf96Smrg
15245dfecf96Smrg    if (strcmp(search.ptr, replace.ptr) != 0 &&
15255dfecf96Smrg	XawTextReplace(ispell.ascii, pos, pos + search.length,
15265dfecf96Smrg		       &replace) == XawEditDone) {
15275dfecf96Smrg	ispell.right += replace.length - search.length;
15285dfecf96Smrg	IspellCheckUndo();
15295dfecf96Smrg	ispell.undo_head->undo_str = NULL;
15305dfecf96Smrg	ispell.undo_head->undo_pos = pos;
15315dfecf96Smrg	ispell.undo_head->undo_count = 1;
15325dfecf96Smrg
15335dfecf96Smrg	if (ispell.repeat) {
15345dfecf96Smrg	    ispell.undo_head->repeat = 2; /* To recognize later it was replaced */
15355dfecf96Smrg	    ispell.undo_head->undo_count = ispell.right;
15365dfecf96Smrg	    ispell.undo_head->undo_str = XtNewString(search.ptr);
15375dfecf96Smrg	}
15385dfecf96Smrg	if (client_data && !ispell.repeat) {
15395dfecf96Smrg	    XawTextDisableRedisplay(ispell.ascii);
15405dfecf96Smrg	    pos = ispell.right;
15415dfecf96Smrg	    while ((pos = XawTextSourceSearch(ispell.source, pos, XawsdRight, &search))
15425dfecf96Smrg		!= XawTextSearchError) {
15435dfecf96Smrg		Bool do_replace = True;
15445dfecf96Smrg		char mb[sizeof(wchar_t)];
15455dfecf96Smrg
15465dfecf96Smrg		if (XawTextSourceRead(ispell.source, pos - 1, &check, 1) > 0) {
1547f14f4646Smrg		    if (international)
1548f14f4646Smrg			wctomb(mb, *(wchar_t*)check.ptr);
1549f14f4646Smrg		    else
1550f14f4646Smrg			mb[0] = check.ptr[0];
15515dfecf96Smrg		    do_replace = !isalpha(*mb) && *mb && !strchr(ispell.wchars, *mb);
15525dfecf96Smrg		}
15535dfecf96Smrg		if (do_replace &&
15545dfecf96Smrg		    XawTextSourceRead(ispell.source, pos + search.length, &check, 1) > 0) {
1555f14f4646Smrg		    if (international)
1556f14f4646Smrg			wctomb(mb, *(wchar_t*)check.ptr);
1557f14f4646Smrg		    else
1558f14f4646Smrg			mb[0] = check.ptr[0];
15595dfecf96Smrg		    do_replace = !isalpha(*mb) && *mb && !strchr(ispell.wchars, *mb);
15605dfecf96Smrg		}
15615dfecf96Smrg		if (do_replace) {
15625dfecf96Smrg		    XawTextReplace(ispell.ascii, pos, pos + search.length, &replace);
15635dfecf96Smrg		    ++ispell.undo_head->undo_count;
15645dfecf96Smrg		}
15655dfecf96Smrg		pos += search.length;
15665dfecf96Smrg	    }
15675dfecf96Smrg	    XawTextEnableRedisplay(ispell.ascii);
15685dfecf96Smrg	}
15695dfecf96Smrg	(void)IspellReplacedWord(search.ptr, replace.ptr);
15705dfecf96Smrg
15715dfecf96Smrg	strncpy(&ispell.sentbuf[1], replace.ptr, sizeof(ispell.sentbuf) - 2);
15725dfecf96Smrg	ispell.sentbuf[sizeof(ispell.sentbuf) - 1] = '\0';
15735dfecf96Smrg    }
15745dfecf96Smrg    else
15755dfecf96Smrg	Feep();
15765dfecf96Smrg
15775dfecf96Smrg    if (ispell.repeat)
15785dfecf96Smrg	ispell.right = ispell.left = XawTextGetInsertionPoint(ispell.ascii);
15795dfecf96Smrg    else if (!ispell.terse_mode || !ispell.item ||
15805dfecf96Smrg	     strcmp(ispell.item, replace.ptr))
15815dfecf96Smrg	ispell.right = ispell.left;	/* check it again! */
15825dfecf96Smrg
15835dfecf96Smrg    ispell.lock = ispell.checkit = False;
15845dfecf96Smrg
15855dfecf96Smrg    ispell.stat = SEND;
15865dfecf96Smrg    IspellSetStatus(ispell.working_label);
15875dfecf96Smrg    while (IspellSend() == 0)
15885dfecf96Smrg	;
15895dfecf96Smrg}
15905dfecf96Smrg
15915dfecf96Smrg/*ARGSUSED*/
15925dfecf96Smrgvoid
15935dfecf96SmrgIgnoreIspell(Widget w, XtPointer client_data, XtPointer call_data)
15945dfecf96Smrg{
15955dfecf96Smrg    Arg args[1];
15965dfecf96Smrg    char *text;
15975dfecf96Smrg
15985dfecf96Smrg    if (!ispell.lock)
15995dfecf96Smrg	return;
16005dfecf96Smrg
16015dfecf96Smrg    XtSetArg(args[0], XtNlabel, &text);
16025dfecf96Smrg    XtGetValues(ispell.word, args, 1);
16035dfecf96Smrg
16045dfecf96Smrg    IspellCheckUndo();
16055dfecf96Smrg
16065dfecf96Smrg    if ((ispell.undo_head->repeat = ispell.repeat) != False) {
16075dfecf96Smrg	ispell.undo_head->undo_count = ispell.right;
16085dfecf96Smrg	ispell.undo_head->undo_str = XtNewString(text);
16095dfecf96Smrg    }
16105dfecf96Smrg    else
16115dfecf96Smrg	ispell.undo_head->undo_count = 0;
16125dfecf96Smrg
16135dfecf96Smrg    ispell.undo_head->undo_pos = XawTextGetInsertionPoint(ispell.ascii);
16145dfecf96Smrg
16155dfecf96Smrg    if (!ispell.repeat) {
16165dfecf96Smrg	if (client_data) {
16175dfecf96Smrg	    IspellIgnoredWord(text, ADD, 0);
16185dfecf96Smrg	    ispell.undo_head->undo_str = XtNewString(text);
16195dfecf96Smrg	}
16205dfecf96Smrg	else
16215dfecf96Smrg	    ispell.undo_head->undo_str = NULL;
16225dfecf96Smrg    }
16235dfecf96Smrg
16245dfecf96Smrg    ispell.lock = ispell.checkit = False;
16255dfecf96Smrg
16265dfecf96Smrg    ispell.stat = SEND;
16275dfecf96Smrg    IspellSetStatus(ispell.working_label);
16285dfecf96Smrg    while (IspellSend() == 0)
16295dfecf96Smrg	;
16305dfecf96Smrg}
16315dfecf96Smrg
16325dfecf96Smrg/*ARGSUSED*/
16335dfecf96Smrgvoid
16345dfecf96SmrgAddIspell(Widget w, XtPointer client_data, XtPointer call_data)
16355dfecf96Smrg{
16365dfecf96Smrg    Arg args[1];
16375dfecf96Smrg    char *text;
16385dfecf96Smrg    int cmd = (long)client_data;
16395dfecf96Smrg
16405dfecf96Smrg    if (!ispell.lock || ispell.repeat)
16415dfecf96Smrg	return;
16425dfecf96Smrg
16435dfecf96Smrg    XtSetArg(args[0], XtNlabel, &text);
16445dfecf96Smrg    XtGetValues(ispell.word, args, 1);
16455dfecf96Smrg
16465dfecf96Smrg    IspellCheckUndo();
16475dfecf96Smrg    ispell.undo_head->undo_str = XtNewString(text);
16485dfecf96Smrg    ispell.undo_head->undo_pos = XawTextGetInsertionPoint(ispell.ascii);
16495dfecf96Smrg    ispell.undo_head->undo_count = -cmd;
16505dfecf96Smrg
16515dfecf96Smrg    (void)IspellIgnoredWord(text, ADD, cmd);
16525dfecf96Smrg
16535dfecf96Smrg    ispell.lock = ispell.checkit = False;
16545dfecf96Smrg    ispell.stat = SEND;
16555dfecf96Smrg    IspellSetStatus(ispell.working_label);
16565dfecf96Smrg    while (IspellSend() == 0)
16575dfecf96Smrg	;
16585dfecf96Smrg}
16595dfecf96Smrg
16605dfecf96Smrg/*ARGSUSED*/
16615dfecf96Smrgstatic void
16625dfecf96SmrgUndoIspell(Widget w, XtPointer client_data, XtPointer call_data)
16635dfecf96Smrg{
16645dfecf96Smrg    Bool enable_redisplay = False;
16655dfecf96Smrg    ispell_undo *undo = ispell.undo_head;
16665dfecf96Smrg
16675dfecf96Smrg    if ((!ispell.lock && ispell.stat) || !undo)
16685dfecf96Smrg	return;
16695dfecf96Smrg
16705dfecf96Smrg    if (ispell.undo_for && strcmp(ispell.undo_for, ispell.dictionary)) {
16715dfecf96Smrg	XeditPrintf("Undo: Dictionary changed. Undo information was lost.\n");
16725dfecf96Smrg	IspellKillUndoBuffer();
16735dfecf96Smrg	Feep();
16745dfecf96Smrg	return;
16755dfecf96Smrg    }
16765dfecf96Smrg
16775dfecf96Smrg    if (undo->terse != ispell.terse_mode)
16785dfecf96Smrg	IspellSetTerseMode(undo->terse);
16795dfecf96Smrg
16805dfecf96Smrg    if (undo->format != ispell.format_info->value) {
16815dfecf96Smrg	struct _ispell_format *fmt = &ispell_format[undo->format];
16825dfecf96Smrg	ChangeFormatIspell(fmt->sme, (XtPointer)fmt, NULL);
16835dfecf96Smrg    }
16845dfecf96Smrg
16855dfecf96Smrg    if (undo->undo_count > 0 && !undo->repeat) {
16865dfecf96Smrg	XawTextPosition tmp;
16875dfecf96Smrg
16885dfecf96Smrg	enable_redisplay = undo->undo_count > 1;
16895dfecf96Smrg	if (enable_redisplay)
16905dfecf96Smrg	    XawTextDisableRedisplay(ispell.ascii);
16915dfecf96Smrg	while (undo->undo_count--)
16925dfecf96Smrg	    if (!_XawTextSrcUndo((TextSrcObject)ispell.source, &tmp)) {
16935dfecf96Smrg		Feep();
16945dfecf96Smrg		break;
16955dfecf96Smrg	    }
16965dfecf96Smrg    }
16975dfecf96Smrg    else if (undo->undo_count < 0) {
16985dfecf96Smrg	if (undo->undo_str)
16995dfecf96Smrg	    (void)IspellIgnoredWord(undo->undo_str, REMOVE, -undo->undo_count);
17005dfecf96Smrg    }
17015dfecf96Smrg    else if (undo->undo_str) {
17025dfecf96Smrg	if (!undo->repeat)
17035dfecf96Smrg	    IspellIgnoredWord(undo->undo_str, REMOVE, 0);
17045dfecf96Smrg    }
17055dfecf96Smrg
17065dfecf96Smrg    XawTextSetInsertionPoint(ispell.ascii,
17075dfecf96Smrg			     ispell.right = ispell.left = undo->undo_pos);
17085dfecf96Smrg    if (enable_redisplay)
17095dfecf96Smrg	XawTextEnableRedisplay(ispell.ascii);
17105dfecf96Smrg
17115dfecf96Smrg    /* need to do it because may be two misspelled words together */
17125dfecf96Smrg    if (undo->repeat) {
17135dfecf96Smrg	char **list, **old_list;
17145dfecf96Smrg	int old_len;
17155dfecf96Smrg	Arg args[2];
17165dfecf96Smrg
17175dfecf96Smrg	if (undo->repeat > 1) {
17185dfecf96Smrg	    XawTextDisableRedisplay(ispell.ascii);
17195dfecf96Smrg	    if (!_XawTextSrcUndo((TextSrcObject)ispell.source, &ispell.right))
17205dfecf96Smrg		Feep();
17215dfecf96Smrg	    XawTextEnableRedisplay(ispell.ascii);
17225dfecf96Smrg	}
17235dfecf96Smrg	else
17245dfecf96Smrg	    ispell.right = (XawTextPosition)undo->undo_count;
17255dfecf96Smrg	IspellSetRepeated(ispell.repeat = True);
17265dfecf96Smrg	XtSetArg(args[0], XtNlabel, undo->undo_str);
17275dfecf96Smrg	XtSetValues(ispell.word, args, 1);
17285dfecf96Smrg	XmuSnprintf(ispell.sentbuf, sizeof(ispell.sentbuf), "^%s",
17295dfecf96Smrg		    strrchr(undo->undo_str, ' ') + 1);
17305dfecf96Smrg	strcpy(ispell.sendbuf, ispell.sentbuf);
17315dfecf96Smrg	XtSetArg(args[0], XtNstring, &ispell.sentbuf[1]);
17325dfecf96Smrg	XtSetValues(ispell.text, args, 1);
17335dfecf96Smrg
17345dfecf96Smrg	XtSetArg(args[0], XtNlist, &old_list);
17355dfecf96Smrg	XtSetArg(args[1], XtNnumberStrings, &old_len);
17365dfecf96Smrg	XtGetValues(ispell.list, args, 2);
17375dfecf96Smrg
17385dfecf96Smrg	list = (char **)XtMalloc(sizeof(char*));
17395dfecf96Smrg	list[0] = XtNewString(&ispell.sentbuf[1]);
17405dfecf96Smrg	XtSetArg(args[0], XtNlist, list);
17415dfecf96Smrg	XtSetArg(args[1], XtNnumberStrings, 1);
17425dfecf96Smrg	XtSetValues(ispell.list, args, 2);
17435dfecf96Smrg	XtSetSensitive(ispell.list, True);
17445dfecf96Smrg	XawListHighlight(ispell.list, 0);
17455dfecf96Smrg
17465dfecf96Smrg	if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
17475dfecf96Smrg	    while (--old_len > -1)
17485dfecf96Smrg		XtFree(old_list[old_len]);
17495dfecf96Smrg	    XtFree((char*)old_list);
17505dfecf96Smrg	}
17515dfecf96Smrg
17525dfecf96Smrg	IspellSetSelection(ispell.left, ispell.right);
17535dfecf96Smrg	IspellSetStatus(ispell.repeat_label);
17545dfecf96Smrg	ispell.lock = True;
17555dfecf96Smrg	ispell.checkit = False;
17565dfecf96Smrg    }
17575dfecf96Smrg    else if (ispell.repeat) {
17585dfecf96Smrg	*ispell.sentbuf = '\0';
17595dfecf96Smrg	IspellSetRepeated(ispell.repeat = False);
17605dfecf96Smrg    }
17615dfecf96Smrg
17625dfecf96Smrg    if (undo->prev)
17635dfecf96Smrg	undo->prev->next = NULL;
17645dfecf96Smrg    ispell.undo_head = undo->prev;
17655dfecf96Smrg    if (undo == ispell.undo_base) {
17665dfecf96Smrg	ispell.undo_base = NULL;
17675dfecf96Smrg	ispell.undo_for = NULL;
17685dfecf96Smrg	XtSetSensitive(ispell.undo, False);
17695dfecf96Smrg    }
17705dfecf96Smrg    if (undo->undo_str)
17715dfecf96Smrg	XtFree(undo->undo_str);
17725dfecf96Smrg    XtFree((char*)undo);
17735dfecf96Smrg    --ispell.undo_depth;
17745dfecf96Smrg
17755dfecf96Smrg    if (!ispell.stat || ispell.checkit)
17765dfecf96Smrg	IspellSetSensitive(True);
17775dfecf96Smrg
17785dfecf96Smrg    if (!ispell.repeat) {
17795dfecf96Smrg	ispell.lock = ispell.checkit = False;
17805dfecf96Smrg	ispell.stat = SEND;
17815dfecf96Smrg	IspellSetStatus(ispell.working_label);
17825dfecf96Smrg	while (IspellSend() == 0)
17835dfecf96Smrg	    ;
17845dfecf96Smrg    }
17855dfecf96Smrg}
17865dfecf96Smrg
17875dfecf96Smrg/*ARGSUSED*/
17885dfecf96Smrgstatic void
17895dfecf96SmrgCheckIspell(Widget w, XtPointer client_data, XtPointer call_data)
17905dfecf96Smrg{
17915dfecf96Smrg    Arg args[1];
17925dfecf96Smrg    char *text, *str, string[1024];
17935dfecf96Smrg    int i, len;
17945dfecf96Smrg
17955dfecf96Smrg    if (!ispell.lock)
17965dfecf96Smrg	return;
17975dfecf96Smrg
17985dfecf96Smrg    XtSetArg(args[0], XtNstring, &text);
17995dfecf96Smrg    XtGetValues(ispell.text, args, 1);
18005dfecf96Smrg
18015dfecf96Smrg    /* Check only a word at a time */
18025dfecf96Smrg    len = 0;
18035dfecf96Smrg    str = text;
18045dfecf96Smrg    while (*str) {
18055dfecf96Smrg	if (isalpha(*str) || strchr(ispell.wchars, *str))
18065dfecf96Smrg	    break;
18075dfecf96Smrg	++str;
18085dfecf96Smrg	++len;
18095dfecf96Smrg    }
18105dfecf96Smrg    i = 0;
18115dfecf96Smrg    while (*str) {
18125dfecf96Smrg	if (isalpha(*str) || strchr(ispell.wchars, *str))
18135dfecf96Smrg	    string[i++] = *str++;
18145dfecf96Smrg	else
18155dfecf96Smrg	    break;
18165dfecf96Smrg    }
18175dfecf96Smrg    string[i] = '\0';
18185dfecf96Smrg
18195dfecf96Smrg    if (strcmp(text, string)) {
18205dfecf96Smrg	XawTextPosition pos = XawTextGetInsertionPoint(ispell.text) - len;
18215dfecf96Smrg
18225dfecf96Smrg	XtSetArg(args[0], XtNstring, string);
18235dfecf96Smrg	XtSetValues(ispell.text, args, 1);
18245dfecf96Smrg	XawTextSetInsertionPoint(ispell.text, pos);
18255dfecf96Smrg	Feep();
18265dfecf96Smrg    }
18275dfecf96Smrg
18285dfecf96Smrg    if (i == 0) {
18295dfecf96Smrg	Feep();
18305dfecf96Smrg	return;
18315dfecf96Smrg    }
18325dfecf96Smrg
18335dfecf96Smrg    len = XmuSnprintf(ispell.sendbuf, sizeof(ispell.sendbuf), "^%s\n", string);
18345dfecf96Smrg
18355dfecf96Smrg    ispell.sendbuf[sizeof(ispell.sendbuf) - 1] = '\n';
18365dfecf96Smrg
18375dfecf96Smrg    write(ispell.ofd[1], ispell.sendbuf, len);
18385dfecf96Smrg
18395dfecf96Smrg    ispell.lock = False;
18405dfecf96Smrg    ispell.checkit = True;
18415dfecf96Smrg    ispell.stat = RECEIVE;
18425dfecf96Smrg}
18435dfecf96Smrg
18445dfecf96Smrg/*ARGSUSED*/
18455dfecf96Smrgstatic void
18465dfecf96SmrgLookIspell(Widget w, XtPointer client_data, XtPointer call_data)
18475dfecf96Smrg{
18485dfecf96Smrg    int len, old_len;
18495dfecf96Smrg    FILE *fd;
18505dfecf96Smrg    Arg args[2];
18515dfecf96Smrg    char *text, *str, **list, **old_list, command[1024], buffer[1024];
18525dfecf96Smrg    Bool sensitive = True;
18535dfecf96Smrg
18545dfecf96Smrg    if (!ispell.lock)
18555dfecf96Smrg	return;
18565dfecf96Smrg
18575dfecf96Smrg    XtSetArg(args[0], XtNstring, &text);
18585dfecf96Smrg    XtGetValues(ispell.text, args, 1);
18595dfecf96Smrg
18605dfecf96Smrg    if (!*text) {
18615dfecf96Smrg	Feep();
18625dfecf96Smrg	return;
18635dfecf96Smrg    }
18645dfecf96Smrg
18655dfecf96Smrg    if (strlen(ispell.look_cmd) + strlen(text) + strlen(ispell.words_file) + 8
18665dfecf96Smrg	> sizeof(command) - 1) {
18675dfecf96Smrg	fprintf(stderr, "Command line too large\n");
18685dfecf96Smrg	return;
18695dfecf96Smrg    }
18705dfecf96Smrg
18715dfecf96Smrg    XmuSnprintf(command, sizeof(command), "%s '^%s.*$' %s",
18725dfecf96Smrg		ispell.look_cmd, text, ispell.words_file);
18735dfecf96Smrg
18745dfecf96Smrg    if ((fd = popen(command, "r")) == NULL) {
18755dfecf96Smrg	fprintf(stderr, "Cannot popen '%s'\n", ispell.look_cmd);
18765dfecf96Smrg	return;
18775dfecf96Smrg    }
18785dfecf96Smrg
18795dfecf96Smrg    list = NULL;
18805dfecf96Smrg    len = 0;
18815dfecf96Smrg
18825dfecf96Smrg#define	MAX_LOOK_RESULTS	256
18835dfecf96Smrg    while (fgets(buffer, sizeof(buffer), fd) != NULL) {
18845dfecf96Smrg	if ((str = strchr(buffer, '\n')) == NULL) {
18855dfecf96Smrg	    fprintf(stderr, "String is too large\n");
18865dfecf96Smrg	    break;
18875dfecf96Smrg	}
18885dfecf96Smrg	*str = '\0';
18895dfecf96Smrg	if ((len % 16) == 0)
18905dfecf96Smrg	    list = (char**)XtRealloc((char*)list, sizeof(char*) * (len + 16));
18915dfecf96Smrg	list[len] = XtNewString(buffer);
18925dfecf96Smrg	if (++len >= MAX_LOOK_RESULTS) {
18935dfecf96Smrg	    Feep();
18945dfecf96Smrg	    break;
18955dfecf96Smrg	}
18965dfecf96Smrg    }
18975dfecf96Smrg#undef MAX_LOOK_RESULTS
18985dfecf96Smrg
18995dfecf96Smrg    XtSetArg(args[0], XtNlist, &old_list);
19005dfecf96Smrg    XtSetArg(args[1], XtNnumberStrings, &old_len);
19015dfecf96Smrg    XtGetValues(ispell.list, args, 2);
19025dfecf96Smrg
19035dfecf96Smrg    if (len == 0) {
19045dfecf96Smrg	list = (char**)XtMalloc(sizeof(char*));
19055dfecf96Smrg	list[0] = XtNewString("");
19065dfecf96Smrg	len = 1;
19075dfecf96Smrg	sensitive = False;
19085dfecf96Smrg    }
19095dfecf96Smrg
19105dfecf96Smrg    XtSetArg(args[0], XtNlist, list);
19115dfecf96Smrg    XtSetArg(args[1], XtNnumberStrings, len);
19125dfecf96Smrg    XtSetValues(ispell.list, args, 2);
19135dfecf96Smrg
19145dfecf96Smrg    XtSetSensitive(ispell.list, sensitive);
19155dfecf96Smrg    IspellSetStatus(sensitive ? ispell.look_label : ispell.none_label);
19165dfecf96Smrg
19175dfecf96Smrg    if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
19185dfecf96Smrg	while (--old_len > -1)
19195dfecf96Smrg	    XtFree(old_list[old_len]);
19205dfecf96Smrg	XtFree((char*)old_list);
19215dfecf96Smrg    }
19225dfecf96Smrg
19235dfecf96Smrg    pclose(fd);
19245dfecf96Smrg}
19255dfecf96Smrg
19265dfecf96Smrg/*ARGSUSED*/
19275dfecf96Smrgstatic void
19285dfecf96SmrgToggleTerseIspell(Widget w, XtPointer client_data, XtPointer call_data)
19295dfecf96Smrg{
19305dfecf96Smrg    if (!ispell.lock)
19315dfecf96Smrg	return;
19325dfecf96Smrg
19335dfecf96Smrg    ispell.terse_mode = !ispell.terse_mode;
19345dfecf96Smrg    write(ispell.ofd[1], ispell.terse_mode ? "!\n" : "%\n", 2);
19355dfecf96Smrg}
19365dfecf96Smrg
19375dfecf96Smrg/*ARGSUSED*/
19385dfecf96Smrgstatic void
19395dfecf96SmrgChangeDictionaryIspell(Widget w, XtPointer client_data, XtPointer call_data)
19405dfecf96Smrg{
19415dfecf96Smrg    ispell_dict *tmp, *dic = (ispell_dict*)client_data;
19425dfecf96Smrg    XawTextPosition pos = XawTextGetInsertionPoint(ispell.ascii);
19435dfecf96Smrg    XawTextPosition right = ispell.right;
19445dfecf96Smrg    Arg args[1];
19455dfecf96Smrg
19465dfecf96Smrg    if (strcmp(XtName(dic->sme), ispell.dictionary) == 0)
19475dfecf96Smrg	return;
19485dfecf96Smrg
19495dfecf96Smrg    if (!ispell.lock) {
1950f14f4646Smrg	if (IspellCheckProcess()) {
1951f14f4646Smrg	    Feep();
1952f14f4646Smrg	    return;
1953f14f4646Smrg	}
19545dfecf96Smrg    }
19555dfecf96Smrg
19565dfecf96Smrg    for (tmp = ispell.dict_info; tmp; tmp = tmp->next)
19575dfecf96Smrg	if (strcmp(XtName(tmp->sme), ispell.dictionary) == 0) {
19585dfecf96Smrg	    XtSetArg(args[0], XtNleftBitmap, None);
19595dfecf96Smrg	    XtSetValues(tmp->sme, args, 1);
19605dfecf96Smrg	}
19615dfecf96Smrg
19625dfecf96Smrg    if (ispell.undo_base && !ispell.undo_for)
19635dfecf96Smrg	ispell.undo_for = ispell.dictionary;
19645dfecf96Smrg
19655dfecf96Smrg    XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
19665dfecf96Smrg    XtSetValues(dic->sme, args, 1);
19675dfecf96Smrg    ispell.dictionary = XtName(dic->sme);
19685dfecf96Smrg    ispell.wchars = dic->wchars;
19695dfecf96Smrg    XtSetArg(args[0], XtNlabel, XtName(dic->sme));
19705dfecf96Smrg    XtSetValues(ispell.dict, args, 1);
19715dfecf96Smrg
19725dfecf96Smrg    IspellSetStatus(ispell.working_label);
19735dfecf96Smrg
19745dfecf96Smrg    (void)IspellEndProcess(True, False);
19755dfecf96Smrg    ispell.lock = ispell.checkit = False;
19765dfecf96Smrg    (void)IspellStartProcess();
19775dfecf96Smrg
19785dfecf96Smrg    ispell.stat = RECEIVE;
19795dfecf96Smrg
19805dfecf96Smrg    /* restart at the same selected word */
19815dfecf96Smrg    if (ispell.repeat == False)
19825dfecf96Smrg	ispell.left = ispell.right = pos;
19835dfecf96Smrg    else
19845dfecf96Smrg	ispell.right = right;
19855dfecf96Smrg}
19865dfecf96Smrg
19875dfecf96Smrg/*ARGSUSED*/
19885dfecf96Smrgstatic void
19895dfecf96SmrgChangeFormatIspell(Widget w, XtPointer client_data, XtPointer call_data)
19905dfecf96Smrg{
19915dfecf96Smrg    struct _ispell_format *fmt = (struct _ispell_format*)client_data;
19925dfecf96Smrg    Arg args[1];
19935dfecf96Smrg
19945dfecf96Smrg    if (strcmp(fmt->name, ispell.formatting) == 0)
19955dfecf96Smrg	return;
19965dfecf96Smrg
19975dfecf96Smrg    if (!ispell.lock) {
19985dfecf96Smrg	Feep();
19995dfecf96Smrg	return;
20005dfecf96Smrg    }
20015dfecf96Smrg
20025dfecf96Smrg    XtSetArg(args[0], XtNleftBitmap, None);
20035dfecf96Smrg    XtSetValues(ispell.format_info->sme, args, 1);
20045dfecf96Smrg
20055dfecf96Smrg    XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
20065dfecf96Smrg    XtSetValues(fmt->sme, args, 1);
20075dfecf96Smrg    ispell.formatting = fmt->name;
20085dfecf96Smrg    ispell.format_info = fmt;
20095dfecf96Smrg    XtSetArg(args[0], XtNlabel, fmt->name);
20105dfecf96Smrg    XtSetValues(ispell.format, args, 1);
20115dfecf96Smrg}
20125dfecf96Smrg
20135dfecf96Smrgstatic Bool
20145dfecf96SmrgInitIspell(void)
20155dfecf96Smrg{
20165dfecf96Smrg    Atom delete_window;
20175dfecf96Smrg    char *str, *list;
20185dfecf96Smrg    XtResource dict_res;
2019f14f4646Smrg    ispell_dict *dict, *prev_dict;
20205dfecf96Smrg    int i;
20215dfecf96Smrg    static XtResource text_res[] = {
20225dfecf96Smrg	{"skipLines", "Skip", XtRString, sizeof(char*),
20235dfecf96Smrg	 XtOffsetOf(struct _ispell, skip), XtRString, "#"},
20245dfecf96Smrg    };
20255dfecf96Smrg
20265dfecf96Smrg    if (ispell.shell)
20275dfecf96Smrg	return (False);
20285dfecf96Smrg
2029f14f4646Smrg    replace_hash = hash_new(RSTRTBLSZ, NULL);
2030f14f4646Smrg    ignore_hash = hash_new(ISTRTBLSZ, NULL);
2031f14f4646Smrg
20325dfecf96Smrg    ispell.shell	= XtCreatePopupShell("ispell", transientShellWidgetClass,
20335dfecf96Smrg					     topwindow, NULL, 0);
20345dfecf96Smrg
20355dfecf96Smrg    XtGetApplicationResources(ispell.shell, (XtPointer)&ispell, resources,
20365dfecf96Smrg			      XtNumber(resources), NULL, 0);
20375dfecf96Smrg
20385dfecf96Smrg    ispell.form		= XtCreateManagedWidget("form", formWidgetClass,
20395dfecf96Smrg						ispell.shell, NULL, 0);
20405dfecf96Smrg    ispell.mispelled	= XtCreateManagedWidget("mispelled", labelWidgetClass,
20415dfecf96Smrg						ispell.form, NULL, 0);
20425dfecf96Smrg    ispell.repeated	= XtCreateWidget("repeated", labelWidgetClass,
20435dfecf96Smrg					 ispell.form, NULL, 0);
20445dfecf96Smrg    ispell.word		= XtCreateManagedWidget("word", commandWidgetClass,
20455dfecf96Smrg						ispell.form, NULL, 0);
20465dfecf96Smrg    XtAddCallback(ispell.word, XtNcallback, RevertIspell, NULL);
20475dfecf96Smrg    ispell.replacement	= XtCreateManagedWidget("replacement", labelWidgetClass,
20485dfecf96Smrg						ispell.form, NULL, 0);
20495dfecf96Smrg    ispell.text		= XtVaCreateManagedWidget("text", asciiTextWidgetClass,
20505dfecf96Smrg						ispell.form,
20515dfecf96Smrg						XtNeditType, XawtextEdit,
20525dfecf96Smrg						NULL);
20535dfecf96Smrg    ispell.suggestions	= XtCreateManagedWidget("suggestions", labelWidgetClass,
20545dfecf96Smrg						ispell.form, NULL, 0);
20555dfecf96Smrg    ispell.viewport	= XtCreateManagedWidget("viewport", viewportWidgetClass,
20565dfecf96Smrg						ispell.form, NULL, 0);
20575dfecf96Smrg    ispell.list		= XtCreateManagedWidget("list", listWidgetClass,
20585dfecf96Smrg						ispell.viewport, NULL, 0);
20595dfecf96Smrg    XtAddCallback(ispell.list, XtNcallback, SelectIspell, NULL);
20605dfecf96Smrg    ispell.commands	= XtCreateManagedWidget("commands", formWidgetClass,
20615dfecf96Smrg						ispell.form, NULL, 0);
20625dfecf96Smrg    ispell.check	= XtCreateManagedWidget("check", commandWidgetClass,
20635dfecf96Smrg						ispell.commands, NULL, 0);
20645dfecf96Smrg    XtAddCallback(ispell.check, XtNcallback, CheckIspell, NULL);
20655dfecf96Smrg    ispell.look		= XtCreateManagedWidget("look", commandWidgetClass,
20665dfecf96Smrg						ispell.commands, NULL, 0);
20675dfecf96Smrg    XtAddCallback(ispell.look, XtNcallback, LookIspell, NULL);
20685dfecf96Smrg    ispell.undo		= XtCreateManagedWidget("undo", commandWidgetClass,
20695dfecf96Smrg						ispell.commands, NULL, 0);
20705dfecf96Smrg    XtAddCallback(ispell.undo, XtNcallback, UndoIspell, NULL);
20715dfecf96Smrg    ispell.replace	= XtCreateManagedWidget("replace", commandWidgetClass,
20725dfecf96Smrg						ispell.commands, NULL, 0);
20735dfecf96Smrg    XtAddCallback(ispell.replace, XtNcallback, ReplaceIspell, (XtPointer)False);
20745dfecf96Smrg    ispell.replaceAll	= XtCreateManagedWidget("replaceAll", commandWidgetClass,
20755dfecf96Smrg						ispell.commands, NULL, 0);
20765dfecf96Smrg    XtAddCallback(ispell.replaceAll, XtNcallback, ReplaceIspell, (XtPointer)True);
20775dfecf96Smrg    ispell.ignore	= XtCreateManagedWidget("ignore", commandWidgetClass,
20785dfecf96Smrg						ispell.commands, NULL, 0);
20795dfecf96Smrg    XtAddCallback(ispell.ignore, XtNcallback, IgnoreIspell, (XtPointer)False);
20805dfecf96Smrg    ispell.ignoreAll	= XtCreateManagedWidget("ignoreAll", commandWidgetClass,
20815dfecf96Smrg						ispell.commands, NULL, 0);
20825dfecf96Smrg    XtAddCallback(ispell.ignoreAll, XtNcallback, IgnoreIspell, (XtPointer)True);
20835dfecf96Smrg    ispell.add		= XtCreateManagedWidget("add", commandWidgetClass,
20845dfecf96Smrg						ispell.commands, NULL, 0);
20855dfecf96Smrg    XtAddCallback(ispell.add, XtNcallback, AddIspell, (XtPointer)ASIS);
20865dfecf96Smrg    ispell.addUncap	= XtCreateManagedWidget("addUncap", commandWidgetClass,
20875dfecf96Smrg						ispell.commands, NULL, 0);
20885dfecf96Smrg    XtAddCallback(ispell.addUncap, XtNcallback, AddIspell, (XtPointer)UNCAP);
20895dfecf96Smrg    ispell.suspend	= XtCreateManagedWidget("suspend", commandWidgetClass,
20905dfecf96Smrg						ispell.commands, NULL, 0);
20915dfecf96Smrg    XtAddCallback(ispell.suspend, XtNcallback, PopdownIspell, (XtPointer)False);
20925dfecf96Smrg    ispell.cancel	= XtCreateManagedWidget("cancel", commandWidgetClass,
20935dfecf96Smrg						ispell.commands, NULL, 0);
20945dfecf96Smrg    XtAddCallback(ispell.cancel, XtNcallback, PopdownIspell, (XtPointer)True);
20955dfecf96Smrg    ispell.terse	= XtVaCreateManagedWidget("terse", toggleWidgetClass,
20965dfecf96Smrg						  ispell.commands,
20975dfecf96Smrg						  XtNstate, ispell.terse_mode,
20985dfecf96Smrg						  NULL);
20995dfecf96Smrg    XtAddCallback(ispell.terse, XtNcallback, ToggleTerseIspell, NULL);
21005dfecf96Smrg    ispell.status	= XtCreateManagedWidget("status", labelWidgetClass,
21015dfecf96Smrg						ispell.form, NULL, 0);
21025dfecf96Smrg    ispell.options	= XtCreateManagedWidget("options", formWidgetClass,
21035dfecf96Smrg						ispell.form, NULL, 0);
21045dfecf96Smrg    ispell.dict		= XtVaCreateManagedWidget("dict", menuButtonWidgetClass,
21055dfecf96Smrg						  ispell.options,
21065dfecf96Smrg						  XtNmenuName, "dictionaries",
21075dfecf96Smrg						  NULL);
21085dfecf96Smrg    ispell.dictMenu	= XtCreatePopupShell("dictionaries", simpleMenuWidgetClass,
21095dfecf96Smrg					     ispell.options, NULL, 0);
21105dfecf96Smrg    XtRealizeWidget(ispell.dictMenu);
21115dfecf96Smrg
21125dfecf96Smrg    ispell.format	= XtVaCreateManagedWidget("format", menuButtonWidgetClass,
21135dfecf96Smrg						  ispell.options,
21145dfecf96Smrg						  XtNmenuName, "formats",
21155dfecf96Smrg						  NULL);
21165dfecf96Smrg    ispell.formatMenu	= XtCreatePopupShell("formats", simpleMenuWidgetClass,
21175dfecf96Smrg					     ispell.options, NULL, 0);
21185dfecf96Smrg    XtRealizeWidget(ispell.formatMenu);
21195dfecf96Smrg
21205dfecf96Smrg    XtRealizeWidget(ispell.shell);
21215dfecf96Smrg
21225dfecf96Smrg    for (i = 0; i < sizeof(ispell_format) / sizeof(ispell_format[0]); i++) {
21235dfecf96Smrg	struct _ispell_format *fmt = &ispell_format[i];
21245dfecf96Smrg
21255dfecf96Smrg	fmt->sme = XtCreateManagedWidget(fmt->name, smeBSBObjectClass,
21265dfecf96Smrg					 ispell.formatMenu, NULL, 0);
21275dfecf96Smrg	XtAddCallback(fmt->sme, XtNcallback, ChangeFormatIspell, (XtPointer)fmt);
21285dfecf96Smrg
21295dfecf96Smrg	if (strcmp(fmt->name, ispell.formatting) == 0) {
21305dfecf96Smrg	    Arg args[1];
21315dfecf96Smrg
21325dfecf96Smrg	    XtSetArg(args[0], XtNlabel, ispell.formatting);
21335dfecf96Smrg	    XtSetValues(ispell.format, args, 1);
21345dfecf96Smrg	    XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
21355dfecf96Smrg	    XtSetValues(fmt->sme, args, 1);
21365dfecf96Smrg	    ispell.format_info = fmt;
21375dfecf96Smrg	}
21385dfecf96Smrg    }
21395dfecf96Smrg    if (ispell.format_info == NULL) {
21405dfecf96Smrg	Arg args[1];
21415dfecf96Smrg	char msg[256];
21425dfecf96Smrg
21435dfecf96Smrg	ispell.format_info = &ispell_format[TEXT];
21445dfecf96Smrg
21455dfecf96Smrg	XmuSnprintf(msg, sizeof(msg),
21465dfecf96Smrg		    "Unrecognized formatting type \"%s\", will use \"%s\"",
21475dfecf96Smrg		    ispell.formatting, ispell.format_info->name);
21485dfecf96Smrg	XtAppWarning(XtWidgetToApplicationContext(ispell.shell), msg);
21495dfecf96Smrg	ispell.formatting = ispell.format_info->name;
21505dfecf96Smrg
21515dfecf96Smrg	XtSetArg(args[0], XtNlabel, ispell.format_info->name);
21525dfecf96Smrg	XtSetValues(ispell.format, args, 1);
21535dfecf96Smrg	XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
21545dfecf96Smrg	XtSetValues(ispell.format_info->sme, args, 1);
21555dfecf96Smrg    }
21565dfecf96Smrg    XtGetApplicationResources(ispell_format[TEXT].sme, (XtPointer)&ispell,
21575dfecf96Smrg			      text_res, XtNumber(text_res), NULL, 0);
21585dfecf96Smrg
21595dfecf96Smrg    dict_res.resource_name = "wordChars";
21605dfecf96Smrg    dict_res.resource_class = "Chars";
21615dfecf96Smrg    dict_res.resource_type = XtRString;
21625dfecf96Smrg    dict_res.resource_size = sizeof(char*);
21635dfecf96Smrg    dict_res.resource_offset = XtOffsetOf(ispell_dict, wchars);
21645dfecf96Smrg    dict_res.default_type = XtRString;
21655dfecf96Smrg    dict_res.default_addr = "";
21665dfecf96Smrg
21675dfecf96Smrg    list = XtNewString(ispell.dict_list);
21685dfecf96Smrg
2169f14f4646Smrg    /* Create first empty entry */
2170f14f4646Smrg    dict = XtNew(ispell_dict);
2171f14f4646Smrg    dict->sme = XtCreateManagedWidget("", smeBSBObjectClass,
2172f14f4646Smrg				      ispell.dictMenu, NULL, 0);
2173f14f4646Smrg    dict->wchars = "";
2174f14f4646Smrg    XtAddCallback(dict->sme, XtNcallback, ChangeDictionaryIspell,
2175f14f4646Smrg		  (XtPointer)dict);
2176f14f4646Smrg    ispell.dict_info = prev_dict = dict;
2177f14f4646Smrg
2178f14f4646Smrg    for (str = strtok(list, " \t,"); str; str = strtok(NULL, " \t,")) {
2179f14f4646Smrg	dict = XtNew(ispell_dict);
2180f14f4646Smrg	dict->sme = XtCreateManagedWidget(str, smeBSBObjectClass,
2181f14f4646Smrg					  ispell.dictMenu, NULL, 0);
2182f14f4646Smrg	XtGetApplicationResources(dict->sme, (XtPointer)dict, &dict_res,
21835dfecf96Smrg				  1, NULL, 0);
2184f14f4646Smrg	XtAddCallback(dict->sme, XtNcallback, ChangeDictionaryIspell,
2185f14f4646Smrg		      (XtPointer)dict);
2186f14f4646Smrg	prev_dict->next = dict;
2187f14f4646Smrg	prev_dict = dict;
2188f14f4646Smrg	dict->next = NULL;
2189f14f4646Smrg    }
2190f14f4646Smrg    XtFree(list);
2191f14f4646Smrg
2192f14f4646Smrg    for (dict = ispell.dict_info; dict; dict = dict->next) {
2193f14f4646Smrg	if (strcmp(XtName(dict->sme), ispell.dictionary) == 0) {
21945dfecf96Smrg	    Arg args[1];
21955dfecf96Smrg
21965dfecf96Smrg	    XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
2197f14f4646Smrg	    XtSetValues(dict->sme, args, 1);
2198f14f4646Smrg	    XtSetArg(args[0], XtNlabel, XtName(dict->sme));
21995dfecf96Smrg	    XtSetValues(ispell.dict, args, 1);
2200f14f4646Smrg	    ispell.wchars = dict->wchars;
2201f14f4646Smrg	    break;
22025dfecf96Smrg	}
22035dfecf96Smrg    }
2204f14f4646Smrg
22055dfecf96Smrg
22065dfecf96Smrg    delete_window = XInternAtom(XtDisplay(ispell.shell), "WM_DELETE_WINDOW", False);
22075dfecf96Smrg    XSetWMProtocols(XtDisplay(ispell.shell), XtWindow(ispell.shell), &delete_window, 1);
22085dfecf96Smrg
22095dfecf96Smrg    return (True);
22105dfecf96Smrg}
2211