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