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