summaryrefslogtreecommitdiff
path: root/ispell.c
diff options
context:
space:
mode:
Diffstat (limited to 'ispell.c')
-rw-r--r--ispell.c2217
1 files changed, 2217 insertions, 0 deletions
diff --git a/ispell.c b/ispell.c
new file mode 100644
index 0000000..1066cb6
--- /dev/null
+++ b/ispell.c
@@ -0,0 +1,2217 @@
+/*
+ * Copyright (c) 1999 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+ *
+ * Author: Paulo César Pereira de Andrade
+ */
+
+/* $XFree86: xc/programs/xedit/ispell.c,v 1.19 2002/10/19 20:04:20 herrb Exp $ */
+
+#include "xedit.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <X11/Xaw/Toggle.h>
+#include <X11/Xaw/MenuButton.h>
+#include <X11/Xaw/SmeBSB.h>
+#include <X11/Xaw/SimpleMenu.h>
+
+#define RECEIVE 1
+#define SEND 2
+
+#define CHECK 0
+#define ADD 1
+#define REMOVE 2
+
+#define ASIS 1
+#define UNCAP 2
+
+/*
+ * Types
+ */
+#define UNDO_DEPTH 16
+typedef struct _ispell_undo {
+ char *undo_str;
+ int undo_count;
+ XawTextPosition undo_pos;
+ Boolean repeat; /* two (misspelled?) words together */
+ Boolean terse;
+ int format; /* remember text formatting style */
+ struct _ispell_undo *next, *prev;
+} ispell_undo;
+
+typedef struct _ispell_dict {
+ Widget sme;
+ char *wchars;
+ struct _ispell_dict *next;
+} ispell_dict;
+
+#define TEXT 0
+#define HTML 1
+struct _ispell_format {
+ char *name;
+ int value;
+ Widget sme;
+};
+
+static struct _ispell_format ispell_format[] = {
+ {"text", TEXT},
+ {"html", HTML},
+};
+
+struct _ispell {
+ Widget shell, form, mispelled, repeated, word, replacement, text,
+ suggestions, viewport, list, commands, replace, status,
+ replaceAll, undo, ignore, ignoreAll, add, addUncap, suspend,
+ cancel, check, look, terse, options, dict, dictMenu,
+ format, formatMenu;
+
+ Widget ascii, source;
+ XtInputId id;
+ int pid, ifd[2], ofd[2];
+ XawTextPosition left, right;
+ char *item;
+ Bool lock;
+ Bool repeat;
+ Bool checkit;
+ int stat;
+ char *buf;
+ int bufsiz;
+ int buflen;
+ char sendbuf[1024];
+ char sentbuf[1024];
+
+ int undo_depth;
+ ispell_undo *undo_head, *undo_base;
+ char *undo_for;
+
+ char *wchars;
+ char *cmd;
+ char *skip;
+ char *command;
+ Boolean terse_mode, undo_terse_mode;
+ char *guess_label, *miss_label, *root_label, *none_label, *eof_label,
+ *compound_label, *ok_label, *repeat_label, *working_label, *look_label;
+ char *look_cmd;
+ char *words_file;
+
+ char *dictionary;
+ char *dict_list;
+ ispell_dict *dict_info;
+
+ int format_mode; /* to undo correctly */
+ char *formatting;
+ struct _ispell_format *format_info;
+};
+
+typedef struct _ReplaceList {
+ char *word;
+ char *replace;
+ struct _ReplaceList *next;
+} ReplaceList;
+
+typedef struct _IgnoreList {
+ char *word;
+ int add;
+ struct _IgnoreList *next;
+} IgnoreList;
+
+/*
+ * Prototypes
+ */
+static void AddIspell(Widget, XtPointer, XtPointer);
+static void ChangeDictionaryIspell(Widget, XtPointer, XtPointer);
+static void ChangeFormatIspell(Widget, XtPointer, XtPointer);
+static void CheckIspell(Widget, XtPointer, XtPointer);
+static void IgnoreIspell(Widget, XtPointer, XtPointer);
+static Bool InitIspell(void);
+static void IspellCheckUndo(void);
+static int IspellConvertHtmlAmp(char*);
+static Bool IspellDoIgnoredWord(char*, int, int);
+static Bool IspellIgnoredWord(char*, int, int);
+static void IspellInputCallback(XtPointer, int*, XtInputId*);
+static void IspellKillUndoBuffer(void);
+static Bool IspellReceive(void);
+static char *IspellReplacedWord(char*, char*);
+static int IspellSend(void);
+static void IspellSetSelection(XawTextPosition, XawTextPosition);
+static void IspellSetRepeated(Bool);
+static void IspellSetSensitive(Bool);
+static void IspellSetStatus(char*);
+static void IspellSetTerseMode(Bool);
+static Bool IspellStartProcess(void);
+static Bool IspellEndProcess(Bool, Bool);
+static void LookIspell(Widget, XtPointer, XtPointer);
+static void PopdownIspell(Widget, XtPointer, XtPointer);
+static void ReplaceIspell(Widget, XtPointer, XtPointer);
+static void RevertIspell(Widget, XtPointer, XtPointer);
+static void SelectIspell(Widget, XtPointer, XtPointer);
+static void ToggleTerseIspell(Widget, XtPointer, XtPointer);
+#ifndef SIGNALRETURNSINT
+static void timeout_signal(int);
+static void (*old_timeout)(int);
+#else
+static int timeout_signal(int);
+static int (*old_timeout)(int);
+#endif
+static void UndoIspell(Widget, XtPointer, XtPointer);
+
+Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
+
+/*
+ * Initialization
+ */
+static struct _ispell ispell;
+
+#define RSTRTBLSZ 23
+#define ISTRTBLSZ 71
+static ReplaceList *replace_list[RSTRTBLSZ];
+static IgnoreList *ignore_list[ISTRTBLSZ];
+
+#ifndef XtCStatus
+#define XtCStatus "Status"
+#endif
+
+#define Offset(field) XtOffsetOf(struct _ispell, field)
+static XtResource resources[] = {
+ {"wordChars", "Chars", XtRString, sizeof(char*),
+ Offset(wchars), XtRString, ""},
+ {"ispellCommand", "CommandLine", XtRString, sizeof(char*),
+ Offset(cmd), XtRString, "/usr/local/bin/ispell"},
+ {"terseMode", "Terse", XtRBoolean, sizeof(Boolean),
+ Offset(terse_mode), XtRImmediate, (XtPointer)False},
+ {"guessLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(guess_label), XtRString, "Guess"},
+ {"missLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(miss_label), XtRString, "Miss"},
+ {"rootLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(root_label), XtRString, "Root:"},
+ {"noneLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(none_label), XtRString, "None"},
+ {"compoundLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(compound_label), XtRString, "Compound"},
+ {"okLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(ok_label), XtRString, "Ok"},
+ {"eofLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(eof_label), XtRString, "End Of File"},
+ {"repeatLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(repeat_label), XtRString, "Repeat"},
+ {"workingLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(working_label), XtRString, "..."},
+ {"lookLabel", XtCStatus, XtRString, sizeof(String),
+ Offset(look_label), XtRString, "Look"},
+ {"lookCommand", "CommandLine", XtRString, sizeof(char*),
+ Offset(look_cmd), XtRString, "/usr/bin/egrep -i"},
+ {"wordsFile", "Words", XtRString, sizeof(char*),
+ Offset(words_file), XtRString, "/usr/share/dict/words"},
+ {"dictionary", "Dictionary", XtRString, sizeof(char*),
+ Offset(dictionary), XtRString, "american"},
+ {"dictionaries", "Dictionary", XtRString, sizeof(char*),
+ Offset(dict_list), XtRString, "american americanmed+ english"},
+ {"formatting", "TextFormat", XtRString, sizeof(char*),
+ Offset(formatting), XtRString, "text"},
+};
+#undef Offset
+
+#ifdef NO_LIBC_I18N
+static int
+ToLower(int ch)
+{
+ char buf[2];
+
+ *buf = ch;
+ XmuNCopyISOLatin1Lowered(buf, buf, sizeof(buf));
+
+ return (*buf);
+}
+
+static int
+ToUpper(int ch)
+{
+ char buf[2];
+
+ *buf = ch;
+ XmuNCopyISOLatin1Uppered(buf, buf, sizeof(buf));
+
+ return (*buf);
+}
+
+static int
+IsLower(int ch)
+{
+ char upbuf[2];
+ char lobuf[2];
+
+ *upbuf = *lobuf = ch;
+ XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
+ XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
+
+ return (*lobuf != *upbuf && ch == *lobuf);
+}
+
+static int
+IsUpper(int ch)
+{
+ char upbuf[2];
+ char lobuf[2];
+
+ *upbuf = *lobuf = ch;
+ XmuNCopyISOLatin1Lowered(lobuf, lobuf, sizeof(lobuf));
+ XmuNCopyISOLatin1Uppered(upbuf, upbuf, sizeof(upbuf));
+
+ return (*lobuf != *upbuf && ch == *upbuf);
+}
+#else
+#define ToLower tolower
+#define ToUpper toupper
+#define IsLower islower
+#define IsUpper isupper
+#endif
+
+/*
+ * Implementation
+ */
+#ifdef STDERR_FILENO
+# define WRITES(s) write(STDERR_FILENO, s, strlen(s))
+#else
+# define WRITES(s) write(fileno(stderr), s, strlen(s))
+#endif
+
+/*ARGSUSED*/
+#ifndef SIGNALRETURNSINT
+static void
+timeout_signal(int unused)
+{
+ int olderrno = errno;
+
+ WRITES("Warning: Timeout waiting ispell process to die.\n");
+ kill(ispell.pid, SIGTERM);
+ errno = olderrno;
+}
+#else
+static int
+timeout_signal(int unused)
+{
+ int olderrno = errno;
+
+ WRITES("Warning: Timeout waiting ispell process to die.\n");
+ kill(ispell.pid, SIGTERM);
+
+ errno = olderrno;
+ return (0);
+}
+#endif
+
+static void
+IspellSetSelection(XawTextPosition left, XawTextPosition right)
+{
+ /* Try to make sure the selected word is completely visible */
+ XawTextSetInsertionPoint(ispell.ascii, right);
+ XawTextSetInsertionPoint(ispell.ascii, left);
+ XawTextSetSelection(ispell.ascii, left, right);
+}
+
+static void
+IspellSetStatus(char *label)
+{
+ Arg args[1];
+
+ XtSetArg(args[0], XtNlabel, label);
+ XtSetValues(ispell.status, args, 1);
+}
+
+static void
+IspellSetRepeated(Bool state)
+{
+ static char *mispelled, *repeated;
+ Arg args[1];
+
+ if (mispelled == NULL) {
+ XtSetArg(args[0], XtNlabel, &mispelled);
+ XtGetValues(ispell.mispelled, args, 1);
+ mispelled = XtNewString(mispelled);
+ }
+ if (repeated == NULL) {
+ XtSetArg(args[0], XtNlabel, &repeated);
+ XtGetValues(ispell.repeated, args, 1);
+ repeated = XtNewString(repeated);
+ }
+ XtSetSensitive(ispell.replaceAll, !state);
+ XtSetSensitive(ispell.ignoreAll, !state);
+ XtSetSensitive(ispell.add, !state);
+ XtSetSensitive(ispell.addUncap, !state);
+ if (!state) {
+ XtSetArg(args[0], XtNlabel, mispelled);
+ XtSetValues(ispell.mispelled, args, 1);
+ }
+ else {
+ XtSetArg(args[0], XtNlabel, repeated);
+ XtSetValues(ispell.mispelled, args, 1);
+ }
+}
+
+static void
+IspellSetSensitive(Bool state)
+{
+ XtSetSensitive(ispell.replace, state);
+ XtSetSensitive(ispell.replaceAll, state);
+ XtSetSensitive(ispell.ignore, state);
+ XtSetSensitive(ispell.ignoreAll, state);
+ XtSetSensitive(ispell.add, state);
+ XtSetSensitive(ispell.addUncap, state);
+}
+
+static void
+IspellSetTerseMode(Bool mode)
+{
+ Arg args[1];
+
+ XtSetArg(args[0], XtNstate, ispell.terse_mode = mode);
+ XtSetValues(ispell.terse, args, 1);
+ write(ispell.ofd[1], mode ? "!\n" : "%\n", 2);
+}
+
+static void
+IspellCheckUndo(void)
+{
+ ispell_undo *undo = XtNew(ispell_undo);
+
+ if (ispell.undo_for && strcmp(ispell.undo_for, ispell.dictionary)) {
+ XeditPrintf("Undo: Dictionary changed. Previous undo information lost.\n");
+ IspellKillUndoBuffer();
+ Feep();
+ }
+
+ undo->next = NULL;
+ undo->repeat = False;
+ undo->terse = ispell.undo_terse_mode;
+ undo->format = ispell.format_mode;
+ if ((undo->prev = ispell.undo_head) != NULL)
+ undo->prev->next = undo;
+ else
+ undo->prev = NULL;
+ ++ispell.undo_depth;
+ if (!ispell.undo_base) {
+ ispell.undo_base = undo;
+ XtSetSensitive(ispell.undo, True);
+ }
+ else if (ispell.undo_depth > UNDO_DEPTH) {
+ ispell_undo *tmp;
+
+ if (ispell.undo_base->undo_str)
+ XtFree(ispell.undo_base->undo_str);
+ tmp = ispell.undo_base->next;
+ XtFree((char*)ispell.undo_base);
+ tmp->prev = NULL;
+ ispell.undo_base = tmp;
+ ispell.undo_depth = UNDO_DEPTH;
+ }
+ ispell.undo_head = undo;
+}
+
+static char *
+IspellReplacedWord(char *word, char *replace)
+{
+ ReplaceList *list;
+ int ii = 0;
+ char *pp = word;
+
+ while (*pp)
+ ii = (ii << 1) ^ *pp++;
+ if (ii < 0)
+ ii = -ii;
+ ii %= RSTRTBLSZ;
+ for (list = replace_list[ii]; list; list = list->next)
+ if (strcmp(list->word, word) == 0) {
+ if (replace) {
+ XtFree(list->replace);
+ list->replace = XtNewString(replace);
+ }
+ return (list->replace);
+ }
+
+ if (!replace)
+ return (NULL);
+
+ list = XtNew(ReplaceList);
+ list->word = XtNewString(word);
+ list->replace = XtNewString(replace);
+ list->next = replace_list[ii];
+ replace_list[ii] = list;
+
+ return (list->replace);
+}
+
+static Bool
+IspellDoIgnoredWord(char *word, int cmd, int add)
+{
+ IgnoreList *list, *prev;
+ int ii = 0;
+ char *pp = word;
+
+ while (*pp)
+ ii = (ii << 1) ^ *pp++;
+ if (ii < 0)
+ ii = -ii;
+ ii %= ISTRTBLSZ;
+ for (prev = list = ignore_list[ii]; list; prev = list, list = list->next)
+ if (strcmp(list->word, word) == 0) {
+ if (cmd == REMOVE) {
+ XtFree(list->word);
+ prev->next = list->next;
+ XtFree((char*)list);
+ if (prev == list)
+ ignore_list[ii] = NULL;
+ return (True);
+ }
+ return (cmd == CHECK);
+ }
+
+ if (cmd != ADD)
+ return (False);
+
+ list = XtNew(IgnoreList);
+ list->word = XtNewString(word);
+ list->add = add;
+ list->next = ignore_list[ii];
+ ignore_list[ii] = list;
+
+ return (True);
+}
+
+static Bool
+IspellIgnoredWord(char *word, int cmd, int add)
+{
+ if (add != UNCAP && IspellDoIgnoredWord(word, cmd, add))
+ return (True);
+
+ /* add/remove uncapped word to/of list,
+ * or cheks for correct capitalization */
+ if (add == UNCAP || cmd == CHECK) {
+ unsigned char *str = (unsigned char*)word;
+ unsigned char string[1024];
+ Bool upper, status;
+ int i;
+
+ status = True;
+ upper = IsUpper(*str);
+ *string = upper ? ToLower(*str) : *str;
+ if (*str)
+ str++;
+ if (IsLower(*str))
+ upper = False;
+ for (i = 1; *str && i < sizeof(string) - 1; i++, str++) {
+ if (upper && IsLower(*str))
+ status = False;
+ else if (!upper && IsUpper(*str))
+ status = False;
+ string[i] = ToLower(*str);
+ }
+ string[i] = '\0';
+
+ if ((cmd != CHECK || status) &&
+ IspellDoIgnoredWord((char*)string, cmd, add))
+ return (True);
+ }
+
+ return (False);
+}
+
+/*ARGSUSED*/
+static Bool
+IspellReceive(void)
+{
+ int i, len, old_len;
+ Arg args[2];
+ char *str, *end, **list, **old_list;
+ char *tmp, word[1024];
+ int j;
+
+ if (ispell.lock || ispell.stat != RECEIVE)
+ return (False);
+
+ while (1) { /* read the entire line */
+ if (ispell.buflen >= ispell.bufsiz - 1)
+ ispell.buf = XtRealloc(ispell.buf, ispell.bufsiz += BUFSIZ);
+ if ((len = read(ispell.ifd[0], &ispell.buf[ispell.buflen],
+ ispell.bufsiz - ispell.buflen - 1)) <= 0)
+ break;
+ ispell.buflen += len;
+ }
+ if (ispell.buflen <= 0)
+ return (False);
+ len = 0;
+ i = ispell.buflen - 1;
+ while (i >= 0 && ispell.buf[i] == '\n') {
+ ++len;
+ --i;
+ }
+ if (len < 2 - ((ispell.terse_mode && i == -1) || ispell.buf[0] == '@'))
+ return (False);
+ ispell.buf[ispell.buflen - len] = '\0';
+ ispell.buflen = 0;
+
+ if ((tmp = strchr(ispell.sendbuf, '\n')) != NULL)
+ *tmp = '\0';
+
+ switch (ispell.buf[0]) {
+ case '&': /* MISS */
+ case '?': /* GUESS */
+ str = strchr(&ispell.buf[2], ' ');
+ if (!ispell.checkit) {
+ *str = '\0';
+ XtSetArg(args[0], XtNlabel, &ispell.buf[2]);
+ XtSetValues(ispell.word, args, 1);
+ }
+ ++str;
+ list = NULL;
+ str = strchr(str, ':') + 1;
+ for (i = 0; ; i++) {
+ end = strchr(str, ',');
+ if (end) *end = '\0';
+ if ((i % 16) == 0)
+ list = (char**)XtRealloc((char*)list, (i + 16) * sizeof(char*));
+ tmp = word;
+ for (j = 1; j < sizeof(word) && str[j]; j++) {
+ if (str[j] == '+')
+ continue;
+ else if (str[j] == '-' && str[j+1] != '-' && str[j-1] != '-') {
+ char *p, string[256];
+ int k, l;
+
+ for (l = 0, k = j + 1; str[k] != '+' && str[k] != '-'
+ && str[k] && l < sizeof(string) - 1; k++, l++)
+ string[l] = str[k];
+ string[l] = '\0';
+ *tmp = '\0';
+ if (l && (p = strstr(word, string)) != NULL) {
+ char *sav = p;
+
+ while ((p = strstr(p + l, string)) != NULL)
+ sav = p;
+ p = sav;
+ if (strcmp(p, string) == 0) {
+ tmp = p;
+ j = k - 1;
+ }
+ else
+ *tmp++ = '-';
+ }
+ else
+ *tmp++ = '-';
+ }
+ else
+ *tmp++ = str[j];
+ }
+ *tmp = '\0';
+ list[i] = XtNewString(word);
+
+ if (end) str = end + 1;
+ else break;
+ }
+ len = i + 1;
+
+ XtSetArg(args[0], XtNlist, &old_list);
+ XtSetArg(args[1], XtNnumberStrings, &old_len);
+ XtGetValues(ispell.list, args, 2);
+
+ ispell.item = NULL;
+ if ((str = IspellReplacedWord(&ispell.buf[2], NULL)) != NULL)
+ for (i = 0; i < len; i++) {
+ if (strcmp(list[i], str) == 0) {
+ ispell.item = list[i];
+ break;
+ }
+ }
+ else
+ ispell.item = list[i = 0];
+ if (!ispell.item) {
+ list = (char**)XtRealloc((char*)list, (len + 1) * sizeof(char*));
+ ispell.item = list[i] = XtNewString(str);
+ ++len;
+ }
+
+ XtSetArg(args[0], XtNlist, list);
+ XtSetArg(args[1], XtNnumberStrings, len);
+ XtSetValues(ispell.list, args, 2);
+
+ XtSetSensitive(ispell.list, True);
+ if (!ispell.checkit)
+ XawListHighlight(ispell.list, i);
+
+ if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
+ while (--old_len > -1)
+ XtFree(old_list[old_len]);
+ XtFree((char*)old_list);
+ }
+
+ if (!ispell.checkit) {
+ XtSetArg(args[0], XtNstring, ispell.item);
+ XtSetValues(ispell.text, args, 1);
+ IspellSetSelection(ispell.left, ispell.right);
+ if (ispell.repeat)
+ IspellSetRepeated(ispell.repeat = False);
+ }
+
+ IspellSetStatus(ispell.buf[0] == '?' ?
+ ispell.guess_label : ispell.miss_label);
+ ispell.undo_terse_mode = ispell.terse_mode;
+ ispell.format_mode = ispell.format_info->value;
+ ispell.lock = True;
+ break;
+ case '#': /* NONE */
+ case '-': /* COMPOUND */
+ case '+': /* ROOT */
+ check_label:
+ str = &ispell.sendbuf[1];
+ if (!ispell.checkit) {
+ XtSetArg(args[0], XtNlabel, str);
+ XtSetValues(ispell.word, args, 1);
+ }
+
+ XtSetArg(args[0], XtNlist, &old_list);
+ XtSetArg(args[1], XtNnumberStrings, &old_len);
+ XtGetValues(ispell.list, args, 2);
+ ispell.item = NULL;
+
+ list = (char**)XtMalloc(sizeof(char**));
+ if ((tmp = IspellReplacedWord(str, NULL)) != NULL)
+ str = tmp;
+ if (tmp == NULL && ispell.buf[0] == '#')
+ list[0] = XtNewString("");
+ else
+ list[0] = XtNewString(str);
+
+ XtSetArg(args[0], XtNlist, list);
+ XtSetArg(args[1], XtNnumberStrings, 1);
+ XtSetValues(ispell.list, args, 2);
+
+ if (tmp == NULL && ispell.buf[0] == '#') {
+ XawListUnhighlight(ispell.list);
+ XtSetSensitive(ispell.list, False);
+ }
+ else {
+ XtSetSensitive(ispell.list, True);
+ if (!ispell.checkit)
+ XawListHighlight(ispell.list, 0);
+ }
+ if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
+ while (--old_len > -1)
+ XtFree(old_list[old_len]);
+ XtFree((char*)old_list);
+ }
+
+ if (!ispell.checkit) {
+ XtSetArg(args[0], XtNstring, str);
+ XtSetValues(ispell.text, args, 1);
+ IspellSetSelection(ispell.left, ispell.right);
+ if (ispell.repeat)
+ IspellSetRepeated(ispell.repeat = False);
+ }
+
+ ispell.undo_terse_mode = ispell.terse_mode;
+ ispell.format_mode = ispell.format_info->value;
+ ispell.lock = True;
+ if (ispell.buf[0] == '+') {
+ if ((tmp = strchr(&ispell.buf[2], '\n')) != NULL)
+ *tmp = '\0';
+ XmuSnprintf(word, sizeof(word), "%s %s",
+ ispell.root_label, &ispell.buf[2]);
+ IspellSetStatus(word);
+ }
+ else
+ IspellSetStatus(ispell.buf[0] == '#' ? ispell.none_label :
+ ispell.buf[0] == '-' ? ispell.compound_label :
+ ispell.ok_label);
+ break;
+ case '*': /* OK */
+ case '\0': /* when running in terse mode */
+ if (!ispell.checkit)
+ (void)IspellIgnoredWord(&ispell.sendbuf[1], ADD, 0);
+ else
+ goto check_label;
+ ispell.lock = False;
+ break;
+ case '@': /* Ispell banner */
+ /* it only happens when the dictionary is changed */
+ if (!ispell.repeat) {
+ XawTextPosition left, right;
+
+ ispell.stat = SEND;
+ while (IspellSend() == 0)
+ ;
+ /* word chars may have changed */
+ XawTextGetSelectionPos(ispell.ascii, &left, &right);
+ if (left != ispell.left || right != ispell.right) {
+ XtSetArg(args[0], XtNstring, &ispell.sendbuf[1]);
+ XtSetValues(ispell.text, args, 1);
+ IspellSetSelection(ispell.left, ispell.right);
+ }
+ ispell.checkit = True;
+ }
+ else {
+ IspellSetStatus(ispell.repeat_label);
+ ispell.undo_terse_mode = ispell.terse_mode;
+ ispell.format_mode = ispell.format_info->value;
+ ispell.lock = True;
+ return (True);
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown ispell command '%c'\n", ispell.buf[0]);
+ return (False);
+ }
+
+ if (!ispell.lock && !ispell.checkit) {
+ ispell.stat = SEND;
+ while (IspellSend() == 0)
+ ;
+ }
+
+ return (True);
+}
+
+static int
+IspellConvertHtmlAmp(char *buf)
+{
+ int len, ch = '?';
+
+ /* this function is static, so I can do it */
+ *strchr(++buf, ';') = '\0';
+
+ len = strlen(buf);
+ if (len == 0)
+ return ('&');
+ if (len > 1) {
+ if (strcasecmp(&buf[1], "lt") == 0)
+ ch = '<';
+ else if (strcasecmp(&buf[1], "gt") == 0)
+ ch = '>';
+ else if (strcasecmp(&buf[1], "nbsp") == 0)
+ ch = ' ';
+ else if (strcasecmp(&buf[1], "amp") == 0)
+ ch = '&';
+ else if (strcasecmp(&buf[1], "quot") == 0)
+ ch = '"';
+ else if (*buf == '#') {
+ char *tmp;
+
+ if (len == 1);
+ return ('?');
+ ch = strtol(&buf[1], &tmp, 10);
+ if (*tmp)
+ fprintf(stderr, "Warning: bad html interpreting '&#' mark.\n");
+ }
+ else if (strcmp(&buf[1], "acute") == 0) {
+ switch (*buf) {
+ case 'a': ch = 'á'; break;
+ case 'e': ch = 'é'; break;
+ case 'i': ch = 'í'; break;
+ case 'o': ch = 'ó'; break;
+ case 'u': ch = 'ú'; break;
+ case 'A': ch = 'Á'; break;
+ case 'E': ch = 'É'; break;
+ case 'I': ch = 'Í'; break;
+ case 'O': ch = 'Ó'; break;
+ case 'U': ch = 'Ú'; break;
+ }
+ }
+ else if (strcmp(&buf[1], "grave") == 0) {
+ switch (*buf) {
+ case 'a': ch = 'à'; break;
+ case 'e': ch = 'è'; break;
+ case 'i': ch = 'ì'; break;
+ case 'o': ch = 'ò'; break;
+ case 'u': ch = 'ù'; break;
+ case 'A': ch = 'À'; break;
+ case 'E': ch = 'È'; break;
+ case 'I': ch = 'Ì'; break;
+ case 'O': ch = 'Ò'; break;
+ case 'U': ch = 'Ù'; break;
+ }
+ }
+ else if (strcmp(&buf[1], "tilde") == 0) {
+ switch (*buf) {
+ case 'a': ch = 'ã'; break;
+ case 'o': ch = 'õ'; break;
+ case 'n': ch = 'ñ'; break;
+ case 'A': ch = 'ã'; break;
+ case 'O': ch = 'Õ'; break;
+ case 'N': ch = 'Ñ'; break;
+ }
+ }
+ else if (strcmp(&buf[1], "circ") == 0) {
+ switch (*buf) {
+ case 'a': ch = 'â'; break;
+ case 'e': ch = 'ê'; break;
+ case 'i': ch = 'î'; break;
+ case 'o': ch = 'ô'; break;
+ case 'u': ch = 'û'; break;
+ case 'A': ch = 'Â'; break;
+ case 'E': ch = 'Ê'; break;
+ case 'I': ch = 'Î'; break;
+ case 'O': ch = 'Ô'; break;
+ case 'U': ch = 'Û'; break;
+ }
+ }
+ else if (strcmp(&buf[1], "cedil") == 0) {
+ switch (*buf) {
+ case 'c': ch = 'ç'; break;
+ case 'C': ch = 'Ç'; break;
+ }
+ }
+ /* add more cases here */
+ }
+
+ return (ch);
+}
+
+/*ARGSUSED*/
+static int
+IspellSend(void)
+{
+ XawTextPosition position, old_left, pos;
+ XawTextBlock block;
+ int i, len, spaces, nls;
+ Bool nl, html, inside_html;
+ char ampbuf[32];
+ int amplen;
+
+ if (ispell.lock || ispell.stat != SEND)
+ return (-1);
+
+ len = 1;
+ ispell.sendbuf[0] = '^'; /* don't evaluate following characters as commands */
+
+ spaces = nls = 0;
+
+ html = ispell.format_info->value == HTML;
+ inside_html = False;
+ amplen = 0;
+
+ /* skip non word characters */
+ pos = position = ispell.right;
+ nl = False;
+ while (1) {
+ Bool done = False;
+ char mb[sizeof(wchar_t)];
+
+ retry_html_space:
+ position = XawTextSourceRead(ispell.source, position,
+ &block, BUFSIZ);
+ if (block.length == 0) { /* end of file */
+ ispell.stat = 0;
+ ispell.lock = True;
+ XawTextSetInsertionPoint(ispell.ascii, ispell.right);
+ XawTextUnsetSelection(ispell.ascii);
+ IspellSetSensitive(False);
+ IspellSetStatus(ispell.eof_label);
+ return (-1);
+ }
+ for (i = 0; i < block.length; i++) {
+ if (international)
+ wctomb(mb, ((wchar_t*)block.ptr)[i]);
+ else
+ *mb = block.ptr[i];
+ if (amplen) {
+ if (amplen + 2 >= sizeof(ampbuf)) {
+ if (!ispell.terse_mode)
+ fprintf(stderr, "Warning: error interpreting '&' mark.\n");
+ amplen = 0;
+ position = pos + 1;
+ goto retry_html_space;
+ }
+ else if ((ampbuf[amplen++] = *mb) == ';') {
+ int ch;
+
+ ampbuf[amplen] = '\0';
+ ch = IspellConvertHtmlAmp(ampbuf);
+ amplen = 0;
+ if (isalpha(ch) ||
+ (ch && strchr(ispell.wchars, ch))) {
+ /* interpret it again */
+ ispell.right = pos;
+ i = 0;
+ done = True;
+ break;
+ }
+ else if ((ch == '\n' || isspace(ch)) && spaces >= 0)
+ ++spaces;
+ else
+ spaces = -1;
+ }
+ }
+ else if (html && *mb == '&') {
+ ampbuf[amplen++] = *mb;
+ pos = block.firstPos + i;
+ continue;
+ }
+ else if ((!html || !inside_html) && (isalpha(*mb) ||
+ (*mb && strchr(ispell.wchars, *mb)))) {
+ done = True;
+ break;
+ }
+ else if (!html && *mb == '\n') {
+ nl = True;
+ if (++nls > 1 && (!html || !inside_html))
+ spaces = -1;
+ else if (spaces >= 0)
+ ++spaces;
+ }
+ else if (nl) {
+ nl = False;
+ if (*mb && strchr(ispell.skip, *mb)) {
+ position = ispell.right =
+ XawTextSourceScan(ispell.source, ispell.right + i,
+ XawstEOL, XawsdRight, 1, False);
+ i = 0;
+ break;
+ }
+ else if (spaces >= 0 && isspace(*mb))
+ ++spaces;
+ else
+ spaces = -1;
+ }
+ else if (html && inside_html) {
+ if (*mb == '>')
+ inside_html = False;
+ }
+ else if (html && *mb == '<')
+ inside_html = True;
+ else if (spaces >= 0 && (isspace(*mb) || (html && *mb == '\n')))
+ ++spaces;
+ else
+ spaces = -1;
+ }
+
+ ispell.right += i;
+ if (done)
+ break;
+ }
+
+ old_left = ispell.left;
+
+ /* read a word */
+ position = ispell.left = ispell.right;
+ while (1) {
+ Bool done = False;
+ char mb[sizeof(wchar_t)];
+
+ retry_html_word:
+ position = XawTextSourceRead(ispell.source, position,
+ &block, BUFSIZ);
+ if (block.length == 0 && len == 1) { /* end of file */
+ ispell.stat = 0;
+ ispell.lock = True;
+ XawTextSetInsertionPoint(ispell.ascii, ispell.right);
+ XawTextUnsetSelection(ispell.ascii);
+ IspellSetSensitive(False);
+ IspellSetStatus(ispell.eof_label);
+ return (-1);
+ }
+ for (i = 0; i < block.length; i++) {
+ if (international)
+ wctomb(mb, ((wchar_t*)block.ptr)[i]);
+ else
+ *mb = block.ptr[i];
+ if (amplen) {
+ if (amplen + 2 >= sizeof(ampbuf)) {
+ if (!ispell.terse_mode)
+ fprintf(stderr, "Warning: error interpreting '&' mark.\n");
+ amplen = 0;
+ position = pos + 1;
+ if (strchr(ispell.wchars, '&')) {
+ if (len + 1 >= sizeof(ispell.sendbuf) - 1) {
+ done = True;
+ fprintf(stderr, "Warning: word is too large!\n");
+ break;
+ }
+ ispell.sendbuf[len++] = '&';
+ goto retry_html_word;
+ }
+ else {
+ ispell.right = position;
+ i = 0;
+ done = True;
+ break;
+ }
+ }
+ else if ((ampbuf[amplen++] = *mb) == ';') {
+ int ch;
+
+ ampbuf[amplen] = '\0';
+ ch = IspellConvertHtmlAmp(ampbuf);
+ amplen = 0;
+ if (!isalpha(ch) &&
+ (!ch || !strchr(ispell.wchars, ch))) {
+ ispell.right = pos;
+ i = 0;
+ done = True;
+ break;
+ }
+ *mb = ch;
+ }
+ else
+ continue;
+ }
+ else if (html && *mb == '&') {
+ ampbuf[amplen++] = *mb;
+ pos = block.firstPos + i;
+ continue;
+ }
+ else if (!isalpha(*mb) && (!*mb || !strchr(ispell.wchars, *mb))) {
+ done = True;
+ break;
+ }
+ ispell.sendbuf[len] = *mb;
+ if (++len >= sizeof(ispell.sendbuf) - 1) {
+ done = True;
+ fprintf(stderr, "Warning: word is too large!\n");
+ break;
+ }
+ }
+ ispell.right += i;
+ if (done || block.length == 0)
+ break;
+ }
+
+ ispell.sendbuf[len] = '\0';
+
+ if (spaces > 0 && spaces <= 32 && strcmp(ispell.sendbuf, ispell.sentbuf) == 0) {
+ Arg args[2];
+ int old_len;
+ char **list, **old_list;
+ char label[sizeof(ispell.sendbuf) + sizeof(ispell.sentbuf) + 32];
+
+ strcpy(label, &ispell.sendbuf[1]);
+ for (i = 0; i < spaces; i++)
+ label[len + i - 1] = ' ';
+ strcpy(&label[len + i - 1], &ispell.sendbuf[1]);
+ XtSetArg(args[0], XtNlabel, label);
+ XtSetValues(ispell.word, args, 1);
+
+ XtSetArg(args[0], XtNstring, &ispell.sendbuf[1]);
+ XtSetValues(ispell.text, args, 1);
+
+ XtSetArg(args[0], XtNlist, &old_list);
+ XtSetArg(args[1], XtNnumberStrings, &old_len);
+ XtGetValues(ispell.list, args, 2);
+ list = (char**)XtMalloc(sizeof(char**));
+ list[0] = XtNewString(&ispell.sendbuf[1]);
+ XtSetArg(args[0], XtNlist, list);
+ XtSetArg(args[1], XtNnumberStrings, 1);
+ XtSetValues(ispell.list, args, 2);
+ XtSetSensitive(ispell.list, True);
+ XawListHighlight(ispell.list, 0);
+ if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
+ while (--old_len > -1)
+ XtFree(old_list[old_len]);
+ XtFree((char*)old_list);
+ }
+
+ IspellSetRepeated(True);
+ IspellSetSelection(old_left, ispell.right);
+ IspellSetStatus(ispell.repeat_label);
+ ispell.repeat = ispell.lock = True;
+
+ return (1);
+ }
+ strcpy(ispell.sentbuf, ispell.sendbuf);
+
+ if (len <= 2 || IspellIgnoredWord(&ispell.sendbuf[1], CHECK, 0))
+ return (0);
+
+ ispell.sendbuf[len++] = '\n';
+
+ write(ispell.ofd[1], ispell.sendbuf, len);
+
+ ispell.stat = RECEIVE;
+
+ return (1);
+}
+
+/*ARGSUSED*/
+static void
+IspellInputCallback(XtPointer closure, int *source, XtInputId *id)
+{
+ if (ispell.right < 0) {
+ int len;
+ char buf[1024];
+
+ ispell.right = XawTextGetInsertionPoint(ispell.ascii);
+ ispell.right = XawTextSourceScan(ispell.source, ispell.right,
+ XawstEOL, XawsdLeft, 1, True);
+ len = read(ispell.ifd[0], buf, sizeof(buf));
+ if (strncmp(buf, "@(#)", 4) == 0) {
+ Arg args[1];
+
+ buf[len - 1] = '\0';
+ XtSetArg(args[0], XtNtitle, &buf[5]);
+ XtSetValues(ispell.shell, args, 1);
+ }
+ else
+ fprintf(stderr, "Error: is ispell talking with me?\n");
+ IspellSetTerseMode(ispell.terse_mode);
+ while (IspellSend() == 0)
+ ;
+ }
+ else if (ispell.source)
+ IspellReceive();
+}
+
+/*ARGSUSED*/
+void
+IspellCallback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Cardinal zero = 0;
+
+ IspellAction(textwindow, NULL, NULL, &zero);
+}
+
+/*ARGSUSED*/
+void
+IspellAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ Arg args[3];
+ Cardinal num_args;
+ char **strs, **list;
+ int n_strs;
+ Bool first_time = InitIspell();
+
+ if (*num_params == 1 && (params[0][0] == 'e' || params[0][0] == 'E')) {
+ PopdownIspell(w, (XtPointer)True, NULL);
+ return;
+ }
+
+ if (!XtIsSubclass(w, textWidgetClass) || ispell.source) {
+ Feep();
+ return;
+ }
+
+ ispell.source = XawTextGetSource(ispell.ascii = w);
+
+ if (first_time) {
+ /* let the user choose the better position for the ispell window */
+ Dimension width, height, b_width;
+ Position x, y, max_x, max_y;
+
+ x = y = -1;
+ if (event) {
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ x = event->xbutton.x_root;
+ y = event->xbutton.y_root;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ x = event->xkey.x_root;
+ y = event->xkey.y_root;
+ break;
+ }
+ }
+ if (x < 0 || y < 0) {
+ Window r, c;
+ int rx, ry, wx, wy;
+ unsigned mask;
+
+ XQueryPointer(XtDisplay(ispell.shell), XtWindow(ispell.shell),
+ &r, &c, &rx, &ry, &wx, &wy, &mask);
+ x = rx;
+ y = ry;
+ }
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNwidth, &width); num_args++;
+ XtSetArg(args[num_args], XtNheight, &height); num_args++;
+ XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++;
+ XtGetValues(ispell.shell, args, num_args);
+
+ width += b_width << 1;
+ height += b_width << 1;
+
+ x -= (Position)(width >> 1);
+ if (x < 0)
+ x = 0;
+ if (x > (max_x = (Position)(XtScreen(w)->width - width)))
+ x = max_x;
+
+ y -= (Position)(height >> 1);
+ if (y < 0)
+ y = 0;
+ if (y > (max_y = (Position)(XtScreen(w)->height - height)))
+ y = max_y;
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNx, x); num_args++;
+ XtSetArg(args[num_args], XtNy, y); num_args++;
+ XtSetValues(ispell.shell, args, num_args);
+ }
+
+ if (ispell.repeat)
+ IspellSetRepeated(False);
+ ispell.lock = ispell.repeat = ispell.checkit = False;
+ ispell.stat = SEND;
+
+ IspellSetSensitive(True);
+ XtSetSensitive(ispell.undo, False);
+
+ XtSetArg(args[0], XtNlabel, "");
+ XtSetValues(ispell.word, args, 1);
+
+ XtSetArg(args[0], XtNstring, "");
+ XtSetValues(ispell.text, args, 1);
+
+ XtSetArg(args[0], XtNlist, &strs);
+ XtSetArg(args[1], XtNnumberStrings, &n_strs);
+ XtGetValues(ispell.list, args, 2);
+
+ list = (char**)XtMalloc(sizeof(char**));
+ list[0] = XtNewString("");
+ XtSetArg(args[0], XtNlist, list);
+ XtSetArg(args[1], XtNnumberStrings, 1);
+ XtSetValues(ispell.list, args, 2);
+
+ if (n_strs > 1 || (XtName(ispell.list) != strs[0])) {
+ while (--n_strs > -1)
+ XtFree(strs[n_strs]);
+ XtFree((char*)strs);
+ }
+
+ IspellSetStatus(ispell.working_label);
+
+ if (!ispell.pid)
+ (void)IspellStartProcess();
+ else {
+ ispell.right = XawTextGetInsertionPoint(ispell.ascii);
+ ispell.right = XawTextSourceScan(ispell.source, ispell.right,
+ XawstEOL, XawsdLeft, 1, True);
+ while (IspellSend() == 0)
+ ;
+ }
+
+ XtPopup(ispell.shell, XtGrabExclusive);
+ XtSetKeyboardFocus(ispell.shell, ispell.text);
+}
+
+static Bool
+IspellStartProcess(void)
+{
+ if (!ispell.pid) {
+ int len;
+ char *command;
+
+ ispell.source = XawTextGetSource(ispell.ascii);
+
+ len = strlen(ispell.cmd) + strlen(ispell.dictionary) +
+ strlen(ispell.wchars) + 16;
+ command = XtMalloc(len);
+ XmuSnprintf(command, len, "%s -a -d '%s' -w '%s'",
+ ispell.cmd, ispell.dictionary, ispell.wchars);
+
+ pipe(ispell.ifd);
+ pipe(ispell.ofd);
+ if ((ispell.pid = fork()) == 0) {
+ close(0);
+ close(1);
+ dup2(ispell.ofd[0], 0);
+ dup2(ispell.ifd[1], 1);
+ close(ispell.ofd[0]);
+ close(ispell.ofd[1]);
+ close(ispell.ifd[0]);
+ close(ispell.ifd[1]);
+ execl("/bin/sh", "sh", "-c", command, (void *)NULL);
+ exit(-127);
+ }
+ else if (ispell.pid < 0) {
+ fprintf(stderr, "Cannot fork\n");
+ exit(1);
+ }
+ ispell.buf = XtMalloc(ispell.bufsiz = BUFSIZ);
+ ispell.right = -1;
+ ispell.id = XtAppAddInput(XtWidgetToApplicationContext(ispell.shell),
+ ispell.ifd[0], (XtPointer)XtInputReadMask,
+ IspellInputCallback, NULL);
+ fcntl(ispell.ifd[0], F_SETFL, O_NONBLOCK);
+ }
+ else
+ return (False);
+
+ return (True);
+}
+
+/*ARGSUSED*/
+static void
+PopdownIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ (void)IspellEndProcess((Bool)(long)client_data, True);
+ XtPopdown(ispell.shell);
+ *ispell.sentbuf = '\0';
+}
+
+static Bool
+IspellEndProcess(Bool killit, Bool killundo)
+{
+ ispell.source = NULL;
+
+ if (ispell.pid) {
+ IgnoreList *il, *pil, *nil;
+ int i;
+
+ /* insert added words in private dictionary */
+ for (i = 0; i < ISTRTBLSZ; i++) {
+ pil = il = ignore_list[i];
+ while (il) {
+ if (il->add) {
+ nil = il->next;
+ if (il == pil)
+ ignore_list[i] = nil;
+ else
+ pil->next = nil;
+ if (il->add == UNCAP)
+ write(ispell.ofd[1], "&", 1);
+ else
+ write(ispell.ofd[1], "*", 1);
+ write(ispell.ofd[1], il->word, strlen(il->word));
+ write(ispell.ofd[1], "\n", 1);
+ XtFree(il->word);
+ XtFree((char*)il);
+ il = nil;
+ }
+ else
+ il = il->next;
+ pil = il;
+ }
+ }
+ write(ispell.ofd[1], "#\n", 2); /* save dictionary */
+
+ if (killit) {
+ ReplaceList *rl, *prl;
+
+ XtRemoveInput(ispell.id);
+
+ close(ispell.ofd[0]);
+ close(ispell.ofd[1]);
+ close(ispell.ifd[0]);
+ close(ispell.ifd[1]);
+
+ /* if something goes wrong, we don't want to block here forever */
+ old_timeout = signal(SIGALRM, timeout_signal);
+ alarm(10);
+ waitpid(ispell.pid, NULL, 0);
+ alarm(0);
+ signal(SIGALRM, old_timeout);
+
+ ispell.pid = 0;
+ if (ispell.buf)
+ XtFree(ispell.buf);
+ ispell.buf = NULL;
+
+ for (i = 0; i < RSTRTBLSZ; i++) {
+ prl = rl = replace_list[i];
+ while (prl) {
+ rl = rl->next;
+ XtFree(prl->word);
+ XtFree(prl->replace);
+ XtFree((char*)prl);
+ prl = rl;
+ }
+ replace_list[i] = NULL;
+ }
+ for (i = 0; i < ISTRTBLSZ; i++) {
+ pil = il = ignore_list[i];
+ while (pil) {
+ il = il->next;
+ XtFree(pil->word);
+ XtFree((char*)pil);
+ pil = il;
+ }
+ ignore_list[i] = NULL;
+ }
+ }
+
+ if (killundo)
+ IspellKillUndoBuffer();
+ }
+ else
+ return (False);
+
+ return (True);
+}
+
+static void
+IspellKillUndoBuffer(void)
+{
+ ispell_undo *undo, *pundo;
+
+ undo = pundo = ispell.undo_base;
+ while (undo) {
+ undo = undo->next;
+ if (pundo->undo_str)
+ XtFree(pundo->undo_str);
+ XtFree((char*)pundo);
+ pundo = undo;
+ }
+ ispell.undo_base = ispell.undo_head = NULL;
+ ispell.undo_for = NULL;
+ ispell.undo_depth = 0;
+ XtSetSensitive(ispell.undo, False);
+}
+
+/*ARGSUSED*/
+static void
+RevertIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Arg args[1];
+ char *string, *repstr = NULL;
+
+ XtSetArg(args[0], XtNlabel, &string);
+ XtGetValues(ispell.word, args, 1);
+ if ((repstr = strchr(string, ' ')) != NULL) {
+ string = repstr = XtNewString(string);
+ *strchr(repstr, ' ') = '\0';
+ }
+ XtSetArg(args[0], XtNstring, string);
+ XtSetValues(ispell.text, args, 1);
+ if (repstr)
+ XtFree(repstr);
+}
+
+/*ARGSUSED*/
+static void
+SelectIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ XawListReturnStruct *info = (XawListReturnStruct *)call_data;
+ Arg args[1];
+
+ XtSetArg(args[0], XtNstring, ispell.item = info->string);
+ XtSetValues(ispell.text, args, 1);
+}
+
+/*ARGSUSED*/
+void
+ReplaceIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ XawTextPosition pos = XawTextGetInsertionPoint(ispell.ascii);
+ XawTextBlock check, search, replace;
+ Arg args[1];
+ char *text;
+
+ if (!ispell.lock)
+ return;
+
+ XtSetArg(args[0], XtNlabel, &text);
+ XtGetValues(ispell.word, args, 1);
+ search.ptr = text;
+ search.format = XawFmt8Bit;
+ search.firstPos = 0;
+ search.length = ispell.right - pos;
+
+ XtSetArg(args[0], XtNstring, &text);
+ XtGetValues(ispell.text, args, 1);
+ replace.ptr = text;
+ replace.format = XawFmt8Bit;
+ replace.firstPos = 0;
+ replace.length = strlen(text);
+
+ if (strcmp(search.ptr, replace.ptr) != 0 &&
+ XawTextReplace(ispell.ascii, pos, pos + search.length,
+ &replace) == XawEditDone) {
+ ispell.right += replace.length - search.length;
+ IspellCheckUndo();
+ ispell.undo_head->undo_str = NULL;
+ ispell.undo_head->undo_pos = pos;
+ ispell.undo_head->undo_count = 1;
+
+ if (ispell.repeat) {
+ ispell.undo_head->repeat = 2; /* To recognize later it was replaced */
+ ispell.undo_head->undo_count = ispell.right;
+ ispell.undo_head->undo_str = XtNewString(search.ptr);
+ }
+ if (client_data && !ispell.repeat) {
+ XawTextDisableRedisplay(ispell.ascii);
+ pos = ispell.right;
+ while ((pos = XawTextSourceSearch(ispell.source, pos, XawsdRight, &search))
+ != XawTextSearchError) {
+ Bool do_replace = True;
+ char mb[sizeof(wchar_t)];
+
+ if (XawTextSourceRead(ispell.source, pos - 1, &check, 1) > 0) {
+ if (international)
+ wctomb(mb, *(wchar_t*)check.ptr);
+ else
+ *mb = *check.ptr;
+ do_replace = !isalpha(*mb) && *mb && !strchr(ispell.wchars, *mb);
+ }
+ if (do_replace &&
+ XawTextSourceRead(ispell.source, pos + search.length, &check, 1) > 0) {
+ if (international)
+ wctomb(mb, *(wchar_t*)check.ptr);
+ else
+ *mb = *check.ptr;
+ do_replace = !isalpha(*mb) && *mb && !strchr(ispell.wchars, *mb);
+ }
+ if (do_replace) {
+ XawTextReplace(ispell.ascii, pos, pos + search.length, &replace);
+ ++ispell.undo_head->undo_count;
+ }
+ pos += search.length;
+ }
+ XawTextEnableRedisplay(ispell.ascii);
+ }
+ (void)IspellReplacedWord(search.ptr, replace.ptr);
+
+ strncpy(&ispell.sentbuf[1], replace.ptr, sizeof(ispell.sentbuf) - 2);
+ ispell.sentbuf[sizeof(ispell.sentbuf) - 1] = '\0';
+ }
+ else
+ Feep();
+
+ if (ispell.repeat)
+ ispell.right = ispell.left = XawTextGetInsertionPoint(ispell.ascii);
+ else if (!ispell.terse_mode || !ispell.item ||
+ strcmp(ispell.item, replace.ptr))
+ ispell.right = ispell.left; /* check it again! */
+
+ ispell.lock = ispell.checkit = False;
+
+ ispell.stat = SEND;
+ IspellSetStatus(ispell.working_label);
+ while (IspellSend() == 0)
+ ;
+}
+
+/*ARGSUSED*/
+void
+IgnoreIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Arg args[1];
+ char *text;
+
+ if (!ispell.lock)
+ return;
+
+ XtSetArg(args[0], XtNlabel, &text);
+ XtGetValues(ispell.word, args, 1);
+
+ IspellCheckUndo();
+
+ if ((ispell.undo_head->repeat = ispell.repeat) != False) {
+ ispell.undo_head->undo_count = ispell.right;
+ ispell.undo_head->undo_str = XtNewString(text);
+ }
+ else
+ ispell.undo_head->undo_count = 0;
+
+ ispell.undo_head->undo_pos = XawTextGetInsertionPoint(ispell.ascii);
+
+ if (!ispell.repeat) {
+ if (client_data) {
+ IspellIgnoredWord(text, ADD, 0);
+ ispell.undo_head->undo_str = XtNewString(text);
+ }
+ else
+ ispell.undo_head->undo_str = NULL;
+ }
+
+ ispell.lock = ispell.checkit = False;
+
+ ispell.stat = SEND;
+ IspellSetStatus(ispell.working_label);
+ while (IspellSend() == 0)
+ ;
+}
+
+/*ARGSUSED*/
+void
+AddIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Arg args[1];
+ char *text;
+ int cmd = (long)client_data;
+
+ if (!ispell.lock || ispell.repeat)
+ return;
+
+ XtSetArg(args[0], XtNlabel, &text);
+ XtGetValues(ispell.word, args, 1);
+
+ IspellCheckUndo();
+ ispell.undo_head->undo_str = XtNewString(text);
+ ispell.undo_head->undo_pos = XawTextGetInsertionPoint(ispell.ascii);
+ ispell.undo_head->undo_count = -cmd;
+
+ (void)IspellIgnoredWord(text, ADD, cmd);
+
+ ispell.lock = ispell.checkit = False;
+ ispell.stat = SEND;
+ IspellSetStatus(ispell.working_label);
+ while (IspellSend() == 0)
+ ;
+}
+
+/*ARGSUSED*/
+static void
+UndoIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Bool enable_redisplay = False;
+ ispell_undo *undo = ispell.undo_head;
+
+ if ((!ispell.lock && ispell.stat) || !undo)
+ return;
+
+ if (ispell.undo_for && strcmp(ispell.undo_for, ispell.dictionary)) {
+ XeditPrintf("Undo: Dictionary changed. Undo information was lost.\n");
+ IspellKillUndoBuffer();
+ Feep();
+ return;
+ }
+
+ if (undo->terse != ispell.terse_mode)
+ IspellSetTerseMode(undo->terse);
+
+ if (undo->format != ispell.format_info->value) {
+ struct _ispell_format *fmt = &ispell_format[undo->format];
+ ChangeFormatIspell(fmt->sme, (XtPointer)fmt, NULL);
+ }
+
+ if (undo->undo_count > 0 && !undo->repeat) {
+ XawTextPosition tmp;
+
+ enable_redisplay = undo->undo_count > 1;
+ if (enable_redisplay)
+ XawTextDisableRedisplay(ispell.ascii);
+ while (undo->undo_count--)
+ if (!_XawTextSrcUndo((TextSrcObject)ispell.source, &tmp)) {
+ Feep();
+ break;
+ }
+ }
+ else if (undo->undo_count < 0) {
+ if (undo->undo_str)
+ (void)IspellIgnoredWord(undo->undo_str, REMOVE, -undo->undo_count);
+ }
+ else if (undo->undo_str) {
+ if (!undo->repeat)
+ IspellIgnoredWord(undo->undo_str, REMOVE, 0);
+ }
+
+ XawTextSetInsertionPoint(ispell.ascii,
+ ispell.right = ispell.left = undo->undo_pos);
+ if (enable_redisplay)
+ XawTextEnableRedisplay(ispell.ascii);
+
+ /* need to do it because may be two misspelled words together */
+ if (undo->repeat) {
+ char **list, **old_list;
+ int old_len;
+ Arg args[2];
+
+ if (undo->repeat > 1) {
+ XawTextDisableRedisplay(ispell.ascii);
+ if (!_XawTextSrcUndo((TextSrcObject)ispell.source, &ispell.right))
+ Feep();
+ XawTextEnableRedisplay(ispell.ascii);
+ }
+ else
+ ispell.right = (XawTextPosition)undo->undo_count;
+ IspellSetRepeated(ispell.repeat = True);
+ XtSetArg(args[0], XtNlabel, undo->undo_str);
+ XtSetValues(ispell.word, args, 1);
+ XmuSnprintf(ispell.sentbuf, sizeof(ispell.sentbuf), "^%s",
+ strrchr(undo->undo_str, ' ') + 1);
+ strcpy(ispell.sendbuf, ispell.sentbuf);
+ XtSetArg(args[0], XtNstring, &ispell.sentbuf[1]);
+ XtSetValues(ispell.text, args, 1);
+
+ XtSetArg(args[0], XtNlist, &old_list);
+ XtSetArg(args[1], XtNnumberStrings, &old_len);
+ XtGetValues(ispell.list, args, 2);
+
+ list = (char **)XtMalloc(sizeof(char*));
+ list[0] = XtNewString(&ispell.sentbuf[1]);
+ XtSetArg(args[0], XtNlist, list);
+ XtSetArg(args[1], XtNnumberStrings, 1);
+ XtSetValues(ispell.list, args, 2);
+ XtSetSensitive(ispell.list, True);
+ XawListHighlight(ispell.list, 0);
+
+ if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
+ while (--old_len > -1)
+ XtFree(old_list[old_len]);
+ XtFree((char*)old_list);
+ }
+
+ IspellSetSelection(ispell.left, ispell.right);
+ IspellSetStatus(ispell.repeat_label);
+ ispell.lock = True;
+ ispell.checkit = False;
+ }
+ else if (ispell.repeat) {
+ *ispell.sentbuf = '\0';
+ IspellSetRepeated(ispell.repeat = False);
+ }
+
+ if (undo->prev)
+ undo->prev->next = NULL;
+ ispell.undo_head = undo->prev;
+ if (undo == ispell.undo_base) {
+ ispell.undo_base = NULL;
+ ispell.undo_for = NULL;
+ XtSetSensitive(ispell.undo, False);
+ }
+ if (undo->undo_str)
+ XtFree(undo->undo_str);
+ XtFree((char*)undo);
+ --ispell.undo_depth;
+
+ if (!ispell.stat || ispell.checkit)
+ IspellSetSensitive(True);
+
+ if (!ispell.repeat) {
+ ispell.lock = ispell.checkit = False;
+ ispell.stat = SEND;
+ IspellSetStatus(ispell.working_label);
+ while (IspellSend() == 0)
+ ;
+ }
+}
+
+/*ARGSUSED*/
+static void
+CheckIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Arg args[1];
+ char *text, *str, string[1024];
+ int i, len;
+
+ if (!ispell.lock)
+ return;
+
+ XtSetArg(args[0], XtNstring, &text);
+ XtGetValues(ispell.text, args, 1);
+
+ /* Check only a word at a time */
+ len = 0;
+ str = text;
+ while (*str) {
+ if (isalpha(*str) || strchr(ispell.wchars, *str))
+ break;
+ ++str;
+ ++len;
+ }
+ i = 0;
+ while (*str) {
+ if (isalpha(*str) || strchr(ispell.wchars, *str))
+ string[i++] = *str++;
+ else
+ break;
+ }
+ string[i] = '\0';
+
+ if (strcmp(text, string)) {
+ XawTextPosition pos = XawTextGetInsertionPoint(ispell.text) - len;
+
+ XtSetArg(args[0], XtNstring, string);
+ XtSetValues(ispell.text, args, 1);
+ XawTextSetInsertionPoint(ispell.text, pos);
+ Feep();
+ }
+
+ if (i == 0) {
+ Feep();
+ return;
+ }
+
+ len = XmuSnprintf(ispell.sendbuf, sizeof(ispell.sendbuf), "^%s\n", string);
+
+ ispell.sendbuf[sizeof(ispell.sendbuf) - 1] = '\n';
+
+ write(ispell.ofd[1], ispell.sendbuf, len);
+
+ ispell.lock = False;
+ ispell.checkit = True;
+ ispell.stat = RECEIVE;
+}
+
+/*ARGSUSED*/
+static void
+LookIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int len, old_len;
+ FILE *fd;
+ Arg args[2];
+ char *text, *str, **list, **old_list, command[1024], buffer[1024];
+ Bool sensitive = True;
+
+ if (!ispell.lock)
+ return;
+
+ XtSetArg(args[0], XtNstring, &text);
+ XtGetValues(ispell.text, args, 1);
+
+ if (!*text) {
+ Feep();
+ return;
+ }
+
+ if (strlen(ispell.look_cmd) + strlen(text) + strlen(ispell.words_file) + 8
+ > sizeof(command) - 1) {
+ fprintf(stderr, "Command line too large\n");
+ return;
+ }
+
+ XmuSnprintf(command, sizeof(command), "%s '^%s.*$' %s",
+ ispell.look_cmd, text, ispell.words_file);
+
+ if ((fd = popen(command, "r")) == NULL) {
+ fprintf(stderr, "Cannot popen '%s'\n", ispell.look_cmd);
+ return;
+ }
+
+ list = NULL;
+ len = 0;
+
+#define MAX_LOOK_RESULTS 256
+ while (fgets(buffer, sizeof(buffer), fd) != NULL) {
+ if ((str = strchr(buffer, '\n')) == NULL) {
+ fprintf(stderr, "String is too large\n");
+ break;
+ }
+ *str = '\0';
+ if ((len % 16) == 0)
+ list = (char**)XtRealloc((char*)list, sizeof(char*) * (len + 16));
+ list[len] = XtNewString(buffer);
+ if (++len >= MAX_LOOK_RESULTS) {
+ Feep();
+ break;
+ }
+ }
+#undef MAX_LOOK_RESULTS
+
+ XtSetArg(args[0], XtNlist, &old_list);
+ XtSetArg(args[1], XtNnumberStrings, &old_len);
+ XtGetValues(ispell.list, args, 2);
+
+ if (len == 0) {
+ list = (char**)XtMalloc(sizeof(char*));
+ list[0] = XtNewString("");
+ len = 1;
+ sensitive = False;
+ }
+
+ XtSetArg(args[0], XtNlist, list);
+ XtSetArg(args[1], XtNnumberStrings, len);
+ XtSetValues(ispell.list, args, 2);
+
+ XtSetSensitive(ispell.list, sensitive);
+ IspellSetStatus(sensitive ? ispell.look_label : ispell.none_label);
+
+ if (old_len > 1 || (XtName(ispell.list) != old_list[0])) {
+ while (--old_len > -1)
+ XtFree(old_list[old_len]);
+ XtFree((char*)old_list);
+ }
+
+ pclose(fd);
+}
+
+/*ARGSUSED*/
+static void
+ToggleTerseIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (!ispell.lock)
+ return;
+
+ ispell.terse_mode = !ispell.terse_mode;
+ write(ispell.ofd[1], ispell.terse_mode ? "!\n" : "%\n", 2);
+}
+
+/*ARGSUSED*/
+static void
+ChangeDictionaryIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ ispell_dict *tmp, *dic = (ispell_dict*)client_data;
+ XawTextPosition pos = XawTextGetInsertionPoint(ispell.ascii);
+ XawTextPosition right = ispell.right;
+ Arg args[1];
+
+ if (strcmp(XtName(dic->sme), ispell.dictionary) == 0)
+ return;
+
+ if (!ispell.lock) {
+ Feep();
+ return;
+ }
+
+ for (tmp = ispell.dict_info; tmp; tmp = tmp->next)
+ if (strcmp(XtName(tmp->sme), ispell.dictionary) == 0) {
+ XtSetArg(args[0], XtNleftBitmap, None);
+ XtSetValues(tmp->sme, args, 1);
+ }
+
+ if (ispell.undo_base && !ispell.undo_for)
+ ispell.undo_for = ispell.dictionary;
+
+ XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
+ XtSetValues(dic->sme, args, 1);
+ ispell.dictionary = XtName(dic->sme);
+ ispell.wchars = dic->wchars;
+ XtSetArg(args[0], XtNlabel, XtName(dic->sme));
+ XtSetValues(ispell.dict, args, 1);
+
+ IspellSetStatus(ispell.working_label);
+
+ (void)IspellEndProcess(True, False);
+ ispell.lock = ispell.checkit = False;
+ (void)IspellStartProcess();
+
+ ispell.stat = RECEIVE;
+
+ /* restart at the same selected word */
+ if (ispell.repeat == False)
+ ispell.left = ispell.right = pos;
+ else
+ ispell.right = right;
+}
+
+/*ARGSUSED*/
+static void
+ChangeFormatIspell(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct _ispell_format *fmt = (struct _ispell_format*)client_data;
+ Arg args[1];
+
+ if (strcmp(fmt->name, ispell.formatting) == 0)
+ return;
+
+ if (!ispell.lock) {
+ Feep();
+ return;
+ }
+
+ XtSetArg(args[0], XtNleftBitmap, None);
+ XtSetValues(ispell.format_info->sme, args, 1);
+
+ XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
+ XtSetValues(fmt->sme, args, 1);
+ ispell.formatting = fmt->name;
+ ispell.format_info = fmt;
+ XtSetArg(args[0], XtNlabel, fmt->name);
+ XtSetValues(ispell.format, args, 1);
+}
+
+static Bool
+InitIspell(void)
+{
+ Atom delete_window;
+ char *str, *list;
+ XtResource dict_res;
+ int i;
+ static XtResource text_res[] = {
+ {"skipLines", "Skip", XtRString, sizeof(char*),
+ XtOffsetOf(struct _ispell, skip), XtRString, "#"},
+ };
+
+ if (ispell.shell)
+ return (False);
+
+ ispell.shell = XtCreatePopupShell("ispell", transientShellWidgetClass,
+ topwindow, NULL, 0);
+
+ XtGetApplicationResources(ispell.shell, (XtPointer)&ispell, resources,
+ XtNumber(resources), NULL, 0);
+
+ ispell.form = XtCreateManagedWidget("form", formWidgetClass,
+ ispell.shell, NULL, 0);
+ ispell.mispelled = XtCreateManagedWidget("mispelled", labelWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.repeated = XtCreateWidget("repeated", labelWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.word = XtCreateManagedWidget("word", commandWidgetClass,
+ ispell.form, NULL, 0);
+ XtAddCallback(ispell.word, XtNcallback, RevertIspell, NULL);
+ ispell.replacement = XtCreateManagedWidget("replacement", labelWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.text = XtVaCreateManagedWidget("text", asciiTextWidgetClass,
+ ispell.form,
+ XtNeditType, XawtextEdit,
+ NULL, 0);
+ ispell.suggestions = XtCreateManagedWidget("suggestions", labelWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.viewport = XtCreateManagedWidget("viewport", viewportWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.list = XtCreateManagedWidget("list", listWidgetClass,
+ ispell.viewport, NULL, 0);
+ XtAddCallback(ispell.list, XtNcallback, SelectIspell, NULL);
+ ispell.commands = XtCreateManagedWidget("commands", formWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.check = XtCreateManagedWidget("check", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.check, XtNcallback, CheckIspell, NULL);
+ ispell.look = XtCreateManagedWidget("look", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.look, XtNcallback, LookIspell, NULL);
+ ispell.undo = XtCreateManagedWidget("undo", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.undo, XtNcallback, UndoIspell, NULL);
+ ispell.replace = XtCreateManagedWidget("replace", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.replace, XtNcallback, ReplaceIspell, (XtPointer)False);
+ ispell.replaceAll = XtCreateManagedWidget("replaceAll", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.replaceAll, XtNcallback, ReplaceIspell, (XtPointer)True);
+ ispell.ignore = XtCreateManagedWidget("ignore", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.ignore, XtNcallback, IgnoreIspell, (XtPointer)False);
+ ispell.ignoreAll = XtCreateManagedWidget("ignoreAll", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.ignoreAll, XtNcallback, IgnoreIspell, (XtPointer)True);
+ ispell.add = XtCreateManagedWidget("add", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.add, XtNcallback, AddIspell, (XtPointer)ASIS);
+ ispell.addUncap = XtCreateManagedWidget("addUncap", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.addUncap, XtNcallback, AddIspell, (XtPointer)UNCAP);
+ ispell.suspend = XtCreateManagedWidget("suspend", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.suspend, XtNcallback, PopdownIspell, (XtPointer)False);
+ ispell.cancel = XtCreateManagedWidget("cancel", commandWidgetClass,
+ ispell.commands, NULL, 0);
+ XtAddCallback(ispell.cancel, XtNcallback, PopdownIspell, (XtPointer)True);
+ ispell.terse = XtVaCreateManagedWidget("terse", toggleWidgetClass,
+ ispell.commands,
+ XtNstate, ispell.terse_mode,
+ NULL, 0);
+ XtAddCallback(ispell.terse, XtNcallback, ToggleTerseIspell, NULL);
+ ispell.status = XtCreateManagedWidget("status", labelWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.options = XtCreateManagedWidget("options", formWidgetClass,
+ ispell.form, NULL, 0);
+ ispell.dict = XtVaCreateManagedWidget("dict", menuButtonWidgetClass,
+ ispell.options,
+ XtNmenuName, "dictionaries",
+ NULL, 0);
+ ispell.dictMenu = XtCreatePopupShell("dictionaries", simpleMenuWidgetClass,
+ ispell.options, NULL, 0);
+ XtRealizeWidget(ispell.dictMenu);
+
+ ispell.format = XtVaCreateManagedWidget("format", menuButtonWidgetClass,
+ ispell.options,
+ XtNmenuName, "formats",
+ NULL, 0);
+ ispell.formatMenu = XtCreatePopupShell("formats", simpleMenuWidgetClass,
+ ispell.options, NULL, 0);
+ XtRealizeWidget(ispell.formatMenu);
+
+ XtRealizeWidget(ispell.shell);
+
+ for (i = 0; i < sizeof(ispell_format) / sizeof(ispell_format[0]); i++) {
+ struct _ispell_format *fmt = &ispell_format[i];
+
+ fmt->sme = XtCreateManagedWidget(fmt->name, smeBSBObjectClass,
+ ispell.formatMenu, NULL, 0);
+ XtAddCallback(fmt->sme, XtNcallback, ChangeFormatIspell, (XtPointer)fmt);
+
+ if (strcmp(fmt->name, ispell.formatting) == 0) {
+ Arg args[1];
+
+ XtSetArg(args[0], XtNlabel, ispell.formatting);
+ XtSetValues(ispell.format, args, 1);
+ XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
+ XtSetValues(fmt->sme, args, 1);
+ ispell.format_info = fmt;
+ }
+ }
+ if (ispell.format_info == NULL) {
+ Arg args[1];
+ char msg[256];
+
+ ispell.format_info = &ispell_format[TEXT];
+
+ XmuSnprintf(msg, sizeof(msg),
+ "Unrecognized formatting type \"%s\", will use \"%s\"",
+ ispell.formatting, ispell.format_info->name);
+ XtAppWarning(XtWidgetToApplicationContext(ispell.shell), msg);
+ ispell.formatting = ispell.format_info->name;
+
+ XtSetArg(args[0], XtNlabel, ispell.format_info->name);
+ XtSetValues(ispell.format, args, 1);
+ XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
+ XtSetValues(ispell.format_info->sme, args, 1);
+ }
+ XtGetApplicationResources(ispell_format[TEXT].sme, (XtPointer)&ispell,
+ text_res, XtNumber(text_res), NULL, 0);
+
+ dict_res.resource_name = "wordChars";
+ dict_res.resource_class = "Chars";
+ dict_res.resource_type = XtRString;
+ dict_res.resource_size = sizeof(char*);
+ dict_res.resource_offset = XtOffsetOf(ispell_dict, wchars);
+ dict_res.default_type = XtRString;
+ dict_res.default_addr = "";
+
+ list = XtNewString(ispell.dict_list);
+ for (str = strtok(list, " \t,"); str; str = strtok(NULL, " \t,")) {
+ ispell_dict *dic = XtNew(ispell_dict);
+
+ dic->sme = XtCreateManagedWidget(str, smeBSBObjectClass,
+ ispell.dictMenu, NULL, 0);
+ XtGetApplicationResources(dic->sme, (XtPointer)dic, &dict_res,
+ 1, NULL, 0);
+ XtAddCallback(dic->sme, XtNcallback, ChangeDictionaryIspell,
+ (XtPointer)dic);
+ dic->next = NULL;
+ if (!ispell.dict_info)
+ ispell.dict_info = dic;
+ else {
+ ispell_dict *tmp = ispell.dict_info;
+
+ for (; tmp->next; tmp = tmp->next)
+ ;
+ tmp->next = dic;
+ }
+ if (strcmp(str, ispell.dictionary) == 0) {
+ Arg args[1];
+
+ XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
+ XtSetValues(dic->sme, args, 1);
+ XtSetArg(args[0], XtNlabel, str);
+ XtSetValues(ispell.dict, args, 1);
+ ispell.wchars = dic->wchars;
+ }
+ }
+ XtFree(list);
+
+ delete_window = XInternAtom(XtDisplay(ispell.shell), "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(XtDisplay(ispell.shell), XtWindow(ispell.shell), &delete_window, 1);
+
+ return (True);
+}