diff --git a/usr.bin/Makefile b/usr.bin/Makefile --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -32,6 +32,7 @@ csplit \ ctlstat \ cut \ + deroff \ diff \ dirname \ dtc \ @@ -141,6 +142,7 @@ sockstat \ soelim \ sort \ + spell \ split \ stat \ stdbuf \ diff --git a/usr.bin/deroff/Makefile b/usr.bin/deroff/Makefile new file mode 100644 --- /dev/null +++ b/usr.bin/deroff/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $OpenBSD: Makefile,v 1.1 2002/02/28 06:58:21 millert Exp $ + +PROG= deroff + +.include + +CFLAGS+=-Wno-strict-prototypes -Wno-unused-parameter +CFLAGS+=-Wno-implicit-function-declaration -Wno-cast-qual +CFLAGS+=-Wno-missing-variable-declarations -Wno-sign-compare diff --git a/usr.bin/deroff/deroff.1 b/usr.bin/deroff/deroff.1 new file mode 100644 --- /dev/null +++ b/usr.bin/deroff/deroff.1 @@ -0,0 +1,176 @@ +.\" $OpenBSD: deroff.1,v 1.12 2022/12/28 13:00:57 jsg Exp $ +.\" +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Copyright (C) Caldera International Inc. 2001-2002. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code and documentation must retain the above +.\" copyright notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed or owned by Caldera +.\" International, Inc. +.\" 4. Neither the name of Caldera International, Inc. nor the names of other +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA +.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, +.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" @(#)deroff.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd $Mdocdate: December 28 2022 $ +.Dt DEROFF 1 +.Os +.Sh NAME +.Nm deroff +.Nd remove nroff/troff, eqn, pic and tbl constructs +.Sh SYNOPSIS +.Nm deroff +.Op Fl ikpw +.Oo +.Fl m +.Ar a | e | l | m | s +.Oc +.Op Ar +.Sh DESCRIPTION +.Nm deroff +reads each file in sequence and removes all roff +command lines, backslash constructions, macro definitions, +eqn constructs (between +.Dq .EQ +and +.Dq .EN +lines or between delimiters), +pic pictures, +and table descriptions and writes the remainder to the standard output. +.Nm +follows chains of included files +.Po +.Dq .so +and +.Dq .nx +commands +.Pc ; +if a file has already been included, a +.Dq .so +is ignored and a +.Dq .nx +terminates execution. +If no input file is given, +.Nm +reads from the standard input. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl i +Ignore +.Dq .so +and +.Dq .nx +commands. +.It Fl k +Keep blocks of text intact. +This is the default behavior unless the +.Fl m +option is given. +.It Fl m +Enable support for common macro packages. +The +.Fl m +option takes the following arguments: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It a +recognize +.Xr man 7 +macros. +.It e +recognize me macros. +.It l +remove list constructs. +.It m +recognize mm macros. +.It s +recognize ms macros. +.El +.It Fl p +Preserve paragraph macros. +This option only has an effect if the +.Fl m +option is also specified. +.It Fl w +Output a word list, one +.Sq word +(string of letters, digits, and apostrophes, beginning with a letter; +apostrophes are removed) per line, and all other characters ignored. +Normally, the output follows the original, with the deletions mentioned above. +.El +.Sh SEE ALSO +.Xr man 7 +.Sh HISTORY +.Nm +first appeared outside of Bell Labs in PWB/UNIX 1.0. +It did not appear in freely redistributable +.Bx +releases for licensing reasons. +After Caldera relicensed early UNIX releases the +.Bx 4.4 +version was added to +.Ox 3.1 +and later to +.Fx 14 . +.Sh AUTHORS +.An Lorinda Cherry +at the Bell Labs Computing Science Research Center. +.Sh BUGS +.Nm +is not a complete troff interpreter, +so it can be confused by subtle constructs. +Most errors result in too much rather than too little output. +.Pp +The +.Fl ml +option does not correctly handle nested lists. diff --git a/usr.bin/deroff/deroff.c b/usr.bin/deroff/deroff.c new file mode 100644 --- /dev/null +++ b/usr.bin/deroff/deroff.c @@ -0,0 +1,1713 @@ +/* $OpenBSD: deroff.c,v 1.16 2023/02/17 18:00:35 miod Exp $ */ + +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (C) Caldera International Inc. 2001-2002. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * 4. Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, + * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Deroff command -- strip troff, eqn, and Tbl sequences from + * a file. Has two flags argument, -w, to cause output one word per line + * rather than in the original format. + * -mm (or -ms) causes the corresponding macro's to be interpreted + * so that just sentences are output + * -ml also gets rid of lists. + * Deroff follows .so and .nx commands, removes contents of macro + * definitions, equations (both .EQ ... .EN and $...$), + * Tbl command sequences, and Troff backslash constructions. + * + * All input is through the Cget macro; + * the most recently read character is in c. + * + * Modified by Robert Henry to process -me and -man macros. + */ + +#define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) ) +#define C1get ( (c=getc(infile)) == EOF ? eof() : c) + +#ifdef DEBUG +# define C _C() +# define C1 _C1() +#else /* not DEBUG */ +# define C Cget +# define C1 C1get +#endif /* not DEBUG */ + +#define SKIP while (C != '\n') +#define SKIP_TO_COM SKIP; SKIP; pc=c; while (C != '.' || pc != '\n' || C > 'Z')pc=c + +#define YES 1 +#define NO 0 +#define MS 0 /* -ms */ +#define MM 1 /* -mm */ +#define ME 2 /* -me */ +#define MA 3 /* -man */ + +#ifdef DEBUG +char *mactab[] = { "-ms", "-mm", "-me", "-ma" }; +#endif /* DEBUG */ + +#define ONE 1 +#define TWO 2 + +#define NOCHAR -2 +#define SPECIAL 0 +#define APOS 1 +#define PUNCT 2 +#define DIGIT 3 +#define LETTER 4 + +#define MAXFILES 20 + +int iflag; +int wordflag; +int msflag; /* processing a source written using a mac package */ +int mac; /* which package */ +int disp; +int parag; +int inmacro; +int intable; +int keepblock; /* keep blocks of text; normally false when msflag */ + +char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */ + +char line[LINE_MAX]; +char *lp; + +int c; +int pc; +int ldelim; +int rdelim; + +char fname[PATH_MAX]; +FILE *files[MAXFILES]; +FILE **filesp; +FILE *infile; + +int argc; +char **argv; + +/* + * Macro processing + * + * Macro table definitions + */ +typedef int pacmac; /* compressed macro name */ +int argconcat = 0; /* concat arguments together (-me only) */ + +#define tomac(c1, c2) ((((c1) & 0xFF) << 8) | ((c2) & 0xFF)) +#define frommac(src, c1, c2) (((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF)) + +struct mactab{ + int condition; + pacmac macname; + int (*func)(); /* XXX - args */ +}; + +struct mactab troffmactab[]; +struct mactab ppmactab[]; +struct mactab msmactab[]; +struct mactab mmmactab[]; +struct mactab memactab[]; +struct mactab manmactab[]; + +/* + * Macro table initialization + */ +#define M(cond, c1, c2, func) {cond, tomac(c1, c2), func} + +/* + * Flags for matching conditions other than + * the macro name + */ +#define NONE 0 +#define FNEST 1 /* no nested files */ +#define NOMAC 2 /* no macro */ +#define MAC 3 /* macro */ +#define PARAG 4 /* in a paragraph */ +#define MSF 5 /* msflag is on */ +#define NBLK 6 /* set if no blocks to be kept */ + +/* + * Return codes from macro minions, determine where to jump, + * how to repeat/reprocess text + */ +#define COMX 1 /* goto comx */ +#define COM 2 /* goto com */ + +int skeqn(void); +int eof(void); +int _C1(void); +int _C(void); +int EQ(void); +int domacro(void); +int PS(void); +int skip(void); +int intbl(void); +int outtbl(void); +int so(void); +int nx(void); +int skiptocom(void); +int PP(pacmac); +int AU(void); +int SH(pacmac); +int UX(void); +int MMHU(pacmac); +int mesnblock(pacmac); +int mssnblock(pacmac); +int nf(void); +int ce(void); +int meip(pacmac); +int mepp(pacmac); +int mesh(pacmac); +int mefont(pacmac); +int manfont(pacmac); +int manpp(pacmac); +int macsort(const void *, const void *); +int sizetab(struct mactab *); +void getfname(void); +void textline(char *, int); +void work(void); +void regline(void (*)(char *, int), int); +void macro(void); +void tbl(void); +void stbl(void); +void eqn(void); +void backsl(void); +void sce(void); +void refer(int); +void inpic(void); +void msputmac(char *, int); +void msputwords(int); +void meputmac(char *, int); +void meputwords(int); +void noblock(char, char); +void defcomline(pacmac); +void comline(void); +void buildtab(struct mactab **, int *); +FILE *opn(char *); +struct mactab *macfill(struct mactab *, struct mactab *); +void usage(void); + +int +main(int ac, char **av) +{ + int i, ch; + int errflg = 0; + int kflag = NO; + + iflag = NO; + wordflag = NO; + msflag = NO; + mac = ME; + disp = NO; + parag = NO; + inmacro = NO; + intable = NO; + ldelim = NOCHAR; + rdelim = NOCHAR; + keepblock = YES; + + while ((ch = getopt(ac, av, "ikpwm:")) != -1) { + switch (ch) { + case 'i': + iflag = YES; + break; + case 'k': + kflag = YES; + break; + case 'm': + msflag = YES; + keepblock = NO; + switch (optarg[0]) { + case 'm': + mac = MM; + break; + case 's': + mac = MS; + break; + case 'e': + mac = ME; + break; + case 'a': + mac = MA; + break; + case 'l': + disp = YES; + break; + default: + errflg = 1; + break; + } + if (optarg[1] != '\0') + errflg = 1; + break; + case 'p': + parag = YES; + break; + case 'w': + wordflag = YES; + kflag = YES; + break; + default: + errflg = 1; + } + } + argc = ac - optind; + argv = av + optind; + + if (kflag) + keepblock = YES; + if (errflg) + usage(); + +#ifdef DEBUG + printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n", + msflag, mactab[mac], keepblock, disp); +#endif /* DEBUG */ + if (argc == 0) { + infile = stdin; + } else { + infile = opn(argv[0]); + --argc; + ++argv; + } + files[0] = infile; + filesp = &files[0]; + + for (i = 'a'; i <= 'z'; ++i) + chars[i] = LETTER; + for (i = 'A'; i <= 'Z'; ++i) + chars[i] = LETTER; + for (i = '0'; i <= '9'; ++i) + chars[i] = DIGIT; + chars['\''] = APOS; + chars['&'] = APOS; + chars['.'] = PUNCT; + chars[','] = PUNCT; + chars[';'] = PUNCT; + chars['?'] = PUNCT; + chars[':'] = PUNCT; + work(); + exit(0); +} + +int +skeqn(void) +{ + + while ((c = getc(infile)) != rdelim) { + if (c == EOF) + c = eof(); + else if (c == '"') { + while ((c = getc(infile)) != '"') { + if (c == EOF || + (c == '\\' && (c = getc(infile)) == EOF)) + c = eof(); + } + } + } + if (msflag) + return((c = 'x')); + return((c = ' ')); +} + +FILE * +opn(char *p) +{ + FILE *fd; + + if ((fd = fopen(p, "r")) == NULL) + err(1, "fopen %s", p); + + return(fd); +} + +int +eof(void) +{ + + if (infile != stdin) + fclose(infile); + if (filesp > files) + infile = *--filesp; + else if (argc > 0) { + infile = opn(argv[0]); + --argc; + ++argv; + } else + exit(0); + return(C); +} + +void +getfname(void) +{ + char *p; + struct chain { + struct chain *nextp; + char *datap; + } *q; + static struct chain *namechain= NULL; + + while (C == ' ') + ; /* nothing */ + + for (p = fname ; p - fname < sizeof(fname) && (*p = c) != '\n' && + c != ' ' && c != '\t' && c != '\\'; ++p) + C; + *p = '\0'; + while (c != '\n') + C; + + /* see if this name has already been used */ + for (q = namechain ; q; q = q->nextp) + if (strcmp(fname, q->datap) == 0) { + fname[0] = '\0'; + return; + } + + q = malloc(sizeof(struct chain)); + if (q == NULL) + err(1, NULL); + q->nextp = namechain; + q->datap = strdup(fname); + if (q->datap == NULL) + err(1, NULL); + namechain = q; +} + +/*ARGSUSED*/ +void +textline(char *str, int constant) +{ + + if (wordflag) { + msputwords(0); + return; + } + puts(str); +} + +void +work(void) +{ + + for (;;) { + C; +#ifdef FULLDEBUG + printf("Starting work with `%c'\n", c); +#endif /* FULLDEBUG */ + if (c == '.' || c == '\'') + comline(); + else + regline(textline, TWO); + } +} + +void +regline(void (*pfunc)(char *, int), int constant) +{ + + line[0] = c; + lp = line; + while (lp - line < sizeof(line)) { + if (c == '\\') { + *lp = ' '; + backsl(); + } + if (c == '\n') + break; + if (intable && c == 'T') { + *++lp = C; + if (c == '{' || c == '}') { + lp[-1] = ' '; + *lp = C; + } + } else { + *++lp = C; + } + } + *lp = '\0'; + + if (line[0] != '\0') + (*pfunc)(line, constant); +} + +void +macro(void) +{ + + if (msflag) { + do { + SKIP; + } while (C!='.' || C!='.' || C=='.'); /* look for .. */ + if (c != '\n') + SKIP; + return; + } + SKIP; + inmacro = YES; +} + +void +tbl(void) +{ + + while (C != '.') + ; /* nothing */ + SKIP; + intable = YES; +} + +void +stbl(void) +{ + + while (C != '.') + ; /* nothing */ + SKIP_TO_COM; + if (c != 'T' || C != 'E') { + SKIP; + pc = c; + while (C != '.' || pc != '\n' || C != 'T' || C != 'E') + pc = c; + } +} + +void +eqn(void) +{ + int c1, c2; + int dflg; + char last; + + last=0; + dflg = 1; + SKIP; + + for (;;) { + if (C1 == '.' || c == '\'') { + while (C1 == ' ' || c == '\t') + ; + if (c == 'E' && C1 == 'N') { + SKIP; + if (msflag && dflg) { + putchar('x'); + putchar(' '); + if (last) { + putchar(last); + putchar('\n'); + } + } + return; + } + } else if (c == 'd') { + /* look for delim */ + if (C1 == 'e' && C1 == 'l') + if (C1 == 'i' && C1 == 'm') { + while (C1 == ' ') + ; /* nothing */ + + if ((c1 = c) == '\n' || + (c2 = C1) == '\n' || + (c1 == 'o' && c2 == 'f' && C1=='f')) { + ldelim = NOCHAR; + rdelim = NOCHAR; + } else { + ldelim = c1; + rdelim = c2; + } + } + dflg = 0; + } + + if (c != '\n') + while (C1 != '\n') { + if (chars[c] == PUNCT) + last = c; + else if (c != ' ') + last = 0; + } + } +} + +/* skip over a complete backslash construction */ +void +backsl(void) +{ + int bdelim; + +sw: + switch (C) { + case '"': + SKIP; + return; + + case 's': + if (C == '\\') + backsl(); + else { + while (C >= '0' && c <= '9') + ; /* nothing */ + ungetc(c, infile); + c = '0'; + } + --lp; + return; + + case 'f': + case 'n': + case '*': + if (C != '(') + return; + + case '(': + if (msflag) { + if (C == 'e') { + if (C == 'm') { + *lp = '-'; + return; + } + } + else if (c != '\n') + C; + return; + } + if (C != '\n') + C; + return; + + case '$': + C; /* discard argument number */ + return; + + case 'b': + case 'x': + case 'v': + case 'h': + case 'w': + case 'o': + case 'l': + case 'L': + if ((bdelim = C) == '\n') + return; + while (C != '\n' && c != bdelim) + if (c == '\\') + backsl(); + return; + + case '\\': + if (inmacro) + goto sw; + + default: + return; + } +} + +void +sce(void) +{ + char *ap; + int n, i; + char a[10]; + + for (ap = a; C != '\n'; ap++) { + *ap = c; + if (ap == &a[9]) { + SKIP; + ap = a; + break; + } + } + if (ap != a) + n = atoi(a); + else + n = 1; + for (i = 0; i < n;) { + if (C == '.') { + if (C == 'c') { + if (C == 'e') { + while (C == ' ') + ; /* nothing */ + if (c == '0') { + SKIP; + break; + } else + SKIP; + } + else + SKIP; + } else if (c == 'P' || C == 'P') { + if (c != '\n') + SKIP; + break; + } else if (c != '\n') + SKIP; + } else { + SKIP; + i++; + } + } +} + +void +refer(int c1) +{ + int c2; + + if (c1 != '\n') + SKIP; + + for (c2 = -1;;) { + if (C != '.') + SKIP; + else { + if (C != ']') + SKIP; + else { + while (C != '\n') + c2 = c; + if (c2 != -1 && chars[c2] == PUNCT) + putchar(c2); + return; + } + } + } +} + +void +inpic(void) +{ + int c1; + char *p1, *ep; + + SKIP; + p1 = line; + ep = line + sizeof(line) - 1; + c = '\n'; + for (;;) { + c1 = c; + if (C == '.' && c1 == '\n') { + if (C != 'P') { + if (c == '\n') + continue; + else { + SKIP; + c = '\n'; + continue; + } + } + if (C != 'E') { + if (c == '\n') + continue; + else { + SKIP; + c = '\n'; + continue; + } + } + SKIP; + return; + } + else if (c == '\"') { + while (C != '\"') { + if (c == '\\') { + if (C == '\"') + continue; + ungetc(c, infile); + backsl(); + } else if (p1 + 1 >= ep) { + errx(1, ".PS length exceeds limit"); + } else { + *p1++ = c; + } + } + *p1++ = ' '; + } + else if (c == '\n' && p1 != line) { + *p1 = '\0'; + if (wordflag) + msputwords(NO); + else { + puts(line); + putchar('\n'); + } + p1 = line; + } + } +} + +#ifdef DEBUG +int +_C1(void) +{ + + return(C1get); +} + +int +_C(void) +{ + + return(Cget); +} +#endif /* DEBUG */ + +/* + * Put out a macro line, using ms and mm conventions. + */ +void +msputmac(char *s, int constant) +{ + char *t; + int found; + int last; + + last = 0; + found = 0; + if (wordflag) { + msputwords(YES); + return; + } + while (*s) { + while (*s == ' ' || *s == '\t') + putchar(*s++); + for (t = s ; *t != ' ' && *t != '\t' && *t != '\0' ; ++t) + ; /* nothing */ + if (*s == '\"') + s++; + if (t > s + constant && chars[(unsigned char)s[0]] == LETTER && + chars[(unsigned char)s[1]] == LETTER) { + while (s < t) + if (*s == '\"') + s++; + else + putchar(*s++); + last = *(t-1); + found++; + } else if (found && chars[(unsigned char)s[0]] == PUNCT && + s[1] == '\0') { + putchar(*s++); + } else { + last = *(t - 1); + s = t; + } + } + putchar('\n'); + if (msflag && chars[last] == PUNCT) { + putchar(last); + putchar('\n'); + } +} + +/* + * put out words (for the -w option) with ms and mm conventions + */ +void +msputwords(int macline) +{ + char *p, *p1; + int i, nlet; + + for (p1 = line;;) { + /* + * skip initial specials ampersands and apostrophes + */ + while (chars[(unsigned char)*p1] < DIGIT) + if (*p1++ == '\0') + return; + nlet = 0; + for (p = p1 ; (i = chars[(unsigned char)*p]) != SPECIAL ; ++p) + if (i == LETTER) + ++nlet; + + if (nlet > 1 && chars[(unsigned char)p1[0]] == LETTER) { + /* + * delete trailing ampersands and apostrophes + */ + while ((i = chars[(unsigned char)p[-1]]) == PUNCT || + i == APOS ) + --p; + while (p1 < p) + putchar(*p1++); + putchar('\n'); + } else { + p1 = p; + } + } +} + +/* + * put out a macro using the me conventions + */ +#define SKIPBLANK(cp) while (*cp == ' ' || *cp == '\t') { cp++; } +#define SKIPNONBLANK(cp) while (*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; } + +void +meputmac(char *cp, int constant) +{ + char *np; + int found; + int argno; + int last; + int inquote; + + last = 0; + found = 0; + if (wordflag) { + meputwords(YES); + return; + } + for (argno = 0; *cp; argno++) { + SKIPBLANK(cp); + inquote = (*cp == '"'); + if (inquote) + cp++; + for (np = cp; *np; np++) { + switch (*np) { + case '\n': + case '\0': + break; + + case '\t': + case ' ': + if (inquote) + continue; + else + goto endarg; + + case '"': + if (inquote && np[1] == '"') { + memmove(np, np + 1, strlen(np)); + np++; + continue; + } else { + *np = ' '; /* bye bye " */ + goto endarg; + } + + default: + continue; + } + } + endarg: ; + /* + * cp points at the first char in the arg + * np points one beyond the last char in the arg + */ + if ((argconcat == 0) || (argconcat != argno)) + putchar(' '); +#ifdef FULLDEBUG + { + char *p; + printf("[%d,%d: ", argno, np - cp); + for (p = cp; p < np; p++) { + putchar(*p); + } + printf("]"); + } +#endif /* FULLDEBUG */ + /* + * Determine if the argument merits being printed + * + * constant is the cut off point below which something + * is not a word. + */ + if (((np - cp) > constant) && + (inquote || (chars[(unsigned char)cp[0]] == LETTER))) { + for (; cp < np; cp++) + putchar(*cp); + last = np[-1]; + found++; + } else if (found && (np - cp == 1) && + chars[(unsigned char)*cp] == PUNCT) { + putchar(*cp); + } else { + last = np[-1]; + } + cp = np; + } + if (msflag && chars[last] == PUNCT) + putchar(last); + putchar('\n'); +} + +/* + * put out words (for the -w option) with ms and mm conventions + */ +void +meputwords(int macline) +{ + + msputwords(macline); +} + +/* + * + * Skip over a nested set of macros + * + * Possible arguments to noblock are: + * + * fi end of unfilled text + * PE pic ending + * DE display ending + * + * for ms and mm only: + * KE keep ending + * + * NE undocumented match to NS (for mm?) + * LE mm only: matches RL or *L (for lists) + * + * for me: + * ([lqbzcdf] + */ +void +noblock(char a1, char a2) +{ + int c1,c2; + int eqnf; + int lct; + + lct = 0; + eqnf = 1; + SKIP; + for (;;) { + while (C != '.') + if (c == '\n') + continue; + else + SKIP; + if ((c1 = C) == '\n') + continue; + if ((c2 = C) == '\n') + continue; + if (c1 == a1 && c2 == a2) { + SKIP; + if (lct != 0) { + lct--; + continue; + } + if (eqnf) + putchar('.'); + putchar('\n'); + return; + } else if (a1 == 'L' && c2 == 'L') { + lct++; + SKIP; + } + /* + * equations (EQ) nested within a display + */ + else if (c1 == 'E' && c2 == 'Q') { + if ((mac == ME && a1 == ')') + || (mac != ME && a1 == 'D')) { + eqn(); + eqnf=0; + } + } + /* + * turning on filling is done by the paragraphing + * macros + */ + else if (a1 == 'f') { /* .fi */ + if ((mac == ME && (c2 == 'h' || c2 == 'p')) + || (mac != ME && (c1 == 'P' || c2 == 'P'))) { + SKIP; + return; + } + } else { + SKIP; + } + } +} + +int +EQ(void) +{ + + eqn(); + return(0); +} + +int +domacro(void) +{ + + macro(); + return(0); +} + +int +PS(void) +{ + + for (C; c == ' ' || c == '\t'; C) + ; /* nothing */ + + if (c == '<') { /* ".PS < file" -- don't expect a .PE */ + SKIP; + return(0); + } + if (!msflag) + inpic(); + else + noblock('P', 'E'); + return(0); +} + +int +skip(void) +{ + + SKIP; + return(0); +} + +int +intbl(void) +{ + + if (msflag) + stbl(); + else + tbl(); + return(0); +} + +int +outtbl(void) +{ + + intable = NO; + return(0); +} + +int +so(void) +{ + + if (!iflag) { + getfname(); + if (fname[0]) { + if (++filesp - &files[0] > MAXFILES) + err(1, "too many nested files (max %d)", + MAXFILES); + infile = *filesp = opn(fname); + } + } + return(0); +} + +int +nx(void) +{ + + if (!iflag) { + getfname(); + if (fname[0] == '\0') + exit(0); + if (infile != stdin) + fclose(infile); + infile = *filesp = opn(fname); + } + return(0); +} + +int +skiptocom(void) +{ + + SKIP_TO_COM; + return(COMX); +} + +int +PP(pacmac c12) +{ + int c1, c2; + + frommac(c12, c1, c2); + printf(".%c%c", c1, c2); + while (C != '\n') + putchar(c); + putchar('\n'); + return(0); +} + +int +AU(void) +{ + + if (mac == MM) + return(0); + SKIP_TO_COM; + return(COMX); +} + +int +SH(pacmac c12) +{ + int c1, c2; + + frommac(c12, c1, c2); + + if (parag) { + printf(".%c%c", c1, c2); + while (C != '\n') + putchar(c); + putchar(c); + putchar('!'); + for (;;) { + while (C != '\n') + putchar(c); + putchar('\n'); + if (C == '.') + return(COM); + putchar('!'); + putchar(c); + } + /*NOTREACHED*/ + } else { + SKIP_TO_COM; + return(COMX); + } +} + +int +UX(void) +{ + + if (wordflag) + printf("UNIX\n"); + else + printf("UNIX "); + return(0); +} + +int +MMHU(pacmac c12) +{ + int c1, c2; + + frommac(c12, c1, c2); + if (parag) { + printf(".%c%c", c1, c2); + while (C != '\n') + putchar(c); + putchar('\n'); + } else { + SKIP; + } + return(0); +} + +int +mesnblock(pacmac c12) +{ + int c1, c2; + + frommac(c12, c1, c2); + noblock(')', c2); + return(0); +} + +int +mssnblock(pacmac c12) +{ + int c1, c2; + + frommac(c12, c1, c2); + noblock(c1, 'E'); + return(0); +} + +int +nf(void) +{ + + noblock('f', 'i'); + return(0); +} + +int +ce(void) +{ + + sce(); + return(0); +} + +int +meip(pacmac c12) +{ + + if (parag) + mepp(c12); + else if (wordflag) /* save the tag */ + regline(meputmac, ONE); + else + SKIP; + return(0); +} + +/* + * only called for -me .pp or .sh, when parag is on + */ +int +mepp(pacmac c12) +{ + + PP(c12); /* eats the line */ + return(0); +} + +/* + * Start of a section heading; output the section name if doing words + */ +int +mesh(pacmac c12) +{ + + if (parag) + mepp(c12); + else if (wordflag) + defcomline(c12); + else + SKIP; + return(0); +} + +/* + * process a font setting + */ +int +mefont(pacmac c12) +{ + + argconcat = 1; + defcomline(c12); + argconcat = 0; + return(0); +} + +int +manfont(pacmac c12) +{ + + return(mefont(c12)); +} + +int +manpp(pacmac c12) +{ + + return(mepp(c12)); +} + +void +defcomline(pacmac c12) +{ + int c1, c2; + + frommac(c12, c1, c2); + if (msflag && mac == MM && c2 == 'L') { + if (disp || c1 == 'R') { + noblock('L', 'E'); + } else { + SKIP; + putchar('.'); + } + } + else if (c1 == '.' && c2 == '.') { + if (msflag) { + SKIP; + return; + } + while (C == '.') + /*VOID*/; + } + ++inmacro; + /* + * Process the arguments to the macro + */ + switch (mac) { + default: + case MM: + case MS: + if (c1 <= 'Z' && msflag) + regline(msputmac, ONE); + else + regline(msputmac, TWO); + break; + case ME: + regline(meputmac, ONE); + break; + } + --inmacro; +} + +void +comline(void) +{ + int c1; + int c2; + pacmac c12; + int mid; + int lb, ub; + int hit; + static int tabsize = 0; + static struct mactab *mactab = NULL; + struct mactab *mp; + + if (mactab == 0) + buildtab(&mactab, &tabsize); +com: + while (C == ' ' || c == '\t') + ; +comx: + if ((c1 = c) == '\n') + return; + c2 = C; + if (c1 == '.' && c2 != '.') + inmacro = NO; + if (msflag && c1 == '[') { + refer(c2); + return; + } + if (parag && mac==MM && c1 == 'P' && c2 == '\n') { + printf(".P\n"); + return; + } + if (c2 == '\n') + return; + /* + * Single letter macro + */ + if (mac == ME && (c2 == ' ' || c2 == '\t') ) + c2 = ' '; + c12 = tomac(c1, c2); + /* + * binary search through the table of macros + */ + lb = 0; + ub = tabsize - 1; + while (lb <= ub) { + mid = (ub + lb) / 2; + mp = &mactab[mid]; + if (mp->macname < c12) + lb = mid + 1; + else if (mp->macname > c12) + ub = mid - 1; + else { + hit = 1; +#ifdef FULLDEBUG + printf("preliminary hit macro %c%c ", c1, c2); +#endif /* FULLDEBUG */ + switch (mp->condition) { + case NONE: + hit = YES; + break; + case FNEST: + hit = (filesp == files); + break; + case NOMAC: + hit = !inmacro; + break; + case MAC: + hit = inmacro; + break; + case PARAG: + hit = parag; + break; + case NBLK: + hit = !keepblock; + break; + default: + hit = 0; + } + + if (hit) { +#ifdef FULLDEBUG + printf("MATCH\n"); +#endif /* FULLDEBUG */ + switch ((*(mp->func))(c12)) { + default: + return; + case COMX: + goto comx; + case COM: + goto com; + } + } +#ifdef FULLDEBUG + printf("FAIL\n"); +#endif /* FULLDEBUG */ + break; + } + } + defcomline(c12); +} + +int +macsort(const void *p1, const void *p2) +{ + struct mactab *t1 = (struct mactab *)p1; + struct mactab *t2 = (struct mactab *)p2; + + return(t1->macname - t2->macname); +} + +int +sizetab(struct mactab *mp) +{ + int i; + + i = 0; + if (mp) { + for (; mp->macname; mp++, i++) + /*VOID*/ ; + } + return(i); +} + +struct mactab * +macfill(struct mactab *dst, struct mactab *src) +{ + + if (src) { + while (src->macname) + *dst++ = *src++; + } + return(dst); +} + +void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-ikpw] [-m a | e | l | m | s] [file ...]\n", __progname); + exit(1); +} + +void +buildtab(struct mactab **r_back, int *r_size) +{ + int size; + struct mactab *p, *p1, *p2; + struct mactab *back; + + size = sizetab(troffmactab) + sizetab(ppmactab); + p1 = p2 = NULL; + if (msflag) { + switch (mac) { + case ME: + p1 = memactab; + break; + case MM: + p1 = msmactab; + p2 = mmmactab; + break; + case MS: + p1 = msmactab; + break; + case MA: + p1 = manmactab; + break; + default: + break; + } + } + size += sizetab(p1); + size += sizetab(p2); + back = calloc(size+2, sizeof(struct mactab)); + if (back == NULL) + err(1, NULL); + + p = macfill(back, troffmactab); + p = macfill(p, ppmactab); + p = macfill(p, p1); + p = macfill(p, p2); + + qsort(back, size, sizeof(struct mactab), macsort); + *r_size = size; + *r_back = back; +} + +/* + * troff commands + */ +struct mactab troffmactab[] = { + M(NONE, '\\','"', skip), /* comment */ + M(NOMAC, 'd','e', domacro), /* define */ + M(NOMAC, 'i','g', domacro), /* ignore till .. */ + M(NOMAC, 'a','m', domacro), /* append macro */ + M(NBLK, 'n','f', nf), /* filled */ + M(NBLK, 'c','e', ce), /* centered */ + + M(NONE, 's','o', so), /* source a file */ + M(NONE, 'n','x', nx), /* go to next file */ + + M(NONE, 't','m', skip), /* print string on tty */ + M(NONE, 'h','w', skip), /* exception hyphen words */ + M(NONE, 0,0, 0) +}; + +/* + * Preprocessor output + */ +struct mactab ppmactab[] = { + M(FNEST, 'E','Q', EQ), /* equation starting */ + M(FNEST, 'T','S', intbl), /* table starting */ + M(FNEST, 'T','C', intbl), /* alternative table? */ + M(FNEST, 'T','&', intbl), /* table reformatting */ + M(NONE, 'T','E', outtbl),/* table ending */ + M(NONE, 'P','S', PS), /* picture starting */ + M(NONE, 0,0, 0) +}; + +/* + * Particular to ms and mm + */ +struct mactab msmactab[] = { + M(NONE, 'T','L', skiptocom), /* title follows */ + M(NONE, 'F','S', skiptocom), /* start footnote */ + M(NONE, 'O','K', skiptocom), /* Other kws */ + + M(NONE, 'N','R', skip), /* undocumented */ + M(NONE, 'N','D', skip), /* use supplied date */ + + M(PARAG, 'P','P', PP), /* begin parag */ + M(PARAG, 'I','P', PP), /* begin indent parag, tag x */ + M(PARAG, 'L','P', PP), /* left blocked parag */ + + M(NONE, 'A','U', AU), /* author */ + M(NONE, 'A','I', AU), /* authors institution */ + + M(NONE, 'S','H', SH), /* section heading */ + M(NONE, 'S','N', SH), /* undocumented */ + M(NONE, 'U','X', UX), /* unix */ + + M(NBLK, 'D','S', mssnblock), /* start display text */ + M(NBLK, 'K','S', mssnblock), /* start keep */ + M(NBLK, 'K','F', mssnblock), /* start float keep */ + M(NONE, 0,0, 0) +}; + +struct mactab mmmactab[] = { + M(NONE, 'H',' ', MMHU), /* -mm ? */ + M(NONE, 'H','U', MMHU), /* -mm ? */ + M(PARAG, 'P',' ', PP), /* paragraph for -mm */ + M(NBLK, 'N','S', mssnblock), /* undocumented */ + M(NONE, 0,0, 0) +}; + +struct mactab memactab[] = { + M(PARAG, 'p','p', mepp), + M(PARAG, 'l','p', mepp), + M(PARAG, 'n','p', mepp), + M(NONE, 'i','p', meip), + + M(NONE, 's','h', mesh), + M(NONE, 'u','h', mesh), + + M(NBLK, '(','l', mesnblock), + M(NBLK, '(','q', mesnblock), + M(NBLK, '(','b', mesnblock), + M(NBLK, '(','z', mesnblock), + M(NBLK, '(','c', mesnblock), + + M(NBLK, '(','d', mesnblock), + M(NBLK, '(','f', mesnblock), + M(NBLK, '(','x', mesnblock), + + M(NONE, 'r',' ', mefont), + M(NONE, 'i',' ', mefont), + M(NONE, 'b',' ', mefont), + M(NONE, 'u',' ', mefont), + M(NONE, 'q',' ', mefont), + M(NONE, 'r','b', mefont), + M(NONE, 'b','i', mefont), + M(NONE, 'b','x', mefont), + M(NONE, 0,0, 0) +}; + +struct mactab manmactab[] = { + M(PARAG, 'B','I', manfont), + M(PARAG, 'B','R', manfont), + M(PARAG, 'I','B', manfont), + M(PARAG, 'I','R', manfont), + M(PARAG, 'R','B', manfont), + M(PARAG, 'R','I', manfont), + + M(PARAG, 'P','P', manpp), + M(PARAG, 'L','P', manpp), + M(PARAG, 'H','P', manpp), + M(NONE, 0,0, 0) +}; diff --git a/usr.bin/spell/Makefile b/usr.bin/spell/Makefile new file mode 100644 --- /dev/null +++ b/usr.bin/spell/Makefile @@ -0,0 +1,25 @@ +# $OpenBSD: Makefile,v 1.2 2002/03/02 16:20:33 millert Exp $ + +PROG= spellprog +MAN= spell.1 +SRCS= spellprog.c look.c +BINDIR= /usr/libexec + +afterinstall: + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/spell.sh ${DESTDIR}/usr/bin/spell + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${NONBINMODE} \ + ${.CURDIR}/stop ${DESTDIR}/usr/share/dict + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${NONBINMODE} \ + ${.CURDIR}/american ${DESTDIR}/usr/share/dict + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${NONBINMODE} \ + ${.CURDIR}/british ${DESTDIR}/usr/share/dict + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${NONBINMODE} \ + ${.CURDIR}/special.4bsd ${DESTDIR}/usr/share/dict/special/4bsd + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${NONBINMODE} \ + ${.CURDIR}/special.math ${DESTDIR}/usr/share/dict/special/math + +.include + +CFLAGS+= -Wno-missing-field-initializers -Wno-incompatible-pointer-types-discards-qualifiers +CFLAGS+= -Wno-missing-variable-declarations -Wno-unused-parameter -Wno-sign-compare diff --git a/usr.bin/spell/american b/usr.bin/spell/american new file mode 100644 --- /dev/null +++ b/usr.bin/spell/american @@ -0,0 +1,353 @@ +acknowledgment +aggrandize +aluminize +aluminum +amor +amorous +amphitheater +analog +analyze +anemia +anemic +anesthesia +anesthetic +anesthetize +anglicize +antagonize +apologize +appareled +appareling +appetize +arbor +archeology +Archeopteryx +ardor +arithmetize +armor +armory +axiomatize +baptize +barreled +barreling +behavior +behavioral +behoove +belabor +beveled +beveler +beveling +canceled +canceler +canceling +candor +carburetor +catalog +catalyze +catechize +categorize +cauterize +center +centimeter +channeled +channeler +channeling +chiseled +chiseler +chiseling +clamor +clamorous +clangor +cognizant +cognize +color +colorable +colorful +corbeled +corbeling +counseled +counseling +crystallize +cudgeled +cudgeler +cudgeling +decentralize +decolonize +decriminalize +defense +dehumanize +deionize +demagnetize +demeanor +demineralize +demoralize +demythologize +depersonalize +depolarize +desensitize +destabilize +desynchronize +detribalize +dialog +dialyze +diarrhea +dichotomize +discolor +disemboweled +disemboweling +disfavor +disheveled +disheveler +disheveling +dishonor +dishonorable +disorganize +doweled +doweler +doweling +dramatize +dueled +dueler +dueling +duelist +economize +ecumenical +edema +emphasize +enameled +enameling +enamor +encyclopedia +endeavor +energize +eon +epicenter +epilog +esophagus +esthetic +eulogize +favor +favorable +favorite +fervor +fiber +flavor +fraternize +fueled +fueler +fueling +funneled +funneler +funneling +furor +galvanize +gaveled +gaveler +gaveling +glamorize +gram +graveled +graveling +gray +graybeard +graywacke +groveled +groveler +groveling +gynecology +harbor +harmonize +hemoglobin +hemolytic +hemophilia +hemophiliac +hemorrhage +hemorrhoid +hemosiderin +hiccup +hiccupped +hiccupping +homeopathy +homogenize +homolog +honor +honorable +humor +hydrolyze +hypnotize +hypostatize +hypothesize +jail +jeweled +jeweler +jeweling +judgment +kilogram +kinesthesis +kinesthetic +labeled +labeler +labeling +labor +laborite +legitimize +leukemia +leveled +leveler +leveling +libeled +libeler +libeling +license +liter +logorrhea +louver +luster +marveled +marveler +marveling +mechanize +medieval +memorize +mesmerize +metallize +milligram +milliliter +millimeter +modeled +modeler +modeling +nanogram +nanometer +naught +neighbor +neighborhood +notarize +ocher +odor +offense +optimize +orientation +ostracize +pajama +paleontology +pallor +paneled +paneling +paralleled +paralleling +paralyze +parametrize +parceled +parceler +parceling +parenthesize +parlor +pasteurize +peptize +photolyze +photosynthesize +picogram +plagiarize +platinize +program +prolog +proselytize +psychoanalyze +pulverize +pummeled +pummeler +pummeling +pyorrhea +pyrolyze +quantize +quarreled +quarreler +quarreling +radiosterilize +rancor +raveled +raveler +raveling +realize +recognize +reconnoiter +reveled +reveler +reveling +rigor +rumor +saber +saltpeter +savior +savor +savory +scepter +schematize +scrutinize +sensitize +sepulcher +shoveled +shoveler +shoveling +shriveled +shriveling +siphon +sniveled +sniveler +sniveling +soliloquize +specialty +specter +spirochete +splendor +squirreled +squirreling +stigmatize +succor +summarize +swiveled +swiveling +symmetrize +sympathize +synchronize +synthesize +systematize +tantalize +tasseled +tasseling +temporize +theater +theatergoer +theatergoing +theorize +tinseled +tinseling +titer +topologize +toweled +toweling +trammeled +traumatize +traveled +traveler +traveling +travelog +tricolor +tumor +tunneled +tunneler +tunneling +tyrannize +valor +vapor +varicolored +vigor +vulcanize +wagon +watercolor +weaseled +weaseling +whiskey +woolen +yodeled +yodeling diff --git a/usr.bin/spell/british b/usr.bin/spell/british new file mode 100644 --- /dev/null +++ b/usr.bin/spell/british @@ -0,0 +1,353 @@ +aeon +aerodrome +aeroplane +aggrandise +alarum +aluminise +aluminium +amour +amourous +amphitheatre +anaemia +anaemic +anaesthesia +anaesthetic +anaesthetise +analyse +anglicise +antagonise +apologise +apparelled +apparelling +appetise +arbour +archaeology +Archaeopteryx +ardour +arithmetise +armour +armoury +axiomatise +baptise +barrelled +barrelling +behaviour +behavioural +behove +belabour +bevelled +beveller +bevelling +cancelled +canceller +cancelling +candour +carburettor +catalyse +catechise +categorise +cauterise +centimetre +centre +channelled +channeller +channelling +cheque +chiselled +chiseller +chiselling +clamour +clamourous +clangour +clew +cognisant +cognise +colour +colourable +colourful +connexion +corbelled +corbelling +counselled +counselling +crystallise +cudgelled +cudgeller +cudgelling +decentralise +decolonise +decriminalise +defence +deflexion +dehumanise +deionise +demagnetise +demeanour +demineralise +demoralise +demythologise +depersonalise +depolarise +desensitise +destabilise +desynchronise +detribalise +dialyse +diarrhoea +dichotomise +discolour +disembowelled +disembowelling +disfavour +dishevelled +disheveller +dishevelling +dishonour +dishonourable +disorganise +dowelled +doweller +dowelling +dramatise +duelled +dueller +duelling +duellist +economise +emphasise +enamelled +enamelling +enamour +encyclopaedia +endeavour +energise +epicentre +eulogise +favour +favourable +favourite +fervour +fibre +flavour +fraternise +fuelled +fueller +fuelling +funnelled +funneller +funnelling +furore +fuze +galvanise +gaol +gavelled +gaveller +gavelling +glamourise +gramme +gravelled +gravelling +greybeard +greywacke +grovelled +groveller +grovelling +gynaecology +haemoglobin +haemolytic +haemophilia +haemophiliac +haemorrhage +haemorrhoid +haemosiderin +harbour +harmonise +hiccough +homoeopathy +homogenise +honour +honourable +humour +hydrolyse +hypnotise +hypostatise +hypothesise +inflexion +jewelled +jeweller +jewelling +kilogramme +kinaesthesis +kinaesthetic +labelled +labeller +labelling +labour +labourite +legitimise +leukaemia +levelled +leveller +levelling +libelled +libeller +libelling +licence +litre +logorrhoea +louvre +lustre +marvelled +marveller +marvelling +mechanise +mediaeval +memorise +mesmerise +metallise +metre +milligramme +millilitre +millimetre +modelled +modeller +modelling +nanogramme +nanometre +neighbour +neighbourhood +notarise +ochre +odour +oecumenical +oedema +oesophagus +offence +optimise +orientate +ostracise +pallour +panelled +panelling +parallelled +parallelling +paralyse +parametrise +parcelled +parceller +parcelling +parenthesise +parlour +pasteurise +peptise +photolyse +photosynthesise +picogramme +plagiarise +platinise +practise +programme +proselytise +psychoanalyse +pulverise +pummelled +pummeller +pummelling +pyjama +pyorrhoea +pyrolyse +quantise +quarrelled +quarreller +quarrelling +radiosterilise +rancour +ravelled +raveller +ravelling +realise +recognise +reconnoitre +reflexion +revelled +reveller +revelling +rigour +rumour +sabre +saltpetre +saviour +savour +savoury +sceptre +schematise +scrutinise +sensitise +sepulchre +shew +shovelled +shoveller +shovelling +shrivelled +shrivelling +snivelled +sniveller +snivelling +soliloquise +speciality +spectre +splendour +squirrelled +squirrelling +stigmatise +succour +summarise +swede +swivelled +swivelling +symmetrise +sympathise +synchronise +synthesise +syphon +systematise +tantalise +tasselled +tasselling +temporise +theatre +theatregoer +theatregoing +theorise +tinselled +tinselling +titre +topologise +towelled +towelling +trammelled +traumatise +travelled +traveller +travelling +tricolour +tumour +tunnelled +tunneller +tunnelling +tyrannise +tyre +valour +vapour +varicoloured +vigour +vulcanise +waggon +watercolour +weaselled +weaselling +whilst +whisky +woollen +yodelled +yodelling diff --git a/usr.bin/spell/look.c b/usr.bin/spell/look.c new file mode 100644 --- /dev/null +++ b/usr.bin/spell/look.c @@ -0,0 +1,172 @@ +/* $OpenBSD: look.c,v 1.7 2016/09/13 15:29:25 millert Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * David Hitz of Auspex Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +u_char *binary_search(u_char *, u_char *, u_char *); +u_char *linear_search(u_char *, u_char *, u_char *); +int compare(u_char *, u_char *, u_char *); +int look(u_char *, u_char *, u_char *); + +int +look(u_char *string, u_char *front, u_char *back) +{ + u_char *s; + + /* Convert string to lower case before searching. */ + for (s = string; *s; s++) { + if (isupper(*s)) + *s = tolower(*s); + } + + front = binary_search(string, front, back); + front = linear_search(string, front, back); + + return (front != NULL); +} + +/* + * Binary search for "string" in memory between "front" and "back". + * + * This routine is expected to return a pointer to the start of a line at + * *or before* the first word matching "string". Relaxing the constraint + * this way simplifies the algorithm. + * + * Invariants: + * front points to the beginning of a line at or before the first + * matching string. + * + * back points to the beginning of a line at or after the first + * matching line. + * + * Base of the Invariants. + * front = NULL; + * back = EOF; + * + * Advancing the Invariants: + * + * p = first newline after halfway point from front to back. + * + * If the string at "p" is not greater than the string to match, + * p is the new front. Otherwise it is the new back. + * + * Termination: + * + * The definition of the routine allows it return at any point, + * since front is always at or before the line to print. + * + * In fact, it returns when the chosen "p" equals "back". This + * implies that there exists a string is least half as long as + * (back - front), which in turn implies that a linear search will + * be no more expensive than the cost of simply printing a string or two. + * + * Trying to continue with binary search at this point would be + * more trouble than it's worth. + */ +#define SKIP_PAST_NEWLINE(p, back) \ + while (p < back && *p++ != '\n'); + +u_char * +binary_search(u_char *string, u_char *front, u_char *back) +{ + u_char *p; + + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + + /* + * If the file changes underneath us, make sure we don't + * infinitely loop. + */ + while (p < back && back > front) { + if (compare(string, p, back) > 0) + front = p; + else + back = p; + p = front + (back - front) / 2; + SKIP_PAST_NEWLINE(p, back); + } + return (front); +} + +/* + * Find the first line that matches string, linearly searching from front + * to back. + * + * Return NULL for no such line. + * + * This routine assumes: + * + * o front points at the first character in a line. + * o front is before or at the first line to be printed. + */ +u_char * +linear_search(u_char *string, u_char *front, u_char *back) +{ + int result; + + while (front < back) { + result = compare(string, front, back); + if (result == 0) + return (front); /* found it */ + if (result < 0) + return (NULL); /* not there */ + + SKIP_PAST_NEWLINE(front, back); + } + return (NULL); +} + +int +compare(u_char *s1, u_char *s2, u_char *back) +{ + int ch; + + /* Note that s1 is already upper case. */ + for (;; ++s1, ++s2) { + if (*s2 == '\n' || s2 == back) + ch = '\0'; + else + ch = tolower(*s2); + if (*s1 != ch) + return (*s1 - ch); + if (ch == '\0') + return (0); + } +} diff --git a/usr.bin/spell/special.4bsd b/usr.bin/spell/special.4bsd new file mode 100644 --- /dev/null +++ b/usr.bin/spell/special.4bsd @@ -0,0 +1 @@ +openbsd diff --git a/usr.bin/spell/special.math b/usr.bin/spell/special.math new file mode 100644 --- /dev/null +++ b/usr.bin/spell/special.math @@ -0,0 +1,248 @@ +Ab +abelian +Abhyankar +adele +adic +a.e +Aequationes +Alaoglu +Amitsur +A.M.S +AMS +Apostol +Arcata +artin +artinian +ary +Arzela +Ascoli +Atiyah +Auslander +automorphic +Azumaya +Baer +Baire +barycenter +Beltrami +bialgebra +bicommutant +bicontinuous +bifunctor +biinvariant +bimodule +Birkhauser +Birkhoff +bivariant +Bolyai +Borel +Bott +Brouwer +Brouwerian +Bures +Cartan +cartesian +Cartier +Chern +Chevalley +Choleski +Civita +Clebsch +clopen +coaction +coaddition +coalgebra +coassociative +cobordant +cobordism +cochain +cocommutative +cocomplete +coderivative +codiagonal +codimension +cofinal +cofinite +cogenerate +cogroup +cohomotopy +coideal +coidentity +coimage +coinfinite +coinverse +cokernel +colimit +comaximal +commutant +comodule +Comp +complexify +componentwise +composable +composita +compositum +comultiplication +contractible +copower +coprime +coprojection +coreflective +cosemigroup +counit +counital +Courant +Coxeter +Dedekind +Dekker +DeRham +determinantal +Dieudonne +Doklady +Dordrecht +eigenring +Eilenberg +epimorph +epimorphic +equicontinuity +equicontinuous +equivariant +Erdos +Esztergom +Fary +Feferman +Feynman +finitary +Formanek +Fraenkel +Frechet +Freyd +Frobenius +Fubini +Fundamenta +Gel'fand +GL +Goldie +Golod +Grothendieck +Halmos +Hensel +Herstein +Hironaka +Hochschild +Hochster +holomorphic +homotopic +Hopf +Hurewicz +IAS +idele +IHES +indiscrete +infinitary +involutive +Jategaonkar +Jonsson +Kac +Kaehler +Kan +Kaplansky +Kato +Kesthely +Kirillov +Kishinev +Knuth +Kolmogorov +Kostant +Krein +Krull +Kurosh +Kutta +Lawvere +Lefschetz +Levitzki +Liouville +Mal'cev +Martindale +Mathematicae +Mazur +meromorphic +metabelian +metaplectic +Milman +Milnor +mod +monodromy +monoidal +monomorphic +Morita +MOS +MSRI +nabla +Nagata +Nikodym +Noether +noetherian +nullstellensatz +Oberwolfach +Passman +pathwise +Plancherel +plethysm +Pontrjagin +prenex +Procesi +profinite +Prufer +PSL +PSU +quasiinverse +quasiinvertible +quasimultiplication +quasivariety +quaternion +quaternionic +Reidel +riemannian +Sard +Seidenberg +Seifert +Serre +sesquilinear +Sethian +sfield +Shafarevich +Shelah +simplices +SL +Sobolev +socle +Spivak +Steenrod +Steinitz +Stiefel +straightedge +tensorial +Thurston +Tietze +torsionfree +trinomial +tripleable +Tychonoff +ultrafiltral +umbral +unimodular +Urysohn +Vandermonde +Varadarajan +Verma +Waerden +Weil +Weyl +w.r.t +Yoneda +Zariski +Zassenhaus +Zermelo +zeroary +ZF +ZFC diff --git a/usr.bin/spell/spell.1 b/usr.bin/spell/spell.1 new file mode 100644 --- /dev/null +++ b/usr.bin/spell/spell.1 @@ -0,0 +1,253 @@ +.\" $OpenBSD: spell.1,v 1.16 2022/08/03 07:43:45 jsg Exp $ +.\" +.\" Copyright (C) 1985, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Copyright (C) Caldera International Inc. 2001-2002. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code and documentation must retain the above +.\" copyright notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed or owned by Caldera +.\" International, Inc. +.\" 4. Neither the name of Caldera International, Inc. nor the names of other +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA +.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, +.\" INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" @(#)spell.1 8.2 (Berkeley) 4/18/94 +.\" +.Dd February 25 2023 +.Dt SPELL 1 +.Os +.Sh NAME +.Nm spell +.Nd find spelling errors +.Sh SYNOPSIS +.Nm spell +.Op Fl biltvx +.Op Fl d Ar list +.Op Fl h Ar spellhist +.Oo +.Fl m +.Ar a | e | l | m | s +.Oc +.Op Fl s Ar list +.Op + Ns Ar extra_list +.Op Ar +.Sh DESCRIPTION +.Nm spell +collects words from the named documents and looks them up in a spelling list. +Words that neither occur among nor are derivable (by applying certain +inflections, prefixes or suffixes) from words in the spelling list +are printed on the standard output. +.Pp +If no files are named, words are collected from the standard input. +.Nm +ignores most troff, tbl, eqn, and pic constructions. +Copies of all output may be accumulated in the history file, +if one is specified. +.Pp +By default, +.Nm +(like +.Xr deroff 1 ) +follows chains of included files +.Po +.Dq .so +and +.Dq .nx +commands +.Pc . +.Pp +The default spelling list is based on Webster's Second International +dictionary and should be fairly complete. +Words that appear in the +.Dq stop list +are immediately flagged as misspellings, regardless of whether or not +they exist in one of the word lists. +This helps filter out misspellings (e.g. thier=thy\-y+ier) +that would otherwise pass. +Additionally, the +.Pa british +file is also used as a stop list unless the +.Fl b +option is specified. +.Pp +Site administrators may add words to the local word list, +.Pa /usr/local/share/dict/words +or the local stop list, +.Pa /usr/local/share/dict/stop . +.Pp +All word (and stop) lists must be sorted in lexicographical order +with case folded. +The simplest way to achieve this is to use +.Dq sort -df . +If the word files are incorrectly sorted, +.Nm +will not be able to operate correctly. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl b +Check British spelling. +Besides preferring +.Em centre , colour , speciality , travelled , +etc., this option insists upon +.Fl ise +in words like +.Em standardise , +Fowler and the OED to the contrary notwithstanding. +In this mode, American variants of words are added to the stop list. +.It Fl d Ar list +Use the specified word list instead of the default system word list. +The word list must be sorted as specified above. +.It Fl h Ar spellhist +Store misspelled words in the specified history file. +The output of +.Li who -m +is appended to the history file after the list of misspelled words. +.It Fl i +Instruct +.Xr deroff 1 +to ignore +.Dq .so +and +.Dq .nx +commands. +.It Fl l +Use +.Sy delatex +instead of +.Xr deroff 1 +if it is present on the system. +.It Fl m +Enable support for common +troff macro packages; this option is passed verbatim to +.Xr deroff 1 . +Refer to the +.Fl m +description in +.Xr deroff 1 +for details. +.It Fl s Ar list +Use the specified stop list instead of the default system stop list. +The stop list must be sorted as specified above. +.It Fl t +Use +.Sy detex +instead of +.Xr deroff 1 +if it is present on the system. +.It Fl v +Print all words not literally in the spelling list in addition to +plausible derivations from spelling list words. +.It Fl x +Print every plausible stem, prefixed with +.Sq = . +.It + Ns Ar extra_list +Use +.Ar extra_list +in addition to the default word list. +The extra word list must be sorted as specified above. +.El +.Sh FILES +.Bl -tag -width /usr/local/share/dict/wordsxx -compact +.It Pa /usr/share/dict/words +Default spelling list. +.It Pa /usr/share/dict/american +American spelling of certain words. +.It Pa /usr/share/dict/british +British spelling of certain words. +.It Pa /usr/share/dict/stop +Default stop list. +.It Pa /usr/local/share/dict/words +Local spelling list (optional). +.It Pa /usr/local/share/dict/stop +Local stop list (optional). +.It Pa /usr/libexec/spellprog +Binary executed by the shell script +.Pa /usr/bin/spell . +.El +.Sh SEE ALSO +.Xr deroff 1 , +.Xr look 1 , +.Xr sed 1 , +.Xr sort 1 , +.Xr tee 1 +.Sh HISTORY +The +.Nm spell +command first appeared in +.At v5 . +It did not appear in freely redistributable +.Bx +releases for licensing reasons. +After Caldera relicensed early UNIX releases the +.Bx 4.4 +version was added to +.Ox 3.1 +and later +to +.Fx 14 . +.Pp +Unlike historic versions, the +.Fx +.Nm +command does not use hashed word files. +Instead, it uses lexicographically sorted files and the same technique as +.Xr look 1 . +.Sh BUGS +The spelling list lacks many technical terms; new installations will +probably wish to monitor the output for several months to gather local +additions. +.Pp +British spelling was done by an American. +.Pp +In +.Fl x +mode it would be nicer if the stems were grouped with the appropriate word. diff --git a/usr.bin/spell/spell.ksh b/usr.bin/spell/spell.ksh new file mode 100644 --- /dev/null +++ b/usr.bin/spell/spell.ksh @@ -0,0 +1,120 @@ +#!/bin/ksh - +# +# $OpenBSD: spell.ksh,v 1.12 2019/01/25 00:19:26 millert Exp $ +# +# Copyright (c) 2001, 2003 Todd C. Miller +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Sponsored in part by the Defense Advanced Research Projects +# Agency (DARPA) and Air Force Research Laboratory, Air Force +# Materiel Command, USAF, under agreement number F39502-99-1-0512. +# +SPELLPROG=/usr/libexec/spellprog +DICT=/usr/share/dict/words +LOCAL_DICT=/usr/local/share/dict/words +STOP=/usr/share/dict/stop +LOCAL_STOP=/usr/local/share/dict/stop +AMERICAN=/usr/share/dict/american +BRITISH=/usr/share/dict/british +LANG=$AMERICAN +STOP_LANG=$BRITISH +EXTRA= +FLAGS= +DEROFF="deroff -w" +HISTFILE= +TMP=`mktemp /tmp/spell.XXXXXXXX` || exit 1 +VTMP= +USAGE="usage: spell [-biltvx] [-d list] [-h spellhist] [-m a | e | l | m | s]\n\t[-s list] [+extra_list] [file ...]" + +set -o posix # set POSIX mode to prevent +foo in getopts +OPTIND=1 # force getopts to reset itself + +trap "rm -f $TMP $VTMP; exit 0" 0 1 2 15 + +# Use local word/stop lists if they exist +if [ -f $LOCAL_DICT ]; then + DICT="$DICT $LOCAL_DICT" +fi +if [ -f $LOCAL_STOP ]; then + STOP="$STOP $LOCAL_STOP" +fi + +while getopts "biltvxd:h:m:s:" c; do + case $c in + b) LANG=$BRITISH + STOP_LANG=$AMERICAN + FLAGS[${#FLAGS[@]}]="-b" + ;; + i) DEROFF="$DEROFF -i" + ;; + l) DEROFF="delatex" + ;; + m) DEROFF="$DEROFF -m $OPTARG" + ;; + t) DEROFF="detex -w" + ;; + v) VTMP=`mktemp /tmp/spell.XXXXXXXX` || { + rm -f ${TMP} + exit 1 + } + FLAGS[${#FLAGS[@]}]="-v" + FLAGS[${#FLAGS[@]}]="-o" + FLAGS[${#FLAGS[@]}]="$VTMP" + ;; + x) FLAGS[${#FLAGS[@]}]="-x" + ;; + d) DICT="$OPTARG" + LANG= + ;; + s) STOP="$OPTARG" + STOP_LANG= + LOCAL_STOP= + ;; + h) HISTFILE="$OPTARG" + ;; + *) echo "$USAGE" 1>&2 + exit 1 + ;; + esac +done +shift $(( $OPTIND - 1 )) + +while test $# -ne 0; do + case "$1" in + +*) EXTRA="$EXTRA ${1#+}" + shift + ;; + *) break + ;; + esac +done + +# Any parameters left are files to be checked, pass them to deroff +DEROFF="$DEROFF $@" + +if [ -n "$HISTFILE" ]; then + $DEROFF | sort -u | $SPELLPROG -o $TMP $STOP $STOP_LANG | \ + $SPELLPROG ${FLAGS[*]} $DICT $LANG $EXTRA | sort -u -k1f - $TMP | \ + tee -a $HISTFILE + who -m >> $HISTFILE +else + $DEROFF | sort -u | $SPELLPROG -o $TMP $STOP $STOP_LANG | \ + $SPELLPROG ${FLAGS[*]} $DICT $LANG $EXTRA | sort -u -k1f - $TMP +fi + +if [ -n "$VTMP" ]; then + sort -u -k2f -k1 $VTMP +fi + +exit 0 diff --git a/usr.bin/spell/spell.sh b/usr.bin/spell/spell.sh new file mode 100644 --- /dev/null +++ b/usr.bin/spell/spell.sh @@ -0,0 +1,120 @@ +#!/bin/sh +# +# $NetBSD: spell.sh,v 1.2 2005/07/06 08:01:13 wiz Exp $ +# +# Taken from: +# OpenBSD: spell.ksh,v 1.8 2004/02/02 22:36:50 fgsch Exp +# +# Converted to sh from ksh by Perry E. Metzger +# +# Copyright (c) 2001, 2003 Todd C. Miller +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Sponsored in part by the Defense Advanced Research Projects +# Agency (DARPA) and Air Force Research Laboratory, Air Force +# Materiel Command, USAF, under agreement number F39502-99-1-0512. +# +SPELLPROG=/usr/libexec/spellprog +DICT=/usr/share/dict/words +LOCAL_DICT=/usr/local/share/dict/words +STOP=/usr/share/dict/stop +LOCAL_STOP=/usr/local/share/dict/stop +AMERICAN=/usr/share/dict/american +BRITISH=/usr/share/dict/british +LANG=$AMERICAN +STOP_LANG=$BRITISH +EXTRA= +FLAGS= +DEROFF="deroff -w" +HISTFILE= +TMP=`mktemp /tmp/spell.XXXXXXXX` || exit 1 +VTMP= +USAGE="usage: spell [-biltvx] [-d list] [-h spellhist] [-m a | e | l | m | s]\n\t[-s stop] [+extra_list] [file ...]" + +trap "rm -f $TMP $VTMP; exit 0" 0 1 2 15 + +# Use local word/stop lists if they exist +if [ -f $LOCAL_DICT ]; then + DICT="$DICT $LOCAL_DICT" +fi +if [ -f $LOCAL_STOP ]; then + STOP="$STOP $LOCAL_STOP" +fi + +while getopts "biltvxd:h:m:s:" c; do + case $c in + b) LANG=$BRITISH + STOP_LANG=$AMERICAN + FLAGS="$FLAGS -b" + ;; + i) DEROFF="$DEROFF -i" + ;; + l) DEROFF="delatex" + ;; + m) DEROFF="$DEROFF -m $OPTARG" + ;; + t) DEROFF="detex" + ;; + v) VTMP=`mktemp /tmp/spell.XXXXXXXX` || { + rm -f $TMP + exit 1 + } + FLAGS="$FLAGS -v -o $VTMP" + ;; + x) FLAGS="$FLAGS -x" + ;; + d) DICT="$OPTARG" + LANG= + ;; + s) STOP="$OPTARG" + STOP_LANG= + LOCAL_STOP= + ;; + h) HISTFILE="$OPTARG" + ;; + *) echo "$USAGE" 1>&2 + exit 1 + ;; + esac +done +shift $(( $OPTIND - 1 )) + +while test $# -ne 0; do + case "$1" in + +*) EXTRA="$EXTRA ${1#+}" + shift + ;; + *) break + ;; + esac +done + +# Any parameters left are files to be checked, pass them to deroff +DEROFF="$DEROFF $@" + +if [ -n "$HISTFILE" ]; then + $DEROFF | sort -u | $SPELLPROG -o $TMP $STOP $STOP_LANG | \ + $SPELLPROG $FLAGS $DICT $LANG $EXTRA | sort -u -k1f - $TMP | \ + tee -a $HISTFILE + who -m >> $HISTFILE +else + $DEROFF | sort -u | $SPELLPROG -o $TMP $STOP $STOP_LANG | \ + $SPELLPROG $FLAGS $DICT $LANG $EXTRA | sort -u -k1f - $TMP +fi + +if [ -n "$VTMP" ]; then + sort -u -k2f -k1 $VTMP +fi + +exit 0 diff --git a/usr.bin/spell/spellprog.c b/usr.bin/spell/spellprog.c new file mode 100644 --- /dev/null +++ b/usr.bin/spell/spellprog.c @@ -0,0 +1,793 @@ +/* $OpenBSD: spellprog.c,v 1.16 2022/12/26 19:16:03 jmc Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)spell.h 8.1 (Berkeley) 6/6/93 + */ +/* + * Copyright (C) Caldera International Inc. 2001-2002. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * 4. Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, + * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DLEV 2 + +int an(char *, char *, char *, int); +int bility(char *, char *, char *, int); +int es(char *, char *, char *, int); +int dict(char *, char *); +int i_to_y(char *, char *, char *, int); +int ily(char *, char *, char *, int); +int ize(char *, char *, char *, int); +int metry(char *, char *, char *, int); +int monosyl(char *, char *); +int ncy(char *, char *, char *, int); +int nop(char *, char *, char *, int); +int trypref(char *, char *, int); +int tryword(char *, char *, int); +int s(char *, char *, char *, int); +int strip(char *, char *, char *, int); +int suffix(char *, int); +int tion(char *, char *, char *, int); +int vowel(unsigned char); +int y_to_e(char *, char *, char *, int); +int CCe(char *, char *, char *, int); +int VCe(char *, char *, char *, int); +char *lookuppref(char **, char *); +char *skipv(char *); +char *estrdup(const char *); +void ise(void); +void print_word(FILE *); +void ztos(char *); +static void usage(void); + +/* from look.c */ +int look(unsigned char *, unsigned char *, unsigned char *); + +struct suftab { + const char *suf; + int (*p1)(char *, char *, char *, int); + int n1; + const char *d1; + const char *a1; + int (*p2)(char *, char *, char *, int); + int n2; + const char *d2; + const char *a2; +} suftab[] = { + {"ssen", ily, 4, "-y+iness", "+ness" }, + {"ssel", ily, 4, "-y+i+less", "+less" }, + {"se", s, 1, "", "+s", es, 2, "-y+ies", "+es" }, + {"s'", s, 2, "", "+'s"}, + {"s", s, 1, "", "+s"}, + {"ecn", ncy, 1, "", "-t+ce"}, + {"ycn", ncy, 1, "", "-cy+t"}, + {"ytilb", nop, 0, "", ""}, + {"ytilib", bility, 5, "-le+ility", ""}, + {"elbaif", i_to_y, 4, "-y+iable", ""}, + {"elba", CCe, 4, "-e+able", "+able"}, + {"yti", CCe, 3, "-e+ity", "+ity"}, + {"ylb", y_to_e, 1, "-e+y", ""}, + {"yl", ily, 2, "-y+ily", "+ly"}, + {"laci", strip, 2, "", "+al"}, + {"latnem", strip, 2, "", "+al"}, + {"lanoi", strip, 2, "", "+al"}, + {"tnem", strip, 4, "", "+ment"}, + {"gni", CCe, 3, "-e+ing", "+ing"}, + {"reta", nop, 0, "", ""}, + {"re", strip, 1, "", "+r", i_to_y, 2, "-y+ier", "+er"}, + {"de", strip, 1, "", "+d", i_to_y, 2, "-y+ied", "+ed"}, + {"citsi", strip, 2, "", "+ic"}, + {"cihparg", i_to_y, 1, "-y+ic", ""}, + {"tse", strip, 2, "", "+st", i_to_y, 3, "-y+iest", "+est"}, + {"cirtem", i_to_y, 1, "-y+ic", ""}, + {"yrtem", metry, 0, "-ry+er", ""}, + {"cigol", i_to_y, 1, "-y+ic", ""}, + {"tsigol", i_to_y, 2, "-y+ist", ""}, + {"tsi", VCe, 3, "-e+ist", "+ist"}, + {"msi", VCe, 3, "-e+ism", "+ist"}, + {"noitacif", i_to_y, 6, "-y+ication", ""}, + {"noitazi", ize, 5, "-e+ation", ""}, + {"rota", tion, 2, "-e+or", ""}, + {"noit", tion, 3, "-e+ion", "+ion"}, + {"naino", an, 3, "", "+ian"}, + {"na", an, 1, "", "+n"}, + {"evit", tion, 3, "-e+ive", "+ive"}, + {"ezi", CCe, 3, "-e+ize", "+ize"}, + {"pihs", strip, 4, "", "+ship"}, + {"dooh", ily, 4, "-y+hood", "+hood"}, + {"ekil", strip, 4, "", "+like"}, + { NULL } +}; + +char *preftab[] = { + "anti", + "bio", + "dis", + "electro", + "en", + "fore", + "hyper", + "intra", + "inter", + "iso", + "kilo", + "magneto", + "meta", + "micro", + "milli", + "mis", + "mono", + "multi", + "non", + "out", + "over", + "photo", + "poly", + "pre", + "pseudo", + "re", + "semi", + "stereo", + "sub", + "super", + "thermo", + "ultra", + "under", /* must precede un */ + "un", + NULL +}; + +struct wlist { + int fd; + unsigned char *front; + unsigned char *back; +} *wlists; + +int vflag; +int xflag; +char word[LINE_MAX]; +char original[LINE_MAX]; +char *deriv[40]; +char affix[40]; + +/* + * The spellprog utility accepts a newline-delimited list of words + * on stdin. For arguments it expects the path to a word list and + * the path to a file in which to store found words. + * + * In normal usage, spell is called twice. The first time it is + * called with a stop list to flag commonly misspelled words. The + * remaining words are then passed to spell again, this time with + * the dictionary file as the first (non-flag) argument. + * + * Unlike historic versions of spellprog, this one does not use + * hashed files. Instead it simply requires that files be sorted + * lexigraphically and uses the same algorithm as the look utility. + * + * Note that spellprog should be called via the spell shell script + * and is not meant to be invoked directly by the user. + */ + +int +main(int argc, char **argv) +{ + char *ep, *cp, *dp; + char *outfile; + int ch, fold, i; + struct stat sb; + FILE *file, *found; + + outfile = NULL; + while ((ch = getopt(argc, argv, "bvxo:")) != -1) { + switch (ch) { + case 'b': + /* Use British dictionary and convert ize -> ise. */ + ise(); + break; + case 'o': + outfile = optarg; + break; + case 'v': + /* Also write derivations to "found" file. */ + vflag = 1; + break; + case 'x': + /* Print plausible stems to stdout. */ + xflag = 1; + break; + default: + usage(); + } + + } + argc -= optind; + argv += optind; + if (argc < 1) + usage(); + + /* Open and mmap the word/stop lists. */ + if ((wlists = calloc(sizeof(struct wlist), (argc + 1))) == NULL) + err(1, "malloc"); + for (i = 0; argc--; i++) { + wlists[i].fd = open(argv[i], O_RDONLY); + if (wlists[i].fd == -1 || fstat(wlists[i].fd, &sb) != 0) + err(1, "%s", argv[i]); + if (sb.st_size > SIZE_MAX) + errc(1, EFBIG, "%s", argv[i]); + wlists[i].front = mmap(NULL, (size_t)sb.st_size, PROT_READ, + MAP_PRIVATE, wlists[i].fd, (off_t)0); + if (wlists[i].front == MAP_FAILED) + err(1, "%s", argv[i]); + wlists[i].back = wlists[i].front + sb.st_size; + } + wlists[i].fd = -1; + + /* Open file where found words are to be saved. */ + if (outfile == NULL) + found = NULL; + else if ((found = fopen(outfile, "w")) == NULL) + err(1, "cannot open %s", outfile); + + for (;; print_word(file)) { + affix[0] = '\0'; + file = found; + for (ep = word; (*ep = ch = getchar()) != '\n'; ep++) { + if (ep - word == sizeof(word) - 1) { + *ep = '\0'; + warnx("word too long (%s)", word); + while ((ch = getchar()) != '\n') + ; /* slurp until EOL */ + } + if (ch == EOF) { + if (found != NULL) + fclose(found); + return (0); + } + } + for (cp = word, dp = original; cp < ep; ) + *dp++ = *cp++; + *dp = '\0'; + fold = 0; + for (cp = word; cp < ep; cp++) + if (islower((unsigned char)*cp)) + goto lcase; + if (trypref(ep, ".", 0)) + continue; + ++fold; + for (cp = original + 1, dp = word + 1; dp < ep; dp++, cp++) + *dp = tolower((unsigned char)*cp); +lcase: + if (trypref(ep, ".", 0) || suffix(ep, 0)) + continue; + if (isupper((unsigned char)word[0])) { + for (cp = original, dp = word; (*dp = *cp++); dp++) { + if (fold) + *dp = tolower((unsigned char)*dp); + } + word[0] = tolower((unsigned char)word[0]); + goto lcase; + } + file = stdout; + } + + return (0); +} + +void +print_word(FILE *f) +{ + + if (f != NULL) { + if (vflag && affix[0] != '\0' && affix[0] != '.') + fprintf(f, "%s\t%s\n", affix, original); + else + fprintf(f, "%s\n", original); + } +} + +/* + * For each matching suffix in suftab, call the function associated + * with that suffix (p1 and p2). + */ +int +suffix(char *ep, int lev) +{ + struct suftab *t; + char *cp, *sp; + + lev += DLEV; + deriv[lev] = deriv[lev-1] = 0; + for (t = suftab; (sp = t->suf); t++) { + cp = ep; + while (*sp) { + if (*--cp != *sp++) + goto next; + } + for (sp = cp; --sp >= word && !vowel(*sp);) + ; /* nothing */ + if (sp < word) + return (0); + if ((*t->p1)(ep-t->n1, t->d1, t->a1, lev+1)) + return (1); + if (t->p2 != NULL) { + deriv[lev] = deriv[lev+1] = 0; + return ((*t->p2)(ep-t->n2, t->d2, t->a2, lev)); + } + return (0); +next: ; + } + return (0); +} + +int +nop(char *ep, char *d, char *a, int lev) +{ + + return (0); +} + +int +strip(char *ep, char *d, char *a, int lev) +{ + + return (trypref(ep, a, lev) || suffix(ep, lev)); +} + +int +s(char *ep, char *d, char *a, int lev) +{ + + if (lev > DLEV + 1) + return (0); + if (*ep == 's' && ep[-1] == 's') + return (0); + return (strip(ep, d, a, lev)); +} + +int +an(char *ep, char *d, char *a, int lev) +{ + + if (!isupper((unsigned char)*word)) /* must be proper name */ + return (0); + return (trypref(ep,a,lev)); +} + +int +ize(char *ep, char *d, char *a, int lev) +{ + + *ep++ = 'e'; + return (strip(ep ,"", d, lev)); +} + +int +y_to_e(char *ep, char *d, char *a, int lev) +{ + char c = *ep; + + *ep++ = 'e'; + if (strip(ep, "", d, lev)) + return (1); + ep[-1] = c; + return (0); +} + +int +ily(char *ep, char *d, char *a, int lev) +{ + + if (ep[-1] == 'i') + return (i_to_y(ep, d, a, lev)); + else + return (strip(ep, d, a, lev)); +} + +int +ncy(char *ep, char *d, char *a, int lev) +{ + + if (skipv(skipv(ep-1)) < word) + return (0); + ep[-1] = 't'; + return (strip(ep, d, a, lev)); +} + +int +bility(char *ep, char *d, char *a, int lev) +{ + + *ep++ = 'l'; + return (y_to_e(ep, d, a, lev)); +} + +int +i_to_y(char *ep, char *d, char *a, int lev) +{ + + if (ep[-1] == 'i') { + ep[-1] = 'y'; + a = d; + } + return (strip(ep, "", a, lev)); +} + +int +es(char *ep, char *d, char *a, int lev) +{ + + if (lev > DLEV) + return (0); + + switch (ep[-1]) { + default: + return (0); + case 'i': + return (i_to_y(ep, d, a, lev)); + case 's': + case 'h': + case 'z': + case 'x': + return (strip(ep, d, a, lev)); + } +} + +int +metry(char *ep, char *d, char *a, int lev) +{ + + ep[-2] = 'e'; + ep[-1] = 'r'; + return (strip(ep, d, a, lev)); +} + +int +tion(char *ep, char *d, char *a, int lev) +{ + + switch (ep[-2]) { + case 'c': + case 'r': + return (trypref(ep, a, lev)); + case 'a': + return (y_to_e(ep, d, a, lev)); + } + return (0); +} + +/* + * Possible consonant-consonant-e ending. + */ +int +CCe(char *ep, char *d, char *a, int lev) +{ + + switch (ep[-1]) { + case 'l': + if (vowel(ep[-2])) + break; + switch (ep[-2]) { + case 'l': + case 'r': + case 'w': + break; + default: + return (y_to_e(ep, d, a, lev)); + } + break; + case 's': + if (ep[-2] == 's') + break; + case 'c': + case 'g': + if (*ep == 'a') + return (0); + case 'v': + case 'z': + if (vowel(ep[-2])) + break; + case 'u': + if (y_to_e(ep, d, a, lev)) + return (1); + if (!(ep[-2] == 'n' && ep[-1] == 'g')) + return (0); + } + return (VCe(ep, d, a, lev)); +} + +/* + * Possible consonant-vowel-consonant-e ending. + */ +int +VCe(char *ep, char *d, char *a, int lev) +{ + char c; + + c = ep[-1]; + if (c == 'e') + return (0); + if (!vowel(c) && vowel(ep[-2])) { + c = *ep; + *ep++ = 'e'; + if (trypref(ep, d, lev) || suffix(ep, lev)) + return (1); + ep--; + *ep = c; + } + return (strip(ep, d, a, lev)); +} + +char * +lookuppref(char **wp, char *ep) +{ + char **sp; + char *bp,*cp; + + for (sp = preftab; *sp; sp++) { + bp = *wp; + for (cp = *sp; *cp; cp++, bp++) { + if (tolower((unsigned char)*bp) != *cp) + goto next; + } + for (cp = bp; cp < ep; cp++) { + if (vowel(*cp)) { + *wp = bp; + return (*sp); + } + } +next: ; + } + return (0); +} + +/* + * If the word is not in the dictionary, try stripping off prefixes + * until the word is found or we run out of prefixes to check. + */ +int +trypref(char *ep, char *a, int lev) +{ + char *cp; + char *bp; + char *pp; + int val = 0; + char space[20]; + + deriv[lev] = a; + if (tryword(word, ep, lev)) + return (1); + bp = word; + pp = space; + deriv[lev+1] = pp; + while ((cp = lookuppref(&bp, ep))) { + *pp++ = '+'; + while ((*pp = *cp++)) + pp++; + if (tryword(bp, ep, lev+1)) { + val = 1; + break; + } + if (pp - space >= sizeof(space)) + return (0); + } + deriv[lev+1] = deriv[lev+2] = 0; + return (val); +} + +int +tryword(char *bp, char *ep, int lev) +{ + int i, j; + char duple[3]; + + if (ep-bp <= 1) + return (0); + if (vowel(*ep) && monosyl(bp, ep)) + return (0); + + i = dict(bp, ep); + if (i == 0 && vowel(*ep) && ep[-1] == ep[-2] && monosyl(bp, ep-1)) { + ep--; + deriv[++lev] = duple; + duple[0] = '+'; + duple[1] = *ep; + duple[2] = '\0'; + i = dict(bp, ep); + } + if (vflag == 0 || i == 0) + return (i); + + /* Also tack on possible derivations. (XXX - warn on truncation?) */ + for (j = lev; j > 0; j--) { + if (deriv[j]) + strlcat(affix, deriv[j], sizeof(affix)); + } + return (i); +} + +int +monosyl(char *bp, char *ep) +{ + + if (ep < bp + 2) + return (0); + if (vowel(*--ep) || !vowel(*--ep) || ep[1] == 'x' || ep[1] == 'w') + return (0); + while (--ep >= bp) + if (vowel(*ep)) + return (0); + return (1); +} + +char * +skipv(char *s) +{ + + if (s >= word && vowel(*s)) + s--; + while (s >= word && !vowel(*s)) + s--; + return (s); +} + +int +vowel(unsigned char c) +{ + + switch (tolower(c)) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + case 'y': + return (1); + } + return (0); +} + +/* + * Crummy way to Britishise. + */ +void +ise(void) +{ + struct suftab *tab; + + for (tab = suftab; tab->suf; tab++) { + /* Assume that suffix will contain 'z' if a1 or d1 do */ + if (strchr(tab->suf, 'z')) { + tab->suf = estrdup(tab->suf); + ztos(tab->suf); + if (strchr(tab->d1, 'z')) { + tab->d1 = estrdup(tab->d1); + ztos(tab->d1); + } + if (strchr(tab->a1, 'z')) { + tab->a1 = estrdup(tab->a1); + ztos(tab->a1); + } + } + } +} + +void +ztos(char *s) +{ + + for (; *s; s++) + if (*s == 'z') + *s = 's'; +} + +char * +estrdup(const char *s) +{ + char *d; + + if ((d = strdup(s)) == NULL) + err(1, "strdup"); + return (d); +} + +/* + * Look up a word in the dictionary. + * Returns 1 if found, 0 if not. + */ +int +dict(char *bp, char *ep) +{ + char c; + int i, rval; + + c = *ep; + *ep = '\0'; + if (xflag) + printf("=%s\n", bp); + for (i = rval = 0; wlists[i].fd != -1; i++) { + if ((rval = look((unsigned char *)bp, wlists[i].front, + wlists[i].back)) == 1) + break; + } + *ep = c; + return (rval); +} + +static void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-bvx] [-o found-words] word-list ...\n", + __progname); + exit(1); +} diff --git a/usr.bin/spell/stop b/usr.bin/spell/stop new file mode 100644 --- /dev/null +++ b/usr.bin/spell/stop @@ -0,0 +1,968 @@ +abator +abeted +abeter +abeting +abuted +abuter +abuting +accessable +accompanyist +acquaince +acquiter +acquiting +acter +addendums +adly +admirality +admitable +admited +admiter +admiting +ahly +allotable +alloted +alloter +alloting +amly +andless +animadvertion +anly +annulable +annuled +annuler +annuling +ans +areless +Argentinan +arguement +arised +asly +assesser +Athenan +ation +ative +atly +ats +auditer +avered +averer +avering +avertion +awared +axises +axly +baned +baning +beared +beated +bedimed +bedimer +bediming +befited +befiter +befiting +befoged +befoger +befoging +begeted +begeter +begeting +begined +beginer +begining +beholded +beless +besetable +beseted +beseter +beseting +bespeaked +bestired +bestirer +bestiring +betted +bidded +bies +binded +bited +blader +bleeded +blowed +breaked +breeded +bringed +bursted +buyed +byly +Canadan +Carolinan +casted +catched +certainity +checksumable +checksumed +checksuming +choosed +clinged +collectable +collecter +comed +commitable +commited +commiter +commiting +compelable +compeled +compeler +compeling +compositer +compositon +compressable +compresser +conducter +coner +conferable +confered +conferer +confering +coning +connecter +conquerer +consigner +constricter +constructable +constructer +contemptable +contracter +contributer +controlable +controled +controler +controling +convertable +convertion +convokable +corpuses +correcter +corrigendums +corrodable +corruptable +counseler +crediter +creeped +crotchity +cruelity +crystalise +crystalize +curiousity +currance +currancy +curriculas +cutted +datas +datums +dealed +debared +debarer +debaring +debator +debter +debuged +debuger +debuging +decontroled +decontroler +decontroling +deductable +defecter +deferable +defered +deferer +defering +defication +deflator +deflecter +degased +degaser +degasing +degumed +degumer +deguming +demitable +demited +demiter +demiting +demured +demuring +denyable +depositer +depressable +depresser +desolator +destructer +detecter +deterable +detered +deterer +detering +determinancy +detracter +digestable +dimed +dimest +directer +discernable +discomfited +discomfiter +discomfiting +disintered +disinterer +disintering +dispelable +dispeled +dispeler +dispeling +dispence +divertion +doly +doned +doner +doning +drawed +drinked +drived +Dudly +duely +dus +dutyable +eated +eavesdroped +eavesdroper +eavesdroping +editer +effluvias +effluviums +ehly +ehs +ejecter +electer +elly +embedable +embeded +embeder +embeding +emitable +emited +emiter +emiting +emly +enaction +enbalm +enbank +enbark +enbattle +enbay +enbed +enbit +enblaze +enblazon +enbody +enboss +enbow +enbowel +enbrace +enbrittle +enbroil +encant +encur +endebted +enend +enflame +enform +engin +enirate +enit +enly +enpanel +enpathetic +enplace +enplane +enploy +enpower +enpress +enpurple +enroach +enroad +entend +enterity +entier +entirity +entone +envoice +envyable +equilibriums +equipable +equiped +equiper +equiping +erodable +errer +esophaguses +estoped +estoper +estoping +etly +ets +evokable +exasperator +exceled +exceler +exceling +exegesises +exhaustable +exhibiter +expection +expelable +expeled +expeler +expeling +expositer +expressable +extendable +extolable +extoled +extoler +extoling +extracter +extremums +extrovertion +facter +fadded +fadding +fallable +falled +feeded +feeled +fifity +fighted +finded +flamable +flexable +flinged +flirtion +Floridan +fluter +forbeared +forbided +foreage +forebade +forebid +forebidden +forebidding +forebore +foreborn +foreborne +foreensic +foreest +foreever +forefend +forefit +foregave +foreget +foregettable +foregetting +foregive +foregiven +foregot +foregotten +foremat +foremate +forematted +forematting +foremica +foresake +foreswear +foreswore +foresworn +foretress +foretune +forevery +foreward +forgetable +forgeted +forless +forsaked +fraility +freezed +froliced +frolicing +frustrator +gayity +generousity +genesises +genuses +getless +getted +Ghanan +giddaped +giddaper +giddaping +gived +goly +gos +gotless +governer +grammer +grimer +grimest +grinded +growed +guility +gullable +hadless +haly +hasless +haveless +heared +hely +hesitator +holded +huggest +huging +humbility +hurted +ifless +ifly +iis +impartion +impelable +impeled +impeler +impeling +importion +impressable +impugnity +incured +incurer +incuring +Indochinan +inducter +infered +inferer +infering +inflamable +inflator +ingestable +inheriter +inless +inly +inspecter +instructer +intence +interable +intercepter +intered +interer +intering +interruptable +intimator +inventer +invertable +invertion +invester +invokable +isless +isly +itly +ivly +ivs +ixes +ixly +jurer +juter +keeped +kiloohm +knowed +laly +lammest +lapeled +layed +lended +letted +licenser +loaned +locomoter +loging +loly +losed +loyality +luminousity +mader +madest +mading +maked +maly +maner +maning +manumitable +manumited +manumiter +manumiting +mared +meaned +meeted +mely +metafor +metafore +mies +mily +monstrousity +muchless +multiplexer +myly +nely +neurosises +nicity +noding +noless +noly +novelity +nuly +objecter +occured +occurer +occuring +offsetable +offseted +offseter +offseting +ofless +ofly +ofs +ohly +ons +oppresser +opuses +orless +outin +outof +outthat +outthe +outto +overthe +overto +ows +oxes +oxly +pairity +paly +paner +paniced +panicing +paralysises +parenthesises +paster +payed +pennance +pepperment +perceptable +perfectable +permitable +permited +permiter +permiting +pervertion +phenomenas +phenomenons +photosynthesises +piity +pipper +pityable +placator +plumer +plummer +plyable +pompousity +porousity +possesser +postprocesser +predicter +preempter +prefered +preferer +prefering +prerequite +presense +presuably +presure +processer +professer +programable +programed +programer +programing +projecter +propagandaist +propeled +propeler +propeling +properity +prosecuter +prospecter +protecter +publical +purveyer +quitable +quiter +quiting +rackity +ratter +readed +reah +realter +rean +reas +reat +reax +rebat +rebe +rebeled +rebeler +rebeling +rebutable +rebuted +rebuter +rebuting +reby +recal +recapable +recaped +recaper +recaping +recloth +recommitable +recommited +recommiter +recommiting +recured +recurer +recuring +redacter +reden +redish +redu +reem +reen +reet +refered +referer +refering +reflecter +rego +regretable +regreted +regreter +regreting +reguard +reha +rehe +rehi +reho +reif +reii +reis +reit +reiv +reix +rela +religiousity +relo +rema +remad +remaned +remaner +remaning +reme +remedyable +remi +remitable +remited +remiter +remiting +remy +rended +renoun +renu +reof +reoh +reon +reor +reow +reox +repa +repelable +repeled +repeler +repeling +repi +rere +rerout +rerunable +reruned +reruner +reruning +resa +reshiped +reshiper +reshiping +resistable +reso +reti +reto +reup +revertion +revi +revisor +revokable +rewe +rewok +rexi +reye +rickity +rided +rised +rocketed +rocketer +rocketing +royality +runable +runed +runned +saging +saly +saturator +sayed +scrupulousity +sculpter +secter +seeked +selecter +selled +senation +senative +sended +senser +setted +shaked +shedded +shelfs +shily +shooted +shrinked +shutted +siner +sining +sinked +siply +sitted +sixity +slayed +sleeped +slided +slightlyless +slinged +slinked +smited +soliciter +soly +somewhatless +sovereignity +speaked +spearment +spended +spinable +spiner +spining +spinned +spiting +splitted +spreaded +stagged +standed +stealed +sticked +stinked +stratas +strictlyless +strided +striked +submitable +submited +submiter +submiting +subtlity +successer +suggestable +suiter +suntaned +suntaning +suppressable +surity +surveyer +suspenser +suzerainity +sweared +sweeped +swinged +synopsises +synthesises +taked +teached +teching +telled +theless +thesises +thier +thinked +thrombosises +throwed +thrusted +tiner +tining +toly +tracter +traiter +transfered +transferer +transfering +transgresser +transmitable +transmited +transmiter +transmiting +transportion +trivias +triviums +truely +typeseter +typeseting +unactivate +unadequacy +unattention +unboard +unbreed +uncant +uncapacity +uncompletion +uncorporate +uncrease +uncredulity +unculpable +uncur +uncurred +uncurrer +uncurring +undebt +undeed +undefinite +undelicate +undent +undenture +undermind +underthat +underthe +underthis +underwhich +undices +undignity +undiscriminate +undisposition +undoor +unduct +undwell +unefficacy +unequity +unfamous +unfelicity +unfest +unfield +unfiltrate +unfinity +unflame +unflammable +unflow +unfluence +unflux +unformant +unformation +unfuse +unfusion +ungather +ungrate +ungratitude +unhabitant +unhabitation +unhale +unhere +unholding +unhumane +unhumanity +unjure +unjury +unnumerable +unoperable +unput +unquest +unscribe +unscription +unsect +unside +unspire +unstall +unstance +unstead +untact +untake +untemperance +untend +untestate +untill +untolerant +untuition +unvade +unvalidate +unvent +unverse +unversion +unvertebrate +unviolate +unvocate +unward +unwieldly +uply +upseter +upseting +usly +usses +varyable +vendable +Viennan +virtuousity +viscousity +visiter +warer +wasless +weared +weeped +wely +wereless +wharfs +whitter +whitting +wifes +winable +winned +withless +wringed +writed +yiper