1 /* $OpenBSD: spellprog.c,v 1.5 2007/09/02 15:19:34 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)spell.h 8.1 (Berkeley) 6/6/93 32 */ 33 /* 34 * Copyright (C) Caldera International Inc. 2001-2002. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code and documentation must retain the above 41 * copyright notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed or owned by Caldera 48 * International, Inc. 49 * 4. Neither the name of Caldera International, Inc. nor the names of other 50 * contributors may be used to endorse or promote products derived from 51 * this software without specific prior written permission. 52 * 53 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 54 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 55 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 56 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 57 * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 58 * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 59 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 60 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 62 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 63 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 64 * POSSIBILITY OF SUCH DAMAGE. 65 */ 66 67 #ifndef lint 68 static const char copyright[] = 69 "@(#) Copyright (c) 1991, 1993\n\ 70 The Regents of the University of California. All rights reserved.\n"; 71 #endif /* not lint */ 72 73 #ifndef lint 74 #if 0 75 static const char sccsid[] = "@(#)spell.c 8.1 (Berkeley) 6/6/93"; 76 #else 77 #endif 78 static const char rcsid[] = "$OpenBSD: spellprog.c,v 1.5 2007/09/02 15:19:34 deraadt Exp $"; 79 #endif /* not lint */ 80 81 #include <sys/param.h> 82 #include <sys/mman.h> 83 #include <sys/stat.h> 84 85 #include <ctype.h> 86 #include <err.h> 87 #include <errno.h> 88 #include <fcntl.h> 89 #include <limits.h> 90 #include <locale.h> 91 #include <stdio.h> 92 #include <stdlib.h> 93 #include <string.h> 94 #include <unistd.h> 95 96 #define DLEV 2 97 98 int an(char *, char *, char *, int); 99 int bility(char *, char *, char *, int); 100 int es(char *, char *, char *, int); 101 int dict(char *, char *); 102 int i_to_y(char *, char *, char *, int); 103 int ily(char *, char *, char *, int); 104 int ize(char *, char *, char *, int); 105 int metry(char *, char *, char *, int); 106 int monosyl(char *, char *); 107 int ncy(char *, char *, char *, int); 108 int nop(void); 109 int trypref(char *, char *, int); 110 int tryword(char *, char *, int); 111 int s(char *, char *, char *, int); 112 int strip(char *, char *, char *, int); 113 int suffix(char *, int); 114 int tion(char *, char *, char *, int); 115 int vowel(int); 116 int y_to_e(char *, char *, char *, int); 117 int CCe(char *, char *, char *, int); 118 int VCe(char *, char *, char *, int); 119 char *lookuppref(char **, char *); 120 char *skipv(char *); 121 char *estrdup(const char *); 122 void ise(void); 123 void print_word(FILE *); 124 void ztos(char *); 125 __dead void usage(void); 126 127 /* from look.c */ 128 int look(unsigned char *, unsigned char *, unsigned char *); 129 130 struct suftab { 131 char *suf; 132 int (*p1)(); /* XXX - variable args */ 133 int n1; 134 char *d1; 135 char *a1; 136 int (*p2)(); /* XXX - variable args */ 137 int n2; 138 char *d2; 139 char *a2; 140 } suftab[] = { 141 {"ssen", ily, 4, "-y+iness", "+ness" }, 142 {"ssel", ily, 4, "-y+i+less", "+less" }, 143 {"se", s, 1, "", "+s", es, 2, "-y+ies", "+es" }, 144 {"s'", s, 2, "", "+'s"}, 145 {"s", s, 1, "", "+s"}, 146 {"ecn", ncy, 1, "", "-t+ce"}, 147 {"ycn", ncy, 1, "", "-cy+t"}, 148 {"ytilb", nop, 0, "", ""}, 149 {"ytilib", bility, 5, "-le+ility", ""}, 150 {"elbaif", i_to_y, 4, "-y+iable", ""}, 151 {"elba", CCe, 4, "-e+able", "+able"}, 152 {"yti", CCe, 3, "-e+ity", "+ity"}, 153 {"ylb", y_to_e, 1, "-e+y", ""}, 154 {"yl", ily, 2, "-y+ily", "+ly"}, 155 {"laci", strip, 2, "", "+al"}, 156 {"latnem", strip, 2, "", "+al"}, 157 {"lanoi", strip, 2, "", "+al"}, 158 {"tnem", strip, 4, "", "+ment"}, 159 {"gni", CCe, 3, "-e+ing", "+ing"}, 160 {"reta", nop, 0, "", ""}, 161 {"re", strip, 1, "", "+r", i_to_y, 2, "-y+ier", "+er"}, 162 {"de", strip, 1, "", "+d", i_to_y, 2, "-y+ied", "+ed"}, 163 {"citsi", strip, 2, "", "+ic"}, 164 {"cihparg", i_to_y, 1, "-y+ic", ""}, 165 {"tse", strip, 2, "", "+st", i_to_y, 3, "-y+iest", "+est"}, 166 {"cirtem", i_to_y, 1, "-y+ic", ""}, 167 {"yrtem", metry, 0, "-ry+er", ""}, 168 {"cigol", i_to_y, 1, "-y+ic", ""}, 169 {"tsigol", i_to_y, 2, "-y+ist", ""}, 170 {"tsi", VCe, 3, "-e+ist", "+ist"}, 171 {"msi", VCe, 3, "-e+ism", "+ist"}, 172 {"noitacif", i_to_y, 6, "-y+ication", ""}, 173 {"noitazi", ize, 5, "-e+ation", ""}, 174 {"rota", tion, 2, "-e+or", ""}, 175 {"noit", tion, 3, "-e+ion", "+ion"}, 176 {"naino", an, 3, "", "+ian"}, 177 {"na", an, 1, "", "+n"}, 178 {"evit", tion, 3, "-e+ive", "+ive"}, 179 {"ezi", CCe, 3, "-e+ize", "+ize"}, 180 {"pihs", strip, 4, "", "+ship"}, 181 {"dooh", ily, 4, "-y+hood", "+hood"}, 182 {"ekil", strip, 4, "", "+like"}, 183 { NULL } 184 }; 185 186 char *preftab[] = { 187 "anti", 188 "bio", 189 "dis", 190 "electro", 191 "en", 192 "fore", 193 "hyper", 194 "intra", 195 "inter", 196 "iso", 197 "kilo", 198 "magneto", 199 "meta", 200 "micro", 201 "milli", 202 "mis", 203 "mono", 204 "multi", 205 "non", 206 "out", 207 "over", 208 "photo", 209 "poly", 210 "pre", 211 "pseudo", 212 "re", 213 "semi", 214 "stereo", 215 "sub", 216 "super", 217 "thermo", 218 "ultra", 219 "under", /* must precede un */ 220 "un", 221 NULL 222 }; 223 224 struct wlist { 225 int fd; 226 unsigned char *front; 227 unsigned char *back; 228 } *wlists; 229 230 int vflag; 231 int xflag; 232 char word[LINE_MAX]; 233 char original[LINE_MAX]; 234 char *deriv[40]; 235 char affix[40]; 236 237 /* 238 * The spellprog utility accepts a newline-delimited list of words 239 * on stdin. For arguments it expects the path to a word list and 240 * the path to a file in which to store found words. 241 * 242 * In normal usage, spell is called twice. The first time it is 243 * called with a stop list to flag commonly mispelled words. The 244 * remaining words are then passed to spell again, this time with 245 * the dictionary file as the first (non-flag) argument. 246 * 247 * Unlike historic versions of spellprog, this one does not use 248 * hashed files. Instead it simply requires that files be sorted 249 * lexigraphically and uses the same algorithm as the look utility. 250 * 251 * Note that spellprog should be called via the spell shell script 252 * and is not meant to be invoked directly by the user. 253 */ 254 255 int 256 main(int argc, char **argv) 257 { 258 char *ep, *cp, *dp; 259 char *outfile; 260 int ch, fold, i; 261 struct stat sb; 262 FILE *file, *found; 263 264 setlocale(LC_ALL, ""); 265 266 outfile = NULL; 267 while ((ch = getopt(argc, argv, "bvxo:")) != -1) { 268 switch (ch) { 269 case 'b': 270 /* Use British dictionary and convert ize -> ise. */ 271 ise(); 272 break; 273 case 'o': 274 outfile = optarg; 275 break; 276 case 'v': 277 /* Also write derivations to "found" file. */ 278 vflag++; 279 break; 280 case 'x': 281 /* Print plausible stems to stdout. */ 282 xflag++; 283 break; 284 default: 285 usage(); 286 } 287 288 } 289 argc -= optind; 290 argv += optind; 291 if (argc < 1) 292 usage(); 293 294 /* Open and mmap the word/stop lists. */ 295 if ((wlists = calloc(sizeof(struct wlist), (argc + 1))) == NULL) 296 err(1, "malloc"); 297 for (i = 0; argc--; i++) { 298 wlists[i].fd = open(argv[i], O_RDONLY, 0); 299 if (wlists[i].fd == -1 || fstat(wlists[i].fd, &sb) != 0) 300 err(1, "%s", argv[i]); 301 if (sb.st_size > SIZE_T_MAX) 302 errx(1, "%s: %s", argv[i], strerror(EFBIG)); 303 wlists[i].front = mmap(NULL, (size_t)sb.st_size, PROT_READ, 304 MAP_PRIVATE, wlists[i].fd, (off_t)0); 305 if (wlists[i].front == MAP_FAILED) 306 err(1, "%s", argv[i]); 307 wlists[i].back = wlists[i].front + sb.st_size; 308 } 309 wlists[i].fd = -1; 310 311 /* Open file where found words are to be saved. */ 312 if (outfile == NULL) 313 found = NULL; 314 else if ((found = fopen(outfile, "w")) == NULL) 315 err(1, "cannot open %s", outfile); 316 317 for (;; print_word(file)) { 318 affix[0] = '\0'; 319 file = found; 320 for (ep = word; (*ep = ch = getchar()) != '\n'; ep++) { 321 if (ep - word == sizeof(word) - 1) { 322 *ep = '\0'; 323 warnx("word too long (%s)", word); 324 while ((ch = getchar()) != '\n') 325 ; /* slurp until EOL */ 326 } 327 if (ch == EOF) { 328 if (found != NULL) 329 fclose(found); 330 exit(0); 331 } 332 } 333 for (cp = word, dp = original; cp < ep; ) 334 *dp++ = *cp++; 335 *dp = '\0'; 336 fold = 0; 337 for (cp = word; cp < ep; cp++) 338 if (islower(*cp)) 339 goto lcase; 340 if (trypref(ep, ".", 0)) 341 continue; 342 ++fold; 343 for (cp = original + 1, dp = word + 1; dp < ep; dp++, cp++) 344 *dp = tolower(*cp); 345 lcase: 346 if (trypref(ep, ".", 0) || suffix(ep, 0)) 347 continue; 348 if (isupper(word[0])) { 349 for (cp = original, dp = word; (*dp = *cp++); dp++) { 350 if (fold) 351 *dp = tolower(*dp); 352 } 353 word[0] = tolower(word[0]); 354 goto lcase; 355 } 356 file = stdout; 357 } 358 359 exit(0); 360 } 361 362 void 363 print_word(FILE *f) 364 { 365 366 if (f != NULL) { 367 if (vflag && affix[0] != '\0' && affix[0] != '.') 368 fprintf(f, "%s\t%s\n", affix, original); 369 else 370 fprintf(f, "%s\n", original); 371 } 372 } 373 374 /* 375 * For each matching suffix in suftab, call the function associated 376 * with that suffix (p1 and p2). 377 */ 378 int 379 suffix(char *ep, int lev) 380 { 381 struct suftab *t; 382 char *cp, *sp; 383 384 lev += DLEV; 385 deriv[lev] = deriv[lev-1] = 0; 386 for (t = suftab; (sp = t->suf); t++) { 387 cp = ep; 388 while (*sp) { 389 if (*--cp != *sp++) 390 goto next; 391 } 392 for (sp = cp; --sp >= word && !vowel(*sp);) 393 ; /* nothing */ 394 if (sp < word) 395 return (0); 396 if ((*t->p1)(ep-t->n1, t->d1, t->a1, lev+1)) 397 return (1); 398 if (t->p2 != NULL) { 399 deriv[lev] = deriv[lev+1] = '\0'; 400 return ((*t->p2)(ep-t->n2, t->d2, t->a2, lev)); 401 } 402 return (0); 403 next: ; 404 } 405 return (0); 406 } 407 408 int 409 nop(void) 410 { 411 412 return (0); 413 } 414 415 int 416 strip(char *ep, char *d, char *a, int lev) 417 { 418 419 return (trypref(ep, a, lev) || suffix(ep, lev)); 420 } 421 422 int 423 s(char *ep, char *d, char *a, int lev) 424 { 425 426 if (lev > DLEV + 1) 427 return (0); 428 if (*ep == 's' && ep[-1] == 's') 429 return (0); 430 return (strip(ep, d, a, lev)); 431 } 432 433 int 434 an(char *ep, char *d, char *a, int lev) 435 { 436 437 if (!isupper(*word)) /* must be proper name */ 438 return (0); 439 return (trypref(ep,a,lev)); 440 } 441 442 int 443 ize(char *ep, char *d, char *a, int lev) 444 { 445 446 *ep++ = 'e'; 447 return (strip(ep ,"", d, lev)); 448 } 449 450 int 451 y_to_e(char *ep, char *d, char *a, int lev) 452 { 453 char c = *ep; 454 455 *ep++ = 'e'; 456 if (strip(ep, "", d, lev)) 457 return (1); 458 ep[-1] = c; 459 return (0); 460 } 461 462 int 463 ily(char *ep, char *d, char *a, int lev) 464 { 465 466 if (ep[-1] == 'i') 467 return (i_to_y(ep, d, a, lev)); 468 else 469 return (strip(ep, d, a, lev)); 470 } 471 472 int 473 ncy(char *ep, char *d, char *a, int lev) 474 { 475 476 if (skipv(skipv(ep-1)) < word) 477 return (0); 478 ep[-1] = 't'; 479 return (strip(ep, d, a, lev)); 480 } 481 482 int 483 bility(char *ep, char *d, char *a, int lev) 484 { 485 486 *ep++ = 'l'; 487 return (y_to_e(ep, d, a, lev)); 488 } 489 490 int 491 i_to_y(char *ep, char *d, char *a, int lev) 492 { 493 494 if (ep[-1] == 'i') { 495 ep[-1] = 'y'; 496 a = d; 497 } 498 return (strip(ep, "", a, lev)); 499 } 500 501 int 502 es(char *ep, char *d, char *a, int lev) 503 { 504 505 if (lev > DLEV) 506 return (0); 507 508 switch (ep[-1]) { 509 default: 510 return (0); 511 case 'i': 512 return (i_to_y(ep, d, a, lev)); 513 case 's': 514 case 'h': 515 case 'z': 516 case 'x': 517 return (strip(ep, d, a, lev)); 518 } 519 } 520 521 int 522 metry(char *ep, char *d, char *a, int lev) 523 { 524 525 ep[-2] = 'e'; 526 ep[-1] = 'r'; 527 return (strip(ep, d, a, lev)); 528 } 529 530 int 531 tion(char *ep, char *d, char *a, int lev) 532 { 533 534 switch (ep[-2]) { 535 case 'c': 536 case 'r': 537 return (trypref(ep, a, lev)); 538 case 'a': 539 return (y_to_e(ep, d, a, lev)); 540 } 541 return (0); 542 } 543 544 /* 545 * Possible consonant-consonant-e ending. 546 */ 547 int 548 CCe(char *ep, char *d, char *a, int lev) 549 { 550 551 switch (ep[-1]) { 552 case 'l': 553 if (vowel(ep[-2])) 554 break; 555 switch (ep[-2]) { 556 case 'l': 557 case 'r': 558 case 'w': 559 break; 560 default: 561 return (y_to_e(ep, d, a, lev)); 562 } 563 break; 564 case 's': 565 if (ep[-2] == 's') 566 break; 567 case 'c': 568 case 'g': 569 if (*ep == 'a') 570 return (0); 571 case 'v': 572 case 'z': 573 if (vowel(ep[-2])) 574 break; 575 case 'u': 576 if (y_to_e(ep, d, a, lev)) 577 return (1); 578 if (!(ep[-2] == 'n' && ep[-1] == 'g')) 579 return (0); 580 } 581 return (VCe(ep, d, a, lev)); 582 } 583 584 /* 585 * Possible consonant-vowel-consonant-e ending. 586 */ 587 int 588 VCe(char *ep, char *d, char *a, int lev) 589 { 590 char c; 591 592 c = ep[-1]; 593 if (c == 'e') 594 return (0); 595 if (!vowel(c) && vowel(ep[-2])) { 596 c = *ep; 597 *ep++ = 'e'; 598 if (trypref(ep, d, lev) || suffix(ep, lev)) 599 return (1); 600 ep--; 601 *ep = c; 602 } 603 return (strip(ep, d, a, lev)); 604 } 605 606 char * 607 lookuppref(char **wp, char *ep) 608 { 609 char **sp; 610 char *bp,*cp; 611 612 for (sp = preftab; *sp; sp++) { 613 bp = *wp; 614 for (cp = *sp; *cp; cp++, bp++) { 615 if (tolower(*bp) != *cp) 616 goto next; 617 } 618 for (cp = bp; cp < ep; cp++) { 619 if (vowel(*cp)) { 620 *wp = bp; 621 return (*sp); 622 } 623 } 624 next: ; 625 } 626 return (0); 627 } 628 629 /* 630 * If the word is not in the dictionary, try stripping off prefixes 631 * until the word is found or we run out of prefixes to check. 632 */ 633 int 634 trypref(char *ep, char *a, int lev) 635 { 636 char *cp; 637 char *bp; 638 char *pp; 639 int val = 0; 640 char space[20]; 641 642 deriv[lev] = a; 643 if (tryword(word, ep, lev)) 644 return (1); 645 bp = word; 646 pp = space; 647 deriv[lev+1] = pp; 648 while ((cp = lookuppref(&bp, ep))) { 649 *pp++ = '+'; 650 while ((*pp = *cp++)) 651 pp++; 652 if (tryword(bp, ep, lev+1)) { 653 val = 1; 654 break; 655 } 656 if (pp - space >= sizeof(space)) 657 return (0); 658 } 659 deriv[lev+1] = deriv[lev+2] = '\0'; 660 return (val); 661 } 662 663 int 664 tryword(char *bp, char *ep, int lev) 665 { 666 int i, j; 667 char duple[3]; 668 669 if (ep-bp <= 1) 670 return (0); 671 if (vowel(*ep) && monosyl(bp, ep)) 672 return (0); 673 674 i = dict(bp, ep); 675 if (i == 0 && vowel(*ep) && ep[-1] == ep[-2] && monosyl(bp, ep-1)) { 676 ep--; 677 deriv[++lev] = duple; 678 duple[0] = '+'; 679 duple[1] = *ep; 680 duple[2] = '\0'; 681 i = dict(bp, ep); 682 } 683 if (vflag == 0 || i == 0) 684 return (i); 685 686 /* Also tack on possible derivations. (XXX - warn on truncation?) */ 687 for (j = lev; j > 0; j--) { 688 if (deriv[j]) 689 strlcat(affix, deriv[j], sizeof(affix)); 690 } 691 return (i); 692 } 693 694 int 695 monosyl(char *bp, char *ep) 696 { 697 698 if (ep < bp + 2) 699 return (0); 700 if (vowel(*--ep) || !vowel(*--ep) || ep[1] == 'x' || ep[1] == 'w') 701 return (0); 702 while (--ep >= bp) 703 if (vowel(*ep)) 704 return (0); 705 return (1); 706 } 707 708 char * 709 skipv(char *s) 710 { 711 712 if (s >= word && vowel(*s)) 713 s--; 714 while (s >= word && !vowel(*s)) 715 s--; 716 return (s); 717 } 718 719 int 720 vowel(int c) 721 { 722 723 switch (tolower(c)) { 724 case 'a': 725 case 'e': 726 case 'i': 727 case 'o': 728 case 'u': 729 case 'y': 730 return (1); 731 } 732 return (0); 733 } 734 735 /* 736 * Crummy way to Britishise. 737 */ 738 void 739 ise(void) 740 { 741 struct suftab *tab; 742 743 for (tab = suftab; tab->suf; tab++) { 744 /* Assume that suffix will contain 'z' if a1 or d1 do */ 745 if (strchr(tab->suf, 'z')) { 746 tab->suf = estrdup(tab->suf); 747 ztos(tab->suf); 748 if (strchr(tab->d1, 'z')) { 749 tab->d1 = estrdup(tab->d1); 750 ztos(tab->d1); 751 } 752 if (strchr(tab->a1, 'z')) { 753 tab->a1 = estrdup(tab->a1); 754 ztos(tab->a1); 755 } 756 } 757 } 758 } 759 760 void 761 ztos(char *s) 762 { 763 764 for (; *s; s++) 765 if (*s == 'z') 766 *s = 's'; 767 } 768 769 char * 770 estrdup(const char *s) 771 { 772 char *d; 773 774 if ((d = strdup(s)) == NULL) 775 err(1, "strdup"); 776 return (d); 777 } 778 779 /* 780 * Look up a word in the dictionary. 781 * Returns 1 if found, 0 if not. 782 */ 783 int 784 dict(char *bp, char *ep) 785 { 786 char c; 787 int i, rval; 788 789 c = *ep; 790 *ep = '\0'; 791 if (xflag) 792 printf("=%s\n", bp); 793 for (i = rval = 0; wlists[i].fd != -1; i++) { 794 if ((rval = look((unsigned char *)bp, wlists[i].front, 795 wlists[i].back)) == 1) 796 break; 797 } 798 *ep = c; 799 return (rval); 800 } 801 802 __dead void 803 usage(void) 804 { 805 extern char *__progname; 806 807 fprintf(stderr, "usage: %s [-bvx] [-o found-words] word-list ...\n", 808 __progname); 809 exit(1); 810 } 811