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