2211 lines
57 KiB
C
2211 lines
57 KiB
C
/*
|
|
* 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
|
|
*/
|
|
|
|
/* $XdotOrg: xc/programs/xedit/ispell.c,v 1.6 2004/12/04 00:43:13 kuhn Exp $ */
|
|
/* $XFree86: xc/programs/xedit/ispell.c,v 1.19 2002/10/19 20:04:20 herrb Exp $ */
|
|
|
|
#include "xedit.h"
|
|
#include "util.h"
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <locale.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>
|
|
#include <X11/Xos.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 _ReplaceEntry ReplaceEntry;
|
|
struct _ReplaceEntry {
|
|
hash_key *word;
|
|
ReplaceEntry*next;
|
|
char *replace;
|
|
};
|
|
|
|
typedef struct _IgnoreEntry IgnoreEntry;
|
|
struct _IgnoreEntry {
|
|
hash_key *word;
|
|
IgnoreEntry *next;
|
|
int add;
|
|
};
|
|
|
|
/*
|
|
* 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 IspellCheckProcess(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);
|
|
static void timeout_signal(int);
|
|
static void (*old_timeout)(int);
|
|
static void UndoIspell(Widget, XtPointer, XtPointer);
|
|
|
|
Bool _XawTextSrcUndo(TextSrcObject, XawTextPosition*);
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
static struct _ispell ispell;
|
|
|
|
#define RSTRTBLSZ 23
|
|
#define ISTRTBLSZ 71
|
|
static hash_table *replace_hash;
|
|
static hash_table *ignore_hash;
|
|
|
|
#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*/
|
|
static void
|
|
timeout_signal(int unused)
|
|
{
|
|
int olderrno = errno;
|
|
|
|
WRITES("Warning: Timeout waiting ispell process to die.\n");
|
|
kill(ispell.pid, SIGTERM);
|
|
errno = olderrno;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int word_len;
|
|
hash_key *word_key;
|
|
ReplaceEntry *entry;
|
|
|
|
word_len = strlen(word);
|
|
entry = (ReplaceEntry *)hash_check(replace_hash, word, word_len);
|
|
if (entry == NULL) {
|
|
word_key = XtNew(hash_key);
|
|
word_key->value = XtNewString(word);
|
|
word_key->length = word_len;
|
|
entry = XtNew(ReplaceEntry);
|
|
entry->word = word_key;
|
|
entry->replace = NULL;
|
|
entry->next = NULL;
|
|
hash_put(replace_hash, (hash_entry *)entry);
|
|
}
|
|
|
|
if (replace) {
|
|
XtFree(entry->replace);
|
|
entry->replace = XtNewString(replace);
|
|
}
|
|
|
|
return (entry->replace);
|
|
}
|
|
|
|
static Bool
|
|
IspellDoIgnoredWord(char *word, int cmd, int add)
|
|
{
|
|
int word_len;
|
|
hash_key *word_key;
|
|
IgnoreEntry *entry;
|
|
|
|
word_len = strlen(word);
|
|
entry = (IgnoreEntry *)hash_check(ignore_hash, word, word_len);
|
|
if (entry == NULL) {
|
|
if (cmd != ADD)
|
|
return (False);
|
|
|
|
word_key = XtNew(hash_key);
|
|
word_key->value = XtNewString(word);
|
|
word_key->length = word_len;
|
|
entry = XtNew(IgnoreEntry);
|
|
entry->word = word_key;
|
|
entry->add = add;
|
|
entry->next = NULL;
|
|
hash_put(ignore_hash, (hash_entry *)entry);
|
|
|
|
return (True);
|
|
}
|
|
else if (cmd == REMOVE)
|
|
hash_rem(ignore_hash, (hash_entry *)entry);
|
|
|
|
return (cmd == CHECK);
|
|
}
|
|
|
|
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 = 0xe1; break;
|
|
case 'e': ch = 0xe9; break;
|
|
case 'i': ch = 0xed; break;
|
|
case 'o': ch = 0xf3; break;
|
|
case 'u': ch = 0xfa; break;
|
|
case 'A': ch = 0xc1; break;
|
|
case 'E': ch = 0xc9; break;
|
|
case 'I': ch = 0xcd; break;
|
|
case 'O': ch = 0xd3; break;
|
|
case 'U': ch = 0xda; break;
|
|
}
|
|
}
|
|
else if (strcmp(&buf[1], "grave") == 0) {
|
|
switch (*buf) {
|
|
case 'a': ch = 0xe0; break;
|
|
case 'e': ch = 0xe8; break;
|
|
case 'i': ch = 0xec; break;
|
|
case 'o': ch = 0xf2; break;
|
|
case 'u': ch = 0xf9; break;
|
|
case 'A': ch = 0xc0; break;
|
|
case 'E': ch = 0xc8; break;
|
|
case 'I': ch = 0xcc; break;
|
|
case 'O': ch = 0xd2; break;
|
|
case 'U': ch = 0xd9; break;
|
|
}
|
|
}
|
|
else if (strcmp(&buf[1], "tilde") == 0) {
|
|
switch (*buf) {
|
|
case 'a': ch = 0xe3; break;
|
|
case 'o': ch = 0xf5; break;
|
|
case 'n': ch = 0xf1; break;
|
|
case 'A': ch = 0xe3; break;
|
|
case 'O': ch = 0xd5; break;
|
|
case 'N': ch = 0xd1; break;
|
|
}
|
|
}
|
|
else if (strcmp(&buf[1], "circ") == 0) {
|
|
switch (*buf) {
|
|
case 'a': ch = 0xe2; break;
|
|
case 'e': ch = 0xea; break;
|
|
case 'i': ch = 0xee; break;
|
|
case 'o': ch = 0xf4; break;
|
|
case 'u': ch = 0xfb; break;
|
|
case 'A': ch = 0xc2; break;
|
|
case 'E': ch = 0xca; break;
|
|
case 'I': ch = 0xce; break;
|
|
case 'O': ch = 0xd4; break;
|
|
case 'U': ch = 0xdb; break;
|
|
}
|
|
}
|
|
else if (strcmp(&buf[1], "cedil") == 0) {
|
|
switch (*buf) {
|
|
case 'c': ch = 0xe7; break;
|
|
case 'C': ch = 0xc7; 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[0] = 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[0] = 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 format[32];
|
|
static char *command;
|
|
|
|
ispell.source = XawTextGetSource(ispell.ascii);
|
|
|
|
if (command)
|
|
XtFree(command);
|
|
|
|
strcpy(format, "%s -a");
|
|
len = strlen(ispell.cmd) + 4;
|
|
if (ispell.dictionary && *ispell.dictionary) {
|
|
len += strlen(ispell.dictionary) + 6;
|
|
strcat(format, " -d '%s'");
|
|
if (ispell.wchars && *ispell.wchars) {
|
|
len += strlen(ispell.wchars + 6);
|
|
strcat(format, " -w '%s'");
|
|
}
|
|
}
|
|
command = XtMalloc(len);
|
|
XmuSnprintf(command, len, format,
|
|
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]);
|
|
if (!international)
|
|
setlocale(LC_ALL, "ISO-8859-1");
|
|
execl("/bin/sh", "sh", "-c", command, 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
|
|
IspellCheckProcess(void)
|
|
{
|
|
int status;
|
|
|
|
if (ispell.pid) {
|
|
waitpid(ispell.pid, &status, WNOHANG);
|
|
if (WIFEXITED(status)) {
|
|
ispell.pid = 0;
|
|
}
|
|
else
|
|
return (True);
|
|
}
|
|
|
|
return (False);
|
|
}
|
|
|
|
static Bool
|
|
IspellEndProcess(Bool killit, Bool killundo)
|
|
{
|
|
ispell.source = NULL;
|
|
|
|
if (ispell.pid) {
|
|
IgnoreEntry *ientry;
|
|
ReplaceEntry *rentry;
|
|
|
|
/* insert added words in private dictionary */
|
|
for (ientry = (IgnoreEntry *)hash_iter_first(ignore_hash);
|
|
ientry;
|
|
ientry = (IgnoreEntry *)hash_iter_next(ignore_hash)) {
|
|
if (ientry->add) {
|
|
if (ientry->add == UNCAP)
|
|
write(ispell.ofd[1], "&", 1);
|
|
else
|
|
write(ispell.ofd[1], "*", 1);
|
|
write(ispell.ofd[1], ientry->word->value, ientry->word->length);
|
|
write(ispell.ofd[1], "\n", 1);
|
|
}
|
|
}
|
|
write(ispell.ofd[1], "#\n", 2); /* save dictionary */
|
|
hash_clr(ignore_hash);
|
|
|
|
if (killit) {
|
|
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;
|
|
|
|
/* forget about replace matches */
|
|
for (rentry = (ReplaceEntry *)hash_iter_first(replace_hash);
|
|
rentry;
|
|
rentry = (ReplaceEntry *)hash_iter_next(replace_hash)) {
|
|
XtFree(rentry->replace);
|
|
}
|
|
hash_clr(replace_hash);
|
|
}
|
|
|
|
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[0] = check.ptr[0];
|
|
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[0] = check.ptr[0];
|
|
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) {
|
|
if (IspellCheckProcess()) {
|
|
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;
|
|
ispell_dict *dict, *prev_dict;
|
|
int i;
|
|
static XtResource text_res[] = {
|
|
{"skipLines", "Skip", XtRString, sizeof(char*),
|
|
XtOffsetOf(struct _ispell, skip), XtRString, "#"},
|
|
};
|
|
|
|
if (ispell.shell)
|
|
return (False);
|
|
|
|
replace_hash = hash_new(RSTRTBLSZ, NULL);
|
|
ignore_hash = hash_new(ISTRTBLSZ, NULL);
|
|
|
|
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);
|
|
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);
|
|
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);
|
|
ispell.dictMenu = XtCreatePopupShell("dictionaries", simpleMenuWidgetClass,
|
|
ispell.options, NULL, 0);
|
|
XtRealizeWidget(ispell.dictMenu);
|
|
|
|
ispell.format = XtVaCreateManagedWidget("format", menuButtonWidgetClass,
|
|
ispell.options,
|
|
XtNmenuName, "formats",
|
|
NULL);
|
|
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);
|
|
|
|
/* Create first empty entry */
|
|
dict = XtNew(ispell_dict);
|
|
dict->sme = XtCreateManagedWidget("", smeBSBObjectClass,
|
|
ispell.dictMenu, NULL, 0);
|
|
dict->wchars = "";
|
|
XtAddCallback(dict->sme, XtNcallback, ChangeDictionaryIspell,
|
|
(XtPointer)dict);
|
|
ispell.dict_info = prev_dict = dict;
|
|
|
|
for (str = strtok(list, " \t,"); str; str = strtok(NULL, " \t,")) {
|
|
dict = XtNew(ispell_dict);
|
|
dict->sme = XtCreateManagedWidget(str, smeBSBObjectClass,
|
|
ispell.dictMenu, NULL, 0);
|
|
XtGetApplicationResources(dict->sme, (XtPointer)dict, &dict_res,
|
|
1, NULL, 0);
|
|
XtAddCallback(dict->sme, XtNcallback, ChangeDictionaryIspell,
|
|
(XtPointer)dict);
|
|
prev_dict->next = dict;
|
|
prev_dict = dict;
|
|
dict->next = NULL;
|
|
}
|
|
XtFree(list);
|
|
|
|
for (dict = ispell.dict_info; dict; dict = dict->next) {
|
|
if (strcmp(XtName(dict->sme), ispell.dictionary) == 0) {
|
|
Arg args[1];
|
|
|
|
XtSetArg(args[0], XtNleftBitmap, flist.pixmap);
|
|
XtSetValues(dict->sme, args, 1);
|
|
XtSetArg(args[0], XtNlabel, XtName(dict->sme));
|
|
XtSetValues(ispell.dict, args, 1);
|
|
ispell.wchars = dict->wchars;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
delete_window = XInternAtom(XtDisplay(ispell.shell), "WM_DELETE_WINDOW", False);
|
|
XSetWMProtocols(XtDisplay(ispell.shell), XtWindow(ispell.shell), &delete_window, 1);
|
|
|
|
return (True);
|
|
}
|