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