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