xref: /netbsd-src/usr.bin/spell/spellprog/spellprog.c (revision 8d9348aad107debd79570b2b2fe79a947e79dc19)
1*8d9348aaSnia /*	$NetBSD: spellprog.c,v 1.10 2021/11/09 09:41:05 nia Exp $	*/
2fcc96823Sperry 
3fcc96823Sperry /* derived from OpenBSD: spellprog.c,v 1.4 2003/06/03 02:56:16 millert Exp */
4fcc96823Sperry 
5fcc96823Sperry /*
6fcc96823Sperry  * Copyright (c) 1991, 1993
7fcc96823Sperry  *	The Regents of the University of California.  All rights reserved.
8fcc96823Sperry  *
9fcc96823Sperry  * Redistribution and use in source and binary forms, with or without
10fcc96823Sperry  * modification, are permitted provided that the following conditions
11fcc96823Sperry  * are met:
12fcc96823Sperry  * 1. Redistributions of source code must retain the above copyright
13fcc96823Sperry  *    notice, this list of conditions and the following disclaimer.
14fcc96823Sperry  * 2. Redistributions in binary form must reproduce the above copyright
15fcc96823Sperry  *    notice, this list of conditions and the following disclaimer in the
16fcc96823Sperry  *    documentation and/or other materials provided with the distribution.
17fcc96823Sperry  * 3. Neither the name of the University nor the names of its contributors
18fcc96823Sperry  *    may be used to endorse or promote products derived from this software
19fcc96823Sperry  *    without specific prior written permission.
20fcc96823Sperry  *
21fcc96823Sperry  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22fcc96823Sperry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23fcc96823Sperry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24fcc96823Sperry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25fcc96823Sperry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26fcc96823Sperry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27fcc96823Sperry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28fcc96823Sperry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29fcc96823Sperry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30fcc96823Sperry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31fcc96823Sperry  * SUCH DAMAGE.
32fcc96823Sperry  *
33fcc96823Sperry  *	@(#)spell.h	8.1 (Berkeley) 6/6/93
34fcc96823Sperry  */
35fcc96823Sperry /*
36fcc96823Sperry  * Copyright (C) Caldera International Inc.  2001-2002.
37fcc96823Sperry  * All rights reserved.
38fcc96823Sperry  *
39fcc96823Sperry  * Redistribution and use in source and binary forms, with or without
40fcc96823Sperry  * modification, are permitted provided that the following conditions
41fcc96823Sperry  * are met:
42fcc96823Sperry  * 1. Redistributions of source code and documentation must retain the above
43fcc96823Sperry  *    copyright notice, this list of conditions and the following disclaimer.
44fcc96823Sperry  * 2. Redistributions in binary form must reproduce the above copyright
45fcc96823Sperry  *    notice, this list of conditions and the following disclaimer in the
46fcc96823Sperry  *    documentation and/or other materials provided with the distribution.
47fcc96823Sperry  * 3. All advertising materials mentioning features or use of this software
48fcc96823Sperry  *    must display the following acknowledgement:
49fcc96823Sperry  *	This product includes software developed or owned by Caldera
50fcc96823Sperry  *	International, Inc.
51fcc96823Sperry  * 4. Neither the name of Caldera International, Inc. nor the names of other
52fcc96823Sperry  *    contributors may be used to endorse or promote products derived from
53fcc96823Sperry  *    this software without specific prior written permission.
54fcc96823Sperry  *
55fcc96823Sperry  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
56fcc96823Sperry  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
57fcc96823Sperry  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
58fcc96823Sperry  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
59fcc96823Sperry  * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT,
60fcc96823Sperry  * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
61fcc96823Sperry  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
62fcc96823Sperry  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63fcc96823Sperry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
64fcc96823Sperry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
65fcc96823Sperry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66fcc96823Sperry  * POSSIBILITY OF SUCH DAMAGE.
67fcc96823Sperry  */
68fcc96823Sperry 
6936c7456dSperry #include <sys/cdefs.h>
7036c7456dSperry 
71fcc96823Sperry #ifndef lint
72fcc96823Sperry static const char copyright[] =
73fcc96823Sperry "@(#) Copyright (c) 1991, 1993\n\
74fcc96823Sperry 	The Regents of the University of California.  All rights reserved.\n";
75fcc96823Sperry #endif /* not lint */
76fcc96823Sperry 
77fcc96823Sperry #ifndef lint
78fcc96823Sperry #if 0
79fcc96823Sperry static const char sccsid[] = "@(#)spell.c	8.1 (Berkeley) 6/6/93";
80fcc96823Sperry #else
81fcc96823Sperry #endif
82fcc96823Sperry static const char rcsid[] = "$OpenBSD: spellprog.c,v 1.4 2003/06/03 02:56:16 millert Exp $";
83fcc96823Sperry #endif /* not lint */
84fcc96823Sperry 
85fcc96823Sperry #include <sys/param.h>
86fcc96823Sperry #include <sys/mman.h>
87fcc96823Sperry #include <sys/stat.h>
88fcc96823Sperry 
89fcc96823Sperry #include <ctype.h>
90fcc96823Sperry #include <err.h>
91fcc96823Sperry #include <errno.h>
92fcc96823Sperry #include <fcntl.h>
93fcc96823Sperry #include <limits.h>
94fcc96823Sperry #include <locale.h>
95fcc96823Sperry #include <stdio.h>
96fcc96823Sperry #include <stdlib.h>
97fcc96823Sperry #include <string.h>
98fcc96823Sperry #include <unistd.h>
99cdab3a7aSchristos #include <util.h>
100fcc96823Sperry 
10197ccbe26Schristos #include "extern.h"
10297ccbe26Schristos 
103fcc96823Sperry #define DLEV 2
104fcc96823Sperry 
10597ccbe26Schristos static int	 dict(char *, char *);
10697ccbe26Schristos static int	 trypref(char *, const char *, size_t);
10797ccbe26Schristos static int	 tryword(char *, char *, size_t);
10897ccbe26Schristos static int	 suffix(char *, size_t);
10997ccbe26Schristos static int	 vowel(int);
11097ccbe26Schristos static const char *lookuppref(char **, char *);
11197ccbe26Schristos static char	*skipv(char *);
11297ccbe26Schristos static void	 ise(void);
11397ccbe26Schristos static void	 print_word(FILE *);
11497ccbe26Schristos static void	 ztos(char *);
11597ccbe26Schristos static int	 monosyl(char *, char *);
1168b0f9554Sperry static void 	 usage(void) __dead;
11797ccbe26Schristos static void	 getderiv(size_t);
118fcc96823Sperry 
11997ccbe26Schristos static int	 an(char *, const char *, const char *, size_t);
12097ccbe26Schristos static int	 bility(char *, const char *, const char *, size_t);
12197ccbe26Schristos static int	 es(char *, const char *, const char *, size_t);
12297ccbe26Schristos static int	 i_to_y(char *, const char *, const char *, size_t);
12397ccbe26Schristos static int	 ily(char *, const char *, const char *, size_t);
12497ccbe26Schristos static int	 ize(char *, const char *, const char *, size_t);
12597ccbe26Schristos static int	 metry(char *, const char *, const char *, size_t);
12697ccbe26Schristos static int	 ncy(char *, const char *, const char *, size_t);
12797ccbe26Schristos static int	 nop(char *, const char *, const char *, size_t);
12897ccbe26Schristos static int	 s(char *, const char *, const char *, size_t);
12997ccbe26Schristos static int	 strip(char *, const char *, const char *, size_t);
13097ccbe26Schristos static int	 tion(char *, const char *, const char *, size_t);
13197ccbe26Schristos static int	 y_to_e(char *, const char *, const char *, size_t);
13297ccbe26Schristos static int	 CCe(char *, const char *, const char *, size_t);
13397ccbe26Schristos static int	 VCe(char *, const char *, const char *, size_t);
134fcc96823Sperry 
1357fc92b02Schristos /*
1367fc92b02Schristos  * This cannot be const because we modify it when we choose british
1377fc92b02Schristos  * spelling.
1387fc92b02Schristos  */
13997ccbe26Schristos static struct suftab {
14097ccbe26Schristos 	const char *suf;
14197ccbe26Schristos 	int (*p1)(char *, const char *, const char *, size_t);
142fcc96823Sperry 	int n1;
14397ccbe26Schristos 	const char *d1;
14497ccbe26Schristos 	const char *a1;
14597ccbe26Schristos 	int (*p2)(char *, const char *, const char *, size_t);
146fcc96823Sperry 	int n2;
14797ccbe26Schristos 	const char *d2;
14897ccbe26Schristos 	const char *a2;
149fcc96823Sperry } suftab[] = {
1507284ae46Schristos 	{ .suf = "ssen",	.p1 = ily,	.n1 = 4,
1517284ae46Schristos 	  .d1 = "-y+iness", 	.a1 = "+ness" },
1527284ae46Schristos 	{ .suf = "ssel",	.p1 = ily,	.n1 = 4,
1537284ae46Schristos 	  .d1 = "-y+i+less", 	.a1 = "+less" },
1547284ae46Schristos 	{ .suf = "se",		.p1 = s,	.n1 = 1,
1557284ae46Schristos 	  .d1 = "", 		.a1 = "+s",	.p2 = es,
1567284ae46Schristos 	  .n2 = 2,		.d2 = "-y+ies",	.a2 = "+es" },
1577284ae46Schristos 	{ .suf = "s'",		.p1 = s,	.n1 = 2,
1587284ae46Schristos 	  .d1 = "", 		.a1 = "+'s" },
1597284ae46Schristos 	{ .suf = "s",		.p1 = s,	.n1 = 1,
1607284ae46Schristos 	  .d1 = "", 		.a1 = "+s" },
1617284ae46Schristos 	{ .suf = "ecn",		.p1 = ncy,	.n1 = 1,
1627284ae46Schristos 	  .d1 = "", 		.a1 = "-t+ce" },
1637284ae46Schristos 	{ .suf = "ycn",		.p1 = ncy,	.n1 = 1,
1647284ae46Schristos 	  .d1 = "", 		.a1 = "-cy+t" },
1657284ae46Schristos 	{ .suf = "ytilb",	.p1 = nop,	.n1 = 0,
1667284ae46Schristos 	  .d1 = "", 		.a1 = "" },
1677284ae46Schristos 	{ .suf = "ytilib",	.p1 = bility,	.n1 = 5,
1687284ae46Schristos 	  .d1 = "-le+ility", 	.a1 = "" },
1697284ae46Schristos 	{ .suf = "elbaif",	.p1 = i_to_y,	.n1 = 4,
1707284ae46Schristos 	  .d1 = "-y+iable", 	.a1 = "" },
1717284ae46Schristos 	{ .suf = "elba",	.p1 = CCe,	.n1 = 4,
1727284ae46Schristos 	  .d1 = "-e+able", 	.a1 = "+able" },
1737284ae46Schristos 	{ .suf = "yti",		.p1 = CCe,	.n1 = 3,
1747284ae46Schristos 	  .d1 = "-e+ity", 	.a1 = "+ity" },
1757284ae46Schristos 	{ .suf = "ylb",		.p1 = y_to_e,	.n1 = 1,
1767284ae46Schristos 	  .d1 = "-e+y", 	.a1 = "" },
1777284ae46Schristos 	{ .suf = "yl",		.p1 = ily,	.n1 = 2,
1787284ae46Schristos 	  .d1 = "-y+ily", 	.a1 = "+ly" },
1797284ae46Schristos 	{ .suf = "laci",	.p1 = strip,	.n1 = 2,
1807284ae46Schristos 	  .d1 = "", 		.a1 = "+al" },
1817284ae46Schristos 	{ .suf = "latnem",	.p1 = strip,	.n1 = 2,
1827284ae46Schristos 	  .d1 = "", 		.a1 = "+al" },
1837284ae46Schristos 	{ .suf = "lanoi",	.p1 = strip,	.n1 = 2,
1847284ae46Schristos 	  .d1 = "", 		.a1 = "+al" },
1857284ae46Schristos 	{ .suf = "tnem",	.p1 = strip,	.n1 = 4,
1867284ae46Schristos 	  .d1 = "", 		.a1 = "+ment" },
1877284ae46Schristos 	{ .suf = "gni",		.p1 = CCe,	.n1 = 3,
1887284ae46Schristos 	  .d1 = "-e+ing", 	.a1 = "+ing" },
1897284ae46Schristos 	{ .suf = "reta",	.p1 = nop,	.n1 = 0,
1907284ae46Schristos 	  .d1 = "", 		.a1 = "" },
1917284ae46Schristos 	{ .suf = "re",		.p1 = strip,	.n1 = 1,
1927284ae46Schristos 	  .d1 = "", 		.a1 = "+r",	.p2 = i_to_y,
1937284ae46Schristos 	  .n2 = 2,		.d2 = "-y+ier",	.a2 = "+er" },
1947284ae46Schristos 	{ .suf = "de",		.p1 = strip,	.n1 = 1,
1957284ae46Schristos 	  .d1 = "", 		.a1 = "+d",	.p2 = i_to_y,
1967284ae46Schristos 	  .n2 = 2,		.d2 = "-y+ied",	.a2 = "+ed" },
1977284ae46Schristos 	{ .suf = "citsi",	.p1 = strip,	.n1 = 2,
1987284ae46Schristos 	  .d1 = "", 		.a1 = "+ic" },
1997284ae46Schristos 	{ .suf = "cihparg",	.p1 = i_to_y,	.n1 = 1,
2007284ae46Schristos 	  .d1 = "-y+ic", 	.a1 = "" },
2017284ae46Schristos 	{ .suf = "tse",		.p1 = strip,	.n1 = 2,
2027284ae46Schristos 	  .d1 = "", 		.a1 = "+st",	.p2 = i_to_y,
2037284ae46Schristos 	  .n2 = 3,		.d2 = "-y+iest",.a2 = "+est" },
2047284ae46Schristos 	{ .suf = "cirtem",	.p1 = i_to_y,	.n1 = 1,
2057284ae46Schristos 	  .d1 = "-y+ic", 	.a1 = "" },
2067284ae46Schristos 	{ .suf = "yrtem",	.p1 = metry,	.n1 = 0,
2077284ae46Schristos 	  .d1 = "-ry+er", 	.a1 = "" },
2087284ae46Schristos 	{ .suf = "cigol",	.p1 = i_to_y,	.n1 = 1,
2097284ae46Schristos 	  .d1 = "-y+ic", 	.a1 = "" },
2107284ae46Schristos 	{ .suf = "tsigol",	.p1 = i_to_y,	.n1 = 2,
2117284ae46Schristos 	  .d1 = "-y+ist", 	.a1 = "" },
2127284ae46Schristos 	{ .suf = "tsi",		.p1 = VCe,	.n1 = 3,
2137284ae46Schristos 	  .d1 = "-e+ist", 	.a1 = "+ist" },
2147284ae46Schristos 	{ .suf = "msi",		.p1 = VCe,	.n1 = 3,
2157284ae46Schristos 	  .d1 = "-e+ism", 	.a1 = "+ist" },
2167284ae46Schristos 	{ .suf = "noitacif",	.p1 = i_to_y,	.n1 = 6,
2177284ae46Schristos 	  .d1 = "-y+ication", 	.a1 = "" },
2187284ae46Schristos 	{ .suf = "noitazi",	.p1 = ize,	.n1 = 5,
2197284ae46Schristos 	  .d1 = "-e+ation", 	.a1 = "" },
2207284ae46Schristos 	{ .suf = "rota",	.p1 = tion,	.n1 = 2,
2217284ae46Schristos 	  .d1 = "-e+or", 	.a1 = "" },
2227284ae46Schristos 	{ .suf = "noit",	.p1 = tion,	.n1 = 3,
2237284ae46Schristos 	  .d1 = "-e+ion", 	.a1 = "+ion" },
2247284ae46Schristos 	{ .suf = "naino",	.p1 = an,	.n1 = 3,
2257284ae46Schristos 	  .d1 = "", 		.a1 = "+ian" },
2267284ae46Schristos 	{ .suf = "na",		.p1 = an,	.n1 = 1,
2277284ae46Schristos 	  .d1 = "", 		.a1 = "+n" },
2287284ae46Schristos 	{ .suf = "evit",	.p1 = tion,	.n1 = 3,
2297284ae46Schristos 	  .d1 = "-e+ive", 	.a1 = "+ive" },
2307284ae46Schristos 	{ .suf = "ezi",		.p1 = CCe,	.n1 = 3,
2317284ae46Schristos 	  .d1 = "-e+ize", 	.a1 = "+ize" },
2327284ae46Schristos 	{ .suf = "pihs",	.p1 = strip,	.n1 = 4,
2337284ae46Schristos 	  .d1 = "", 		.a1 = "+ship" },
2347284ae46Schristos 	{ .suf = "dooh",	.p1 = ily,	.n1 = 4,
2357284ae46Schristos 	  .d1 = "-y+hood", 	.a1 = "+hood" },
2367284ae46Schristos 	{ .suf = "ekil",	.p1 = strip,	.n1 = 4,
2377284ae46Schristos 	  .d1 = "", 		.a1 = "+like" },
2387284ae46Schristos 	{ .suf = NULL, }
239fcc96823Sperry };
240fcc96823Sperry 
24197ccbe26Schristos static const char *preftab[] = {
242fcc96823Sperry 	"anti",
243fcc96823Sperry 	"bio",
244fcc96823Sperry 	"dis",
245fcc96823Sperry 	"electro",
246fcc96823Sperry 	"en",
247fcc96823Sperry 	"fore",
248fcc96823Sperry 	"hyper",
249fcc96823Sperry 	"intra",
250fcc96823Sperry 	"inter",
251fcc96823Sperry 	"iso",
252fcc96823Sperry 	"kilo",
253fcc96823Sperry 	"magneto",
254fcc96823Sperry 	"meta",
255fcc96823Sperry 	"micro",
256fcc96823Sperry 	"milli",
257fcc96823Sperry 	"mis",
258fcc96823Sperry 	"mono",
259fcc96823Sperry 	"multi",
260fcc96823Sperry 	"non",
261fcc96823Sperry 	"out",
262fcc96823Sperry 	"over",
263fcc96823Sperry 	"photo",
264fcc96823Sperry 	"poly",
265fcc96823Sperry 	"pre",
266fcc96823Sperry 	"pseudo",
267fcc96823Sperry 	"re",
268fcc96823Sperry 	"semi",
269fcc96823Sperry 	"stereo",
270fcc96823Sperry 	"sub",
271fcc96823Sperry 	"super",
272fcc96823Sperry 	"thermo",
273fcc96823Sperry 	"ultra",
274fcc96823Sperry 	"under",	/* must precede un */
275fcc96823Sperry 	"un",
276fcc96823Sperry 	NULL
277fcc96823Sperry };
278fcc96823Sperry 
27997ccbe26Schristos static struct wlist {
280fcc96823Sperry 	int fd;
281fcc96823Sperry 	unsigned char *front;
282fcc96823Sperry 	unsigned char *back;
283fcc96823Sperry } *wlists;
284fcc96823Sperry 
28597ccbe26Schristos static int vflag;
28697ccbe26Schristos static int xflag;
28797ccbe26Schristos static char word[LINE_MAX];
28897ccbe26Schristos static char original[LINE_MAX];
28997ccbe26Schristos static char affix[LINE_MAX];
29097ccbe26Schristos static struct {
29197ccbe26Schristos 	const char **buf;
29297ccbe26Schristos 	size_t maxlev;
29397ccbe26Schristos } deriv;
294fcc96823Sperry 
295fcc96823Sperry /*
296fcc96823Sperry  * The spellprog utility accepts a newline-delimited list of words
297fcc96823Sperry  * on stdin.  For arguments it expects the path to a word list and
298fcc96823Sperry  * the path to a file in which to store found words.
299fcc96823Sperry  *
300fcc96823Sperry  * In normal usage, spell is called twice.  The first time it is
301fcc96823Sperry  * called with a stop list to flag commonly mispelled words.  The
302fcc96823Sperry  * remaining words are then passed to spell again, this time with
303fcc96823Sperry  * the dictionary file as the first (non-flag) argument.
304fcc96823Sperry  *
305fcc96823Sperry  * Unlike historic versions of spellprog, this one does not use
306fcc96823Sperry  * hashed files.  Instead it simply requires that files be sorted
307fcc96823Sperry  * lexigraphically and uses the same algorithm as the look utility.
308fcc96823Sperry  *
309fcc96823Sperry  * Note that spellprog should be called via the spell shell script
310fcc96823Sperry  * and is not meant to be invoked directly by the user.
311fcc96823Sperry  */
312fcc96823Sperry 
313fcc96823Sperry int
main(int argc,char ** argv)314fcc96823Sperry main(int argc, char **argv)
315fcc96823Sperry {
316fcc96823Sperry 	char *ep, *cp, *dp;
317fcc96823Sperry 	char *outfile;
318fcc96823Sperry 	int ch, fold, i;
319fcc96823Sperry 	struct stat sb;
320fcc96823Sperry 	FILE *file, *found;
321fcc96823Sperry 
322fcc96823Sperry 	setlocale(LC_ALL, "");
323fcc96823Sperry 
324fcc96823Sperry 	outfile = NULL;
325fcc96823Sperry 	while ((ch = getopt(argc, argv, "bvxo:")) != -1) {
326fcc96823Sperry 		switch (ch) {
327fcc96823Sperry 		case 'b':
328fcc96823Sperry 			/* Use British dictionary and convert ize -> ise. */
329fcc96823Sperry 			ise();
330fcc96823Sperry 			break;
331fcc96823Sperry 		case 'o':
332fcc96823Sperry 			outfile = optarg;
333fcc96823Sperry 			break;
334fcc96823Sperry 		case 'v':
335fcc96823Sperry 			/* Also write derivations to "found" file. */
336fcc96823Sperry 			vflag++;
337fcc96823Sperry 			break;
338fcc96823Sperry 		case 'x':
339fcc96823Sperry 			/* Print plausible stems to stdout. */
340fcc96823Sperry 			xflag++;
341fcc96823Sperry 			break;
342fcc96823Sperry 		default:
343fcc96823Sperry 			usage();
344fcc96823Sperry 		}
345fcc96823Sperry 
346fcc96823Sperry 	}
347fcc96823Sperry 	argc -= optind;
348fcc96823Sperry 	argv += optind;
349fcc96823Sperry 	if (argc < 1)
350fcc96823Sperry 		usage();
351fcc96823Sperry 
352fcc96823Sperry 	/* Open and mmap the word/stop lists. */
353fcc96823Sperry 	if ((wlists = malloc(sizeof(struct wlist) * (argc + 1))) == NULL)
354fcc96823Sperry 		err(1, "malloc");
35597ccbe26Schristos 
356fcc96823Sperry 	for (i = 0; argc--; i++) {
357fcc96823Sperry 		wlists[i].fd = open(argv[i], O_RDONLY, 0);
358fcc96823Sperry 		if (wlists[i].fd == -1 || fstat(wlists[i].fd, &sb) != 0)
359fcc96823Sperry 			err(1, "%s", argv[i]);
360fcc96823Sperry 		if (sb.st_size > SIZE_T_MAX)
361fcc96823Sperry 			errx(1, "%s: %s", argv[i], strerror(EFBIG));
362fcc96823Sperry 		wlists[i].front = mmap(NULL, (size_t)sb.st_size, PROT_READ,
363fcc96823Sperry 		    MAP_PRIVATE, wlists[i].fd, (off_t)0);
364fcc96823Sperry 		if (wlists[i].front == MAP_FAILED)
365fcc96823Sperry 			err(1, "%s", argv[i]);
36697ccbe26Schristos 		wlists[i].back = wlists[i].front + (size_t)sb.st_size;
367fcc96823Sperry 	}
368fcc96823Sperry 	wlists[i].fd = -1;
369fcc96823Sperry 
370fcc96823Sperry 	/* Open file where found words are to be saved. */
371fcc96823Sperry 	if (outfile == NULL)
372fcc96823Sperry 		found = NULL;
373fcc96823Sperry 	else if ((found = fopen(outfile, "w")) == NULL)
374fcc96823Sperry 		err(1, "cannot open %s", outfile);
375fcc96823Sperry 
376fcc96823Sperry 	for (;; print_word(file)) {
377fcc96823Sperry 		affix[0] = '\0';
378fcc96823Sperry 		file = found;
379fcc96823Sperry 		for (ep = word; (*ep = ch = getchar()) != '\n'; ep++) {
380fcc96823Sperry 			if (ep - word == sizeof(word) - 1) {
381fcc96823Sperry 				*ep = '\0';
382fcc96823Sperry 				warnx("word too long (%s)", word);
383fcc96823Sperry 				while ((ch = getchar()) != '\n')
384fcc96823Sperry 					;	/* slurp until EOL */
385fcc96823Sperry 			}
386fcc96823Sperry 			if (ch == EOF) {
387fcc96823Sperry 				if (found != NULL)
388fcc96823Sperry 					fclose(found);
389fcc96823Sperry 				exit(0);
390fcc96823Sperry 			}
391fcc96823Sperry 		}
392fcc96823Sperry 		for (cp = word, dp = original; cp < ep; )
393fcc96823Sperry 			*dp++ = *cp++;
394fcc96823Sperry 		*dp = '\0';
395fcc96823Sperry 		fold = 0;
396fcc96823Sperry 		for (cp = word; cp < ep; cp++)
397fcc96823Sperry 			if (islower((unsigned char)*cp))
398fcc96823Sperry 				goto lcase;
399fcc96823Sperry 		if (trypref(ep, ".", 0))
400fcc96823Sperry 			continue;
401fcc96823Sperry 		++fold;
402fcc96823Sperry 		for (cp = original + 1, dp = word + 1; dp < ep; dp++, cp++)
403fcc96823Sperry 			*dp = tolower((unsigned char)*cp);
404fcc96823Sperry lcase:
405fcc96823Sperry 		if (trypref(ep, ".", 0) || suffix(ep, 0))
406fcc96823Sperry 			continue;
407fcc96823Sperry 		if (isupper((unsigned char)word[0])) {
408fcc96823Sperry 			for (cp = original, dp = word; (*dp = *cp++); dp++) {
409fcc96823Sperry 				if (fold)
410fcc96823Sperry 					*dp = tolower((unsigned char)*dp);
411fcc96823Sperry 			}
412fcc96823Sperry 			word[0] = tolower((unsigned char)word[0]);
413fcc96823Sperry 			goto lcase;
414fcc96823Sperry 		}
415fcc96823Sperry 		file = stdout;
416fcc96823Sperry 	}
417fcc96823Sperry }
418fcc96823Sperry 
41997ccbe26Schristos static void
print_word(FILE * f)420fcc96823Sperry print_word(FILE *f)
421fcc96823Sperry {
422fcc96823Sperry 
423fcc96823Sperry 	if (f != NULL) {
424fcc96823Sperry 		if (vflag && affix[0] != '\0' && affix[0] != '.')
425fcc96823Sperry 			fprintf(f, "%s\t%s\n", affix, original);
426fcc96823Sperry 		else
427fcc96823Sperry 			fprintf(f, "%s\n", original);
428fcc96823Sperry 	}
429fcc96823Sperry }
430fcc96823Sperry 
431fcc96823Sperry /*
432fcc96823Sperry  * For each matching suffix in suftab, call the function associated
433fcc96823Sperry  * with that suffix (p1 and p2).
434fcc96823Sperry  */
43597ccbe26Schristos static int
suffix(char * ep,size_t lev)43697ccbe26Schristos suffix(char *ep, size_t lev)
437fcc96823Sperry {
4387fc92b02Schristos 	const struct suftab *t;
43997ccbe26Schristos 	char *cp;
44097ccbe26Schristos 	const char *sp;
441fcc96823Sperry 
442fcc96823Sperry 	lev += DLEV;
44397ccbe26Schristos 	getderiv(lev + 1);
44497ccbe26Schristos 	deriv.buf[lev] = deriv.buf[lev - 1] = 0;
44597ccbe26Schristos 	for (t = suftab; (sp = t->suf) != NULL; t++) {
446fcc96823Sperry 		cp = ep;
447fcc96823Sperry 		while (*sp) {
448fcc96823Sperry 			if (*--cp != *sp++)
449fcc96823Sperry 				goto next;
450fcc96823Sperry 		}
451fcc96823Sperry 		for (sp = cp; --sp >= word && !vowel(*sp);)
452fcc96823Sperry 			;	/* nothing */
453fcc96823Sperry 		if (sp < word)
45497ccbe26Schristos 			return 0;
455fcc96823Sperry 		if ((*t->p1)(ep - t->n1, t->d1, t->a1, lev + 1))
45697ccbe26Schristos 			return 1;
457fcc96823Sperry 		if (t->p2 != NULL) {
458eb3bd1d5Sjoerg 			deriv.buf[lev] = deriv.buf[lev + 1] = NULL;
45997ccbe26Schristos 			return (*t->p2)(ep - t->n2, t->d2, t->a2, lev);
460fcc96823Sperry 		}
46197ccbe26Schristos 		return 0;
462fcc96823Sperry next:		;
463fcc96823Sperry 	}
46497ccbe26Schristos 	return 0;
465fcc96823Sperry }
466fcc96823Sperry 
46797ccbe26Schristos static int
46897ccbe26Schristos /*ARGSUSED*/
nop(char * ep,const char * d,const char * a,size_t lev)46997ccbe26Schristos nop(char *ep, const char *d, const char *a, size_t lev)
470fcc96823Sperry {
471fcc96823Sperry 
47297ccbe26Schristos 	return 0;
473fcc96823Sperry }
474fcc96823Sperry 
47597ccbe26Schristos static int
47697ccbe26Schristos /*ARGSUSED*/
strip(char * ep,const char * d,const char * a,size_t lev)47797ccbe26Schristos strip(char *ep, const char *d, const char *a, size_t lev)
478fcc96823Sperry {
479fcc96823Sperry 
48097ccbe26Schristos 	return trypref(ep, a, lev) || suffix(ep, lev);
481fcc96823Sperry }
482fcc96823Sperry 
48397ccbe26Schristos static int
s(char * ep,const char * d,const char * a,const size_t lev)48497ccbe26Schristos s(char *ep, const char *d, const char *a, const size_t lev)
485fcc96823Sperry {
486fcc96823Sperry 
487fcc96823Sperry 	if (lev > DLEV + 1)
48897ccbe26Schristos 		return 0;
489fcc96823Sperry 	if (*ep == 's' && ep[-1] == 's')
49097ccbe26Schristos 		return 0;
49197ccbe26Schristos 	return strip(ep, d, a, lev);
492fcc96823Sperry }
493fcc96823Sperry 
49497ccbe26Schristos static int
49597ccbe26Schristos /*ARGSUSED*/
an(char * ep,const char * d,const char * a,size_t lev)49697ccbe26Schristos an(char *ep, const char *d, const char *a, size_t lev)
497fcc96823Sperry {
498fcc96823Sperry 
499fcc96823Sperry 	if (!isupper((unsigned char)*word))	/* must be proper name */
50097ccbe26Schristos 		return 0;
50197ccbe26Schristos 	return trypref(ep, a, lev);
502fcc96823Sperry }
503fcc96823Sperry 
50497ccbe26Schristos static int
50597ccbe26Schristos /*ARGSUSED*/
ize(char * ep,const char * d,const char * a,size_t lev)50697ccbe26Schristos ize(char *ep, const char *d, const char *a, size_t lev)
507fcc96823Sperry {
508fcc96823Sperry 
509fcc96823Sperry 	*ep++ = 'e';
51097ccbe26Schristos 	return strip(ep ,"", d, lev);
511fcc96823Sperry }
512fcc96823Sperry 
51397ccbe26Schristos static int
51497ccbe26Schristos /*ARGSUSED*/
y_to_e(char * ep,const char * d,const char * a,size_t lev)51597ccbe26Schristos y_to_e(char *ep, const char *d, const char *a, size_t lev)
516fcc96823Sperry {
517fcc96823Sperry 	char c = *ep;
518fcc96823Sperry 
519fcc96823Sperry 	*ep++ = 'e';
520fcc96823Sperry 	if (strip(ep, "", d, lev))
52197ccbe26Schristos 		return 1;
522fcc96823Sperry 	ep[-1] = c;
52397ccbe26Schristos 	return 0;
524fcc96823Sperry }
525fcc96823Sperry 
52697ccbe26Schristos static int
ily(char * ep,const char * d,const char * a,size_t lev)52797ccbe26Schristos ily(char *ep, const char *d, const char *a, size_t lev)
528fcc96823Sperry {
529fcc96823Sperry 
530fcc96823Sperry 	if (ep[-1] == 'i')
53197ccbe26Schristos 		return i_to_y(ep, d, a, lev);
532fcc96823Sperry 	else
53397ccbe26Schristos 		return strip(ep, d, a, lev);
534fcc96823Sperry }
535fcc96823Sperry 
53697ccbe26Schristos static int
ncy(char * ep,const char * d,const char * a,size_t lev)53797ccbe26Schristos ncy(char *ep, const char *d, const char *a, size_t lev)
538fcc96823Sperry {
539fcc96823Sperry 
540fcc96823Sperry 	if (skipv(skipv(ep - 1)) < word)
54197ccbe26Schristos 		return 0;
542fcc96823Sperry 	ep[-1] = 't';
54397ccbe26Schristos 	return strip(ep, d, a, lev);
544fcc96823Sperry }
545fcc96823Sperry 
54697ccbe26Schristos static int
bility(char * ep,const char * d,const char * a,size_t lev)54797ccbe26Schristos bility(char *ep, const char *d, const char *a, size_t lev)
548fcc96823Sperry {
549fcc96823Sperry 
550fcc96823Sperry 	*ep++ = 'l';
55197ccbe26Schristos 	return y_to_e(ep, d, a, lev);
552fcc96823Sperry }
553fcc96823Sperry 
55497ccbe26Schristos static int
i_to_y(char * ep,const char * d,const char * a,size_t lev)55597ccbe26Schristos i_to_y(char *ep, const char *d, const char *a, size_t lev)
556fcc96823Sperry {
557fcc96823Sperry 
558fcc96823Sperry 	if (ep[-1] == 'i') {
559fcc96823Sperry 		ep[-1] = 'y';
560fcc96823Sperry 		a = d;
561fcc96823Sperry 	}
56297ccbe26Schristos 	return strip(ep, "", a, lev);
563fcc96823Sperry }
564fcc96823Sperry 
56597ccbe26Schristos static int
es(char * ep,const char * d,const char * a,size_t lev)56697ccbe26Schristos es(char *ep, const char *d, const char *a, size_t lev)
567fcc96823Sperry {
568fcc96823Sperry 
569fcc96823Sperry 	if (lev > DLEV)
57097ccbe26Schristos 		return 0;
571fcc96823Sperry 
572fcc96823Sperry 	switch (ep[-1]) {
573fcc96823Sperry 	default:
57497ccbe26Schristos 		return 0;
575fcc96823Sperry 	case 'i':
57697ccbe26Schristos 		return i_to_y(ep, d, a, lev);
577fcc96823Sperry 	case 's':
578fcc96823Sperry 	case 'h':
579fcc96823Sperry 	case 'z':
580fcc96823Sperry 	case 'x':
58197ccbe26Schristos 		return strip(ep, d, a, lev);
582fcc96823Sperry 	}
583fcc96823Sperry }
584fcc96823Sperry 
58597ccbe26Schristos static int
metry(char * ep,const char * d,const char * a,size_t lev)58697ccbe26Schristos metry(char *ep, const char *d, const char *a, size_t lev)
587fcc96823Sperry {
588fcc96823Sperry 
589fcc96823Sperry 	ep[-2] = 'e';
590fcc96823Sperry 	ep[-1] = 'r';
59197ccbe26Schristos 	return strip(ep, d, a, lev);
592fcc96823Sperry }
593fcc96823Sperry 
59497ccbe26Schristos static int
tion(char * ep,const char * d,const char * a,size_t lev)59597ccbe26Schristos tion(char *ep, const char *d, const char *a, size_t lev)
596fcc96823Sperry {
597fcc96823Sperry 
598fcc96823Sperry 	switch (ep[-2]) {
599fcc96823Sperry 	case 'c':
600fcc96823Sperry 	case 'r':
60197ccbe26Schristos 		return trypref(ep, a, lev);
602fcc96823Sperry 	case 'a':
60397ccbe26Schristos 		return y_to_e(ep, d, a, lev);
604fcc96823Sperry 	}
60597ccbe26Schristos 	return 0;
606fcc96823Sperry }
607fcc96823Sperry 
608fcc96823Sperry /*
609fcc96823Sperry  * Possible consonant-consonant-e ending.
610fcc96823Sperry  */
61197ccbe26Schristos static int
CCe(char * ep,const char * d,const char * a,size_t lev)61297ccbe26Schristos CCe(char *ep, const char *d, const char *a, size_t lev)
613fcc96823Sperry {
614fcc96823Sperry 
615fcc96823Sperry 	switch (ep[-1]) {
616fcc96823Sperry 	case 'l':
617fcc96823Sperry 		if (vowel(ep[-2]))
618fcc96823Sperry 			break;
619fcc96823Sperry 		switch (ep[-2]) {
620fcc96823Sperry 		case 'l':
621fcc96823Sperry 		case 'r':
622fcc96823Sperry 		case 'w':
623fcc96823Sperry 			break;
624fcc96823Sperry 		default:
62597ccbe26Schristos 			return y_to_e(ep, d, a, lev);
626fcc96823Sperry 		}
627fcc96823Sperry 		break;
628fcc96823Sperry 	case 's':
629fcc96823Sperry 		if (ep[-2] == 's')
630fcc96823Sperry 			break;
63197ccbe26Schristos 		/*FALLTHROUGH*/
632fcc96823Sperry 	case 'c':
633fcc96823Sperry 	case 'g':
634fcc96823Sperry 		if (*ep == 'a')
63597ccbe26Schristos 			return 0;
63697ccbe26Schristos 		/*FALLTHROUGH*/
637fcc96823Sperry 	case 'v':
638fcc96823Sperry 	case 'z':
639fcc96823Sperry 		if (vowel(ep[-2]))
640fcc96823Sperry 			break;
64197ccbe26Schristos 		/*FALLTHROUGH*/
642fcc96823Sperry 	case 'u':
643fcc96823Sperry 		if (y_to_e(ep, d, a, lev))
64497ccbe26Schristos 			return 1;
645fcc96823Sperry 		if (!(ep[-2] == 'n' && ep[-1] == 'g'))
64697ccbe26Schristos 			return 0;
647fcc96823Sperry 	}
64897ccbe26Schristos 	return VCe(ep, d, a, lev);
649fcc96823Sperry }
650fcc96823Sperry 
651fcc96823Sperry /*
652fcc96823Sperry  * Possible consonant-vowel-consonant-e ending.
653fcc96823Sperry  */
65497ccbe26Schristos static int
VCe(char * ep,const char * d,const char * a,size_t lev)65597ccbe26Schristos VCe(char *ep, const char *d, const char *a, size_t lev)
656fcc96823Sperry {
657fcc96823Sperry 	char c;
658fcc96823Sperry 
659fcc96823Sperry 	c = ep[-1];
660fcc96823Sperry 	if (c == 'e')
66197ccbe26Schristos 		return 0;
662fcc96823Sperry 	if (!vowel(c) && vowel(ep[-2])) {
663fcc96823Sperry 		c = *ep;
664fcc96823Sperry 		*ep++ = 'e';
665fcc96823Sperry 		if (trypref(ep, d, lev) || suffix(ep, lev))
66697ccbe26Schristos 			return 1;
667fcc96823Sperry 		ep--;
668fcc96823Sperry 		*ep = c;
669fcc96823Sperry 	}
67097ccbe26Schristos 	return strip(ep, d, a, lev);
671fcc96823Sperry }
672fcc96823Sperry 
67397ccbe26Schristos static const char *
lookuppref(char ** wp,char * ep)674fcc96823Sperry lookuppref(char **wp, char *ep)
675fcc96823Sperry {
67697ccbe26Schristos 	const char **sp, *cp;
67797ccbe26Schristos 	char *bp;
678fcc96823Sperry 
679fcc96823Sperry 	for (sp = preftab; *sp; sp++) {
680fcc96823Sperry 		bp = *wp;
681fcc96823Sperry 		for (cp = *sp; *cp; cp++, bp++) {
682fcc96823Sperry 			if (tolower((unsigned char)*bp) != *cp)
683fcc96823Sperry 				goto next;
684fcc96823Sperry 		}
685fcc96823Sperry 		for (cp = bp; cp < ep; cp++) {
686fcc96823Sperry 			if (vowel(*cp)) {
687fcc96823Sperry 				*wp = bp;
68897ccbe26Schristos 				return *sp;
689fcc96823Sperry 			}
690fcc96823Sperry 		}
691fcc96823Sperry next:		;
692fcc96823Sperry 	}
69397ccbe26Schristos 	return 0;
694fcc96823Sperry }
695fcc96823Sperry 
696fcc96823Sperry /*
697fcc96823Sperry  * If the word is not in the dictionary, try stripping off prefixes
698fcc96823Sperry  * until the word is found or we run out of prefixes to check.
699fcc96823Sperry  */
70097ccbe26Schristos static int
trypref(char * ep,const char * a,size_t lev)70197ccbe26Schristos trypref(char *ep, const char *a, size_t lev)
702fcc96823Sperry {
70397ccbe26Schristos 	const char *cp;
704fcc96823Sperry 	char *bp;
705fcc96823Sperry 	char *pp;
706fcc96823Sperry 	int val = 0;
707fcc96823Sperry 	char space[20];
708fcc96823Sperry 
70997ccbe26Schristos 	getderiv(lev + 2);
71097ccbe26Schristos 	deriv.buf[lev] = a;
711fcc96823Sperry 	if (tryword(word, ep, lev))
71297ccbe26Schristos 		return 1;
713fcc96823Sperry 	bp = word;
714fcc96823Sperry 	pp = space;
71597ccbe26Schristos 	deriv.buf[lev + 1] = pp;
71697ccbe26Schristos 	while ((cp = lookuppref(&bp, ep)) != NULL) {
717fcc96823Sperry 		*pp++ = '+';
718fcc96823Sperry 		while ((*pp = *cp++))
719fcc96823Sperry 			pp++;
720fcc96823Sperry 		if (tryword(bp, ep, lev + 1)) {
721fcc96823Sperry 			val = 1;
722fcc96823Sperry 			break;
723fcc96823Sperry 		}
724fcc96823Sperry 		if (pp - space >= sizeof(space))
72597ccbe26Schristos 			return 0;
726fcc96823Sperry 	}
727eb3bd1d5Sjoerg 	deriv.buf[lev + 1] = deriv.buf[lev + 2] = NULL;
72897ccbe26Schristos 	return val;
729fcc96823Sperry }
730fcc96823Sperry 
73197ccbe26Schristos static int
tryword(char * bp,char * ep,size_t lev)73297ccbe26Schristos tryword(char *bp, char *ep, size_t lev)
733fcc96823Sperry {
73497ccbe26Schristos 	size_t i, j;
735fcc96823Sperry 	char duple[3];
736fcc96823Sperry 
737fcc96823Sperry 	if (ep-bp <= 1)
73897ccbe26Schristos 		return 0;
739fcc96823Sperry 	if (vowel(*ep) && monosyl(bp, ep))
74097ccbe26Schristos 		return 0;
741fcc96823Sperry 
742fcc96823Sperry 	i = dict(bp, ep);
74397ccbe26Schristos 	if (i == 0 && vowel(*ep) && ep[-1] == ep[-2] &&
74497ccbe26Schristos 	    monosyl(bp, ep - 1)) {
745fcc96823Sperry 		ep--;
74697ccbe26Schristos 		getderiv(++lev);
74797ccbe26Schristos 		deriv.buf[lev] = duple;
748fcc96823Sperry 		duple[0] = '+';
749fcc96823Sperry 		duple[1] = *ep;
750fcc96823Sperry 		duple[2] = '\0';
751fcc96823Sperry 		i = dict(bp, ep);
752fcc96823Sperry 	}
753fcc96823Sperry 	if (vflag == 0 || i == 0)
75497ccbe26Schristos 		return i;
755fcc96823Sperry 
756fcc96823Sperry 	/* Also tack on possible derivations. (XXX - warn on truncation?) */
757fcc96823Sperry 	for (j = lev; j > 0; j--) {
75897ccbe26Schristos 		if (deriv.buf[j])
75997ccbe26Schristos 			(void)strlcat(affix, deriv.buf[j], sizeof(affix));
760fcc96823Sperry 	}
76197ccbe26Schristos 	return i;
762fcc96823Sperry }
763fcc96823Sperry 
76497ccbe26Schristos static int
monosyl(char * bp,char * ep)765fcc96823Sperry monosyl(char *bp, char *ep)
766fcc96823Sperry {
767fcc96823Sperry 
768fcc96823Sperry 	if (ep < bp + 2)
76997ccbe26Schristos 		return 0;
770fcc96823Sperry 	if (vowel(*--ep) || !vowel(*--ep) || ep[1] == 'x' || ep[1] == 'w')
77197ccbe26Schristos 		return 0;
772fcc96823Sperry 	while (--ep >= bp)
773fcc96823Sperry 		if (vowel(*ep))
77497ccbe26Schristos 			return 0;
77597ccbe26Schristos 	return 1;
776fcc96823Sperry }
777fcc96823Sperry 
77897ccbe26Schristos static char *
skipv(char * st)77997ccbe26Schristos skipv(char *st)
780fcc96823Sperry {
781fcc96823Sperry 
78297ccbe26Schristos 	if (st >= word && vowel(*st))
78397ccbe26Schristos 		st--;
78497ccbe26Schristos 	while (st >= word && !vowel(*st))
78597ccbe26Schristos 		st--;
78697ccbe26Schristos 	return st;
787fcc96823Sperry }
788fcc96823Sperry 
78997ccbe26Schristos static int
vowel(int c)790fcc96823Sperry vowel(int c)
791fcc96823Sperry {
792fcc96823Sperry 
793fcc96823Sperry 	switch (tolower(c)) {
794fcc96823Sperry 	case 'a':
795fcc96823Sperry 	case 'e':
796fcc96823Sperry 	case 'i':
797fcc96823Sperry 	case 'o':
798fcc96823Sperry 	case 'u':
799fcc96823Sperry 	case 'y':
80097ccbe26Schristos 		return 1;
801fcc96823Sperry 	}
80297ccbe26Schristos 	return 0;
803fcc96823Sperry }
804fcc96823Sperry 
805fcc96823Sperry /*
806fcc96823Sperry  * Crummy way to Britishise.
807fcc96823Sperry  */
80897ccbe26Schristos static void
ise(void)809fcc96823Sperry ise(void)
810fcc96823Sperry {
8112d45339eSchristos 	struct suftab *tab;
81297ccbe26Schristos 	char *cp;
813fcc96823Sperry 
814fcc96823Sperry 	for (tab = suftab; tab->suf; tab++) {
815fcc96823Sperry 		/* Assume that suffix will contain 'z' if a1 or d1 do */
816fcc96823Sperry 		if (strchr(tab->suf, 'z')) {
81797ccbe26Schristos 			tab->suf = cp = estrdup(tab->suf);
81897ccbe26Schristos 			ztos(cp);
819fcc96823Sperry 			if (strchr(tab->d1, 'z')) {
82097ccbe26Schristos 				tab->d1 = cp = estrdup(tab->d1);
82197ccbe26Schristos 				ztos(cp);
822fcc96823Sperry 			}
823fcc96823Sperry 			if (strchr(tab->a1, 'z')) {
82497ccbe26Schristos 				tab->a1 = cp = estrdup(tab->a1);
82597ccbe26Schristos 				ztos(cp);
826fcc96823Sperry 			}
827fcc96823Sperry 		}
828fcc96823Sperry 	}
829fcc96823Sperry }
830fcc96823Sperry 
83197ccbe26Schristos static void
ztos(char * st)83297ccbe26Schristos ztos(char *st)
833fcc96823Sperry {
834fcc96823Sperry 
83597ccbe26Schristos 	for (; *st; st++)
83697ccbe26Schristos 		if (*st == 'z')
83797ccbe26Schristos 			*st = 's';
838fcc96823Sperry }
839fcc96823Sperry 
840fcc96823Sperry /*
841fcc96823Sperry  * Look up a word in the dictionary.
842fcc96823Sperry  * Returns 1 if found, 0 if not.
843fcc96823Sperry  */
84497ccbe26Schristos static int
dict(char * bp,char * ep)845fcc96823Sperry dict(char *bp, char *ep)
846fcc96823Sperry {
847fcc96823Sperry 	char c;
848fcc96823Sperry 	int i, rval;
849fcc96823Sperry 
850fcc96823Sperry 	c = *ep;
851fcc96823Sperry 	*ep = '\0';
852fcc96823Sperry 	if (xflag)
853fcc96823Sperry 		printf("=%s\n", bp);
854fcc96823Sperry 	for (i = rval = 0; wlists[i].fd != -1; i++) {
855fcc96823Sperry 		if ((rval = look((unsigned char *)bp, wlists[i].front,
856fcc96823Sperry 		    wlists[i].back)) == 1)
857fcc96823Sperry 			break;
858fcc96823Sperry 	}
859fcc96823Sperry 	*ep = c;
86097ccbe26Schristos 	return rval;
861fcc96823Sperry }
862fcc96823Sperry 
86397ccbe26Schristos static void
getderiv(size_t lev)86497ccbe26Schristos getderiv(size_t lev)
86597ccbe26Schristos {
86697ccbe26Schristos 	if (deriv.maxlev < lev) {
867*8d9348aaSnia 		if (reallocarr(&deriv.buf, lev, sizeof(*deriv.buf)) != 0)
86897ccbe26Schristos 			err(1, "Cannot grow array");
86997ccbe26Schristos 		deriv.maxlev = lev;
87097ccbe26Schristos 	}
87197ccbe26Schristos }
87297ccbe26Schristos 
87397ccbe26Schristos 
87497ccbe26Schristos static void
usage(void)875fcc96823Sperry usage(void)
876fcc96823Sperry {
87797ccbe26Schristos 	(void)fprintf(stderr,
87897ccbe26Schristos 	    "Usage: %s [-bvx] [-o found-words] word-list ...\n",
87997ccbe26Schristos 	    getprogname());
880fcc96823Sperry 	exit(1);
881fcc96823Sperry }
882