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