source: trunk/third/ispell/ispell.c @ 10334

Revision 10334, 26.6 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10333, which included commits to RCS files with non-trunk default branches.
Line 
1#ifndef lint
2static char Rcs_Id[] =
3    "$Id: ispell.c,v 1.1.1.1 1997-09-03 21:08:12 ghudson Exp $";
4#endif
5
6#define MAIN
7
8/*
9 * ispell.c - An interactive spelling corrector.
10 *
11 * Copyright (c), 1983, by Pace Willisson
12 *
13 * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 * 3. All modifications to the source code must be clearly marked as
26 *    such.  Binary redistributions based on modified source code
27 *    must be clearly marked as modified versions in the documentation
28 *    and/or other materials provided with the distribution.
29 * 4. All advertising materials mentioning features or use of this software
30 *    must display the following acknowledgment:
31 *      This product includes software developed by Geoff Kuenning and
32 *      other unpaid contributors.
33 * 5. The name of Geoff Kuenning may not be used to endorse or promote
34 *    products derived from this software without specific prior
35 *    written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 */
49
50/*
51 * $Log: not supported by cvs2svn $
52 * Revision 1.133  1995/10/11  04:30:29  geoff
53 * Get rid of an unused variable.
54 *
55 * Revision 1.132  1995/08/05  23:19:36  geoff
56 * If the DICTIONARY environment variable is set, derive the default
57 * personal-dictionary name from it.
58 *
59 * Revision 1.131  1995/01/08  23:23:39  geoff
60 * Support variable hashfile suffixes for DOS purposes.  Report all the
61 * new configuration variables in the -vv switch.  Do some better error
62 * checking for mktemp failures.  Support the rename system call.  All of
63 * this is to help make DOS porting easier.
64 *
65 * Revision 1.130  1995/01/03  19:24:08  geoff
66 * When constructing a personal-dictioary name from the hash file name,
67 * don't stupidly include path directory components.
68 *
69 * Revision 1.129  1995/01/03  02:23:19  geoff
70 * Disable the setbuf call on BSDI systems, sigh.
71 *
72 * Revision 1.128  1994/10/26  05:12:28  geoff
73 * Include boundary characters in the list of characters to be tried in
74 * corrections.
75 *
76 * Revision 1.127  1994/10/25  05:46:07  geoff
77 * Allow the default dictionary to be specified by an environment
78 * variable (DICTIONARY) as well as a switch.
79 *
80 * Revision 1.126  1994/09/16  03:32:34  geoff
81 * Issue an error message for bad affix flags
82 *
83 * Revision 1.125  1994/07/28  05:11:36  geoff
84 * Log message for previous revision: fix backup-file checks to correctly
85 * test for exceeding MAXNAMLEN.
86 *
87 * Revision 1.124  1994/07/28  04:53:39  geoff
88 *
89 * Revision 1.123  1994/05/17  06:44:12  geoff
90 * Add support for controlled compound formation and the COMPOUNDONLY
91 * option to affix flags.
92 *
93 * Revision 1.122  1994/04/27  01:50:37  geoff
94 * Print MAX_CAPS in -vv mode.
95 *
96 * Revision 1.121  1994/03/16  03:49:10  geoff
97 * Fix -vv to display the value of NO_STDLIB_H.
98 *
99 * Revision 1.120  1994/03/15  06:24:28  geoff
100 * Allow the -t, -n, and -T switches to override each other, as follows:
101 * if no switches are given, the deformatter and string characters are
102 * chosen based on the file suffix.  If only -t/-n are given, the
103 * deformatter is forced but string cahracters come from the file suffix.
104 * If only -T is given, the deformatter is chosen based on the value
105 * given in the -T switch.  Finally, if both -T and -t/-n are given,
106 * string characters are controlled by -T and the deformatter by -t/-n.
107 *
108 * Revision 1.119  1994/03/15  05:58:07  geoff
109 * Get rid of a gcc warning
110 *
111 * Revision 1.118  1994/03/15  05:30:37  geoff
112 * Get rid of an unused-variable complaint by proper ifdeffing
113 *
114 * Revision 1.117  1994/03/12  21:26:48  geoff
115 * Correctly limit maximum name lengths for files that have directory paths
116 * included.  Also don't use a wired-in 256 for the size of the backup file
117 * name.
118 *
119 * Revision 1.116  1994/02/07  08:10:44  geoff
120 * Print GENERATE_LIBRARY_PROTOS in the -vv switch.
121 *
122 * Revision 1.115  1994/01/26  07:44:47  geoff
123 * Make yacc configurable through local.h.
124 *
125 * Revision 1.114  1994/01/25  07:11:44  geoff
126 * Get rid of all old RCS log lines in preparation for the 3.1 release.
127 *
128 */
129
130#include "config.h"
131#include "ispell.h"
132#include "proto.h"
133#include "msgs.h"
134#include "version.h"
135#include <ctype.h>
136#include <sys/stat.h>
137
138static void     usage P ((void));
139static void     initckch P ((char * wchars));
140int             main P ((int argc, char * argv[]));
141static void     dofile P ((char * filename));
142static void     update_file P ((char * filename, struct stat * statbuf));
143static void     expandmode P ((int printorig));
144
145static char *   Cmd;
146static char *   LibDict = NULL;         /* Pointer to name of $(LIBDIR)/dict */
147
148static void usage ()
149    {
150
151    (void) fprintf (stderr, ISPELL_C_USAGE1, Cmd);
152    (void) fprintf (stderr, ISPELL_C_USAGE2, Cmd);
153    (void) fprintf (stderr, ISPELL_C_USAGE3, Cmd);
154    (void) fprintf (stderr, ISPELL_C_USAGE4, Cmd);
155    (void) fprintf (stderr, ISPELL_C_USAGE5, Cmd);
156    (void) fprintf (stderr, ISPELL_C_USAGE6, Cmd);
157    (void) fprintf (stderr, ISPELL_C_USAGE7, Cmd);
158    givehelp (0);
159    exit (1);
160    }
161
162static void initckch (wchars)
163    char *              wchars;         /* Characters in -w option, if any */
164    {
165    register ichar_t    c;
166    char                num[4];
167
168    for (c = 0; c < (ichar_t) (SET_SIZE + hashheader.nstrchars); ++c)
169        {
170        if (iswordch (c))
171            {
172            if (!mylower (c))
173                {
174                Try[Trynum] = c;
175                ++Trynum;
176                }
177            }
178        else if (isboundarych (c))
179            {
180            Try[Trynum] = c;
181            ++Trynum;
182            }
183        }
184    if (wchars != NULL)
185        {
186        while (Trynum < SET_SIZE  &&  *wchars != '\0')
187            {
188            if (*wchars != 'n'  &&  *wchars != '\\')
189                {
190                c = *wchars;
191                ++wchars;
192                }
193            else
194                {
195                ++wchars;
196                num[0] = '\0';
197                num[1] = '\0';
198                num[2] = '\0';
199                num[3] = '\0';
200                if (isdigit (wchars[0]))
201                    {
202                    num[0] = wchars[0];
203                    if (isdigit (wchars[1]))
204                        {
205                        num[1] = wchars[1];
206                        if (isdigit (wchars[2]))
207                            num[2] = wchars[2];
208                        }
209                    }
210                if (wchars[-1] == 'n')
211                    {
212                    wchars += strlen (num);
213                    c = atoi (num);
214                    }
215                else
216                    {
217                    wchars += strlen (num);
218                    c = 0;
219                    if (num[0])
220                        c = num[0] - '0';
221                    if (num[1])
222                        {
223                        c <<= 3;
224                        c += num[1] - '0';
225                        }
226                    if (num[2])
227                        {
228                        c <<= 3;
229                        c += num[2] - '0';
230                        }
231                    }
232                }
233            c &= NOPARITY;
234            if (!hashheader.wordchars[c])
235                {
236                hashheader.wordchars[c] = 1;
237                hashheader.sortorder[c] = hashheader.sortval++;
238                Try[Trynum] = c;
239                ++Trynum;
240                }
241            }
242        }
243    }
244
245int main (argc, argv)
246    int         argc;
247    char *      argv[];
248    {
249    char *      p;
250    char *      cpd;
251    char **     versionp;
252    char *      wchars = NULL;
253    char *      preftype = NULL;
254    static char libdictname[sizeof DEFHASH];
255    static char outbuf[BUFSIZ];
256    int         argno;
257    int         arglen;
258
259    Cmd = *argv;
260
261    Trynum = 0;
262
263    p = getenv ("DICTIONARY");
264    if (p != NULL)
265        {
266        if (index (p, '/') != NULL)
267            (void) strcpy (hashname, p);
268        else
269            (void) sprintf (hashname, "%s/%s", LIBDIR, p);
270        (void) strcpy (libdictname, p);
271        p = rindex (p, '.');
272        if (p == NULL  ||  strcmp (p, HASHSUFFIX) != 0)
273            (void) strcat (hashname, HASHSUFFIX);
274        LibDict = rindex (libdictname, '/');
275        if (LibDict != NULL)
276            LibDict++;
277        else
278            LibDict = libdictname;
279        p = rindex (libdictname, '.');
280        if (p != NULL)
281            *p = '\0';
282        }
283    else
284        (void) sprintf (hashname, "%s/%s", LIBDIR, DEFHASH);
285
286    cpd = NULL;
287
288    argv++;
289    argc--;
290    while (argc && **argv == '-')
291        {
292        /*
293         * Trying to add a new flag?  Can't remember what's been used?
294         * Here's a handy guide:
295         *
296         * Used:
297         *
298         *      ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
299         *      ^^^^       ^^^ ^  ^^ ^^
300         *      abcdefghijklmnopqrstuvwxyz
301         *      ^^^^^^     ^^^ ^  ^^ ^^^
302         */
303        arglen = strlen (*argv);
304        switch ((*argv)[1])
305            {
306            case 'v':
307                if (arglen > 3)
308                    usage ();
309                for (versionp = Version_ID;  *versionp;  )
310                    {
311                    p = *versionp++;
312                    if (strncmp (p, "(#) ", 5) == 0)
313                      p += 5;
314                    (void) printf ("%s\n", p);
315                    }
316                if ((*argv)[2] == 'v')
317                    {
318                    (void) printf (ISPELL_C_OPTIONS_ARE);
319#ifdef USG
320                    (void) printf ("\tUSG\n");
321#else /* USG */
322                    (void) printf ("\t!USG (BSD)\n");
323#endif /* USG */
324                    (void) printf ("\tBAKEXT = \"%s\"\n", BAKEXT);
325                    (void) printf ("\tBINDIR = \"%s\"\n", BINDIR);
326#ifdef BOTTOMCONTEXT
327                    (void) printf ("\tBOTTOMCONTEXT\n");
328#else /* BOTTOMCONTEXT */
329                    (void) printf ("\t!BOTTOMCONTEXT\n");
330#endif /* BOTTOMCONTEXT */
331#if TERM_MODE == CBREAK
332                    (void) printf ("\tCBREAK\n");
333#endif /* TERM_MODE */
334                    (void) printf ("\tCC = \"%s\"\n", CC);
335                    (void) printf ("\tCFLAGS = \"%s\"\n", CFLAGS);
336#ifdef COMMANDFORSPACE
337                    (void) printf ("\tCOMMANDFORSPACE\n");
338#else /* COMMANDFORSPACE */
339                    (void) printf ("\t!COMMANDFORSPACE\n");
340#endif /* COMMANDFORSPACE */
341#ifdef CONTEXTROUNDUP
342                    (void) printf ("\tCONTEXTROUNDUP\n");
343#else /* CONTEXTROUNDUP */
344                    (void) printf ("\t!CONTEXTROUNDUP\n");
345#endif /* CONTEXTROUNDUP */
346                    (void) printf ("\tCONTEXTPCT = %d\n", CONTEXTPCT);
347                    (void) printf ("\tCOUNTSUFFIX = \"%s\"\n", COUNTSUFFIX);
348                    (void) printf ("\tDEFHASH = \"%s\"\n", DEFHASH);
349                    (void) printf ("\tDEFINCSTR = \"%s\"\n", DEFINCSTR);
350                    (void) printf ("\tDEFLANG = \"%s\"\n", DEFLANG);
351                    (void) printf ("\tDEFNOBACKUPFLAG = %d\n",
352                      DEFNOBACKUPFLAG);
353                    (void) printf ("\tDEFPAFF = \"%s\"\n", DEFPAFF);
354                    (void) printf ("\tDEFPDICT = \"%s\"\n", DEFPDICT);
355                    (void) printf ("\tDEFTEXFLAG = %d\n", DEFTEXFLAG);
356                    (void) printf ("\tEGREPCMD = \"%s\"\n", EGREPCMD);
357                    (void) printf ("\tELISPDIR = \"%s\"\n", ELISPDIR);
358                    (void) printf ("\tEMACS = \"%s\"\n", EMACS);
359#ifdef EQUAL_COLUMNS
360                    (void) printf ("\tEQUAL_COLUMNS\n");
361#else /* EQUAL_COLUMNS */
362                    (void) printf ("\t!EQUAL_COLUMNS\n");
363#endif /* EQUAL_COLUMNS */
364#ifdef GENERATE_LIBRARY_PROTOS
365                    (void) printf ("\tGENERATE_LIBRARY_PROTOS\n");
366#else /* GENERATE_LIBRARY_PROTOS */
367                    (void) printf ("\t!GENERATE_LIBRARY_PROTOS\n");
368#endif /* GENERATE_LIBRARY_PROTOS */
369#ifdef HAS_RENAME
370                    (void) printf ("\tHAS_RENAME\n");
371#else /* HAS_RENAME */
372                    (void) printf ("\t!HAS_RENAME\n");
373#endif /* HAS_RENAME */
374                    (void) printf ("\tHASHSUFFIX = \"%s\"\n", HASHSUFFIX);
375                    (void) printf ("\tHOME = \"%s\"\n", HOME);
376#ifdef IGNOREBIB
377                    (void) printf ("\tIGNOREBIB\n");
378#else /* IGNOREBIB */
379                    (void) printf ("\t!IGNOREBIB\n");
380#endif /* IGNOREBIB */
381                    (void) printf ("\tINCSTRVAR = \"%s\"\n", INCSTRVAR);
382                    (void) printf ("\tINPUTWORDLEN = %d\n", INPUTWORDLEN);
383                    (void) printf ("\tLANGUAGES = \"%s\"\n", LANGUAGES);
384                    (void) printf ("\tLIBDIR = \"%s\"\n", LIBDIR);
385                    (void) printf ("\tLIBES = \"%s\"\n", LIBES);
386                    (void) printf ("\tLINT = \"%s\"\n", LINT);
387                    (void) printf ("\tLINTFLAGS = \"%s\"\n", LINTFLAGS);
388#ifndef REGEX_LOOKUP
389                    (void) printf ("\tLOOK = \"%s\"\n", LOOK);
390#endif /* REGEX_LOOKUP */
391                    (void) printf ("\tMAKE_SORTTMP = \"%s\"\n", MAKE_SORTTMP);
392                    (void) printf ("\tMALLOC_INCREMENT = %d\n",
393                      MALLOC_INCREMENT);
394                    (void) printf ("\tMAN1DIR = \"%s\"\n", MAN1DIR);
395                    (void) printf ("\tMAN1EXT = \"%s\"\n", MAN1EXT);
396                    (void) printf ("\tMAN4DIR = \"%s\"\n", MAN4DIR);
397                    (void) printf ("\tMAN4EXT = \"%s\"\n", MAN4EXT);
398                    (void) printf ("\tMASKBITS = %d\n", MASKBITS);
399                    (void) printf ("\tMASKTYPE = %s\n", MASKTYPE_STRING);
400                    (void) printf ("\tMASKTYPE_WIDTH = %d\n", MASKTYPE_WIDTH);
401                    (void) printf ("\tMASTERHASH = \"%s\"\n", MASTERHASH);
402                    (void) printf ("\tMAXAFFIXLEN = %d\n", MAXAFFIXLEN);
403                    (void) printf ("\tMAXCONTEXT = %d\n", MAXCONTEXT);
404                    (void) printf ("\tMAXINCLUDEFILES = %d\n",
405                      MAXINCLUDEFILES);
406                    (void) printf ("\tMAXNAMLEN = %d\n", MAXNAMLEN);
407                    (void) printf ("\tMAXPATHLEN = %d\n", MAXPATHLEN);
408                    (void) printf ("\tMAXPCT = %d\n", MAXPCT);
409                    (void) printf ("\tMAXSEARCH = %d\n", MAXSEARCH);
410                    (void) printf ("\tMAXSTRINGCHARLEN = %d\n",
411                      MAXSTRINGCHARLEN);
412                    (void) printf ("\tMAXSTRINGCHARS = %d\n", MAXSTRINGCHARS);
413                    (void) printf ("\tMAX_CAPS = %d\n", MAX_CAPS);
414                    (void) printf ("\tMAX_HITS = %d\n", MAX_HITS);
415                    (void) printf ("\tMAX_SCREEN_SIZE = %d\n",
416                      MAX_SCREEN_SIZE);
417                    (void) printf ("\tMINCONTEXT = %d\n", MINCONTEXT);
418#ifdef MINIMENU
419                    (void) printf ("\tMINIMENU\n");
420#else /* MINIMENU */
421                    (void) printf ("\t!MINIMENU\n");
422#endif /* MINIMENU */
423                    (void) printf ("\tMINWORD = %d\n", MINWORD);
424                    (void) printf ("\tMSDOS_BINARY_OPEN = 0x%x\n",
425                      (unsigned int) MSDOS_BINARY_OPEN);
426                    (void) printf ("\tMSGLANG = %s\n", MSGLANG);
427#ifdef NO_CAPITALIZATION_SUPPORT
428                    (void) printf ("\tNO_CAPITALIZATION_SUPPORT\n");
429#else /* NO_CAPITALIZATION_SUPPORT */
430                    (void) printf ("\t!NO_CAPITALIZATION_SUPPORT\n");
431#endif /* NO_CAPITALIZATION_SUPPORT */
432#ifdef NO_STDLIB_H
433                    (void) printf ("\tNO_STDLIB_H\n");
434#else /* NO_STDLIB_H */
435                    (void) printf ("\t!NO_STDLIB_H (STDLIB_H)\n");
436#endif /* NO_STDLIB_H */
437#ifdef NO8BIT
438                    (void) printf ("\tNO8BIT\n");
439#else /* NO8BIT */
440                    (void) printf ("\t!NO8BIT (8BIT)\n");
441#endif /* NO8BIT */
442                    (void) printf ("\tNRSPECIAL = \"%s\"\n", NRSPECIAL);
443                    (void) printf ("\tOLDPAFF = \"%s\"\n", OLDPAFF);
444                    (void) printf ("\tOLDPDICT = \"%s\"\n", OLDPDICT);
445#ifdef PDICTHOME
446                    (void) printf ("\tPDICTHOME = \"%s\"\n", PDICTHOME);
447#else /* PDICTHOME */
448                    (void) printf ("\tPDICTHOME = (undefined)\n");
449#endif /* PDICTHOME */
450                    (void) printf ("\tPDICTVAR = \"%s\"\n", PDICTVAR);
451#ifdef PIECEMEAL_HASH_WRITES
452                    (void) printf ("\tPIECEMEAL_HASH_WRITES\n");
453#else /* PIECEMEAL_HASH_WRITES */
454                    (void) printf ("\t!PIECEMEAL_HASH_WRITES\n");
455#endif /* PIECEMEAL_HASH_WRITES */
456#if TERM_MODE != CBREAK
457                    (void) printf ("\tRAW\n");
458#endif /* TERM_MODE */
459#ifdef REGEX_LOOKUP
460                    (void) printf ("\tREGEX_LOOKUP\n");
461#else /* REGEX_LOOKUP */
462                    (void) printf ("\t!REGEX_LOOKUP\n");
463#endif /* REGEX_LOOKUP */
464                    (void) printf ("\tREGLIB = \"%s\"\n", REGLIB);
465                    (void) printf ("\tSIGNAL_TYPE = %s\n", SIGNAL_TYPE_STRING);
466                    (void) printf ("\tSORTPERSONAL = %d\n", SORTPERSONAL);
467                    (void) printf ("\tSTATSUFFIX = \"%s\"\n", STATSUFFIX);
468                    (void) printf ("\tTEMPNAME = \"%s\"\n", TEMPNAME);
469                    (void) printf ("\tTERMLIB = \"%s\"\n", TERMLIB);
470                    (void) printf ("\tTEXINFODIR = \"%s\"\n", TEXINFODIR);
471                    (void) printf ("\tTEXSPECIAL = \"%s\"\n", TEXSPECIAL);
472#ifdef TRUNCATEBAK
473                    (void) printf ("\tTRUNCATEBAK\n");
474#else /* TRUNCATEBAK */
475                    (void) printf ("\t!TRUNCATEBAK\n");
476#endif /* TRUNCATEBAK */
477#ifdef USESH
478                    (void) printf ("\tUSESH\n");
479#else /* USESH */
480                    (void) printf ("\t!USESH\n");
481#endif /* USESH */
482                    (void) printf ("\tWORDS = \"%s\"\n", WORDS);
483                    (void) printf ("\tYACC = \"%s\"\n", YACC);
484                    }
485                exit (0);
486                break;
487            case 'n':
488                if (arglen > 2)
489                    usage ();
490                tflag = 0;              /* nroff/troff mode */
491                deftflag = 0;
492                if (preftype == NULL)
493                    preftype = "nroff";
494                break;
495            case 't':                   /* TeX mode */
496                if (arglen > 2)
497                    usage ();
498                tflag = 1;
499                deftflag = 1;
500                if (preftype == NULL)
501                    preftype = "tex";
502                break;
503            case 'T':                   /* Set preferred file type */
504                p = (*argv)+2;
505                if (*p == '\0')
506                    {
507                    argv++; argc--;
508                    if (argc == 0)
509                        usage ();
510                    p = *argv;
511                    }
512                preftype = p;
513                break;
514            case 'A':
515                if (arglen > 2)
516                    usage ();
517                incfileflag = 1;
518                aflag = 1;
519                break;
520            case 'a':
521                if (arglen > 2)
522                    usage ();
523                aflag++;
524                break;
525            case 'D':
526                if (arglen > 2)
527                    usage ();
528                dumpflag++;
529                nodictflag++;
530                break;
531            case 'e':
532                if (arglen > 3)
533                    usage ();
534                eflag = 1;
535                if ((*argv)[2] == 'e')
536                    eflag = 2;
537                else if ((*argv)[2] >= '1'  &&  (*argv)[2] <= '4')
538                    eflag = (*argv)[2] - '0';
539                else if ((*argv)[2] != '\0')
540                    usage ();
541                nodictflag++;
542                break;
543            case 'c':
544                if (arglen > 2)
545                    usage ();
546                cflag++;
547                lflag++;
548                nodictflag++;
549                break;
550            case 'b':
551                if (arglen > 2)
552                    usage ();
553                xflag = 0;              /* Keep a backup file */
554                break;
555            case 'x':
556                if (arglen > 2)
557                    usage ();
558                xflag = 1;              /* Don't keep a backup file */
559                break;
560            case 'f':
561                fflag++;
562                p = (*argv)+2;
563                if (*p == '\0')
564                    {
565                    argv++; argc--;
566                    if (argc == 0)
567                        usage ();
568                    p = *argv;
569                    }
570                askfilename = p;
571                if (*askfilename == '\0')
572                    askfilename = NULL;
573                break;
574            case 'L':
575                p = (*argv)+2;
576                if (*p == '\0')
577                    {
578                    argv++; argc--;
579                    if (argc == 0)
580                        usage ();
581                    p = *argv;
582                    }
583                contextsize = atoi (p);
584                break;
585            case 'l':
586                if (arglen > 2)
587                    usage ();
588                lflag++;
589                break;
590#ifndef USG
591            case 's':
592                if (arglen > 2)
593                    usage ();
594                sflag++;
595                break;
596#endif
597            case 'S':
598                if (arglen > 2)
599                    usage ();
600                sortit = 0;
601                break;
602            case 'B':           /* -B:  report missing blanks */
603                if (arglen > 2)
604                    usage ();
605                compoundflag = COMPOUND_NEVER;
606                break;
607            case 'C':           /* -C:  compound words are acceptable */
608                if (arglen > 2)
609                    usage ();
610                compoundflag = COMPOUND_ANYTIME;
611                break;
612            case 'P':           /* -P:  don't gen non-dict poss's */
613                if (arglen > 2)
614                    usage ();
615                tryhardflag = 0;
616                break;
617            case 'm':           /* -m:  make all poss affix combos */
618                if (arglen > 2)
619                    usage ();
620                tryhardflag = 1;
621                break;
622            case 'N':           /* -N:  suppress minimenu */
623                if (arglen > 2)
624                    usage ();
625                minimenusize = 0;
626                break;
627            case 'M':           /* -M:  force minimenu */
628                if (arglen > 2)
629                    usage ();
630                minimenusize = 2;
631                break;
632            case 'p':
633                cpd = (*argv)+2;
634                if (*cpd == '\0')
635                    {
636                    argv++; argc--;
637                    if (argc == 0)
638                        usage ();
639                    cpd = *argv;
640                    if (*cpd == '\0')
641                        cpd = NULL;
642                    }
643                LibDict = NULL;
644                break;
645            case 'd':
646                p = (*argv)+2;
647                if (*p == '\0')
648                    {
649                    argv++; argc--;
650                    if (argc == 0)
651                        usage ();
652                    p = *argv;
653                    }
654                if (index (p, '/') != NULL)
655                    (void) strcpy (hashname, p);
656                else
657                    (void) sprintf (hashname, "%s/%s", LIBDIR, p);
658                if (cpd == NULL  &&  *p != '\0')
659                    LibDict = p;
660                p = rindex (p, '.');
661                if (p != NULL  &&  strcmp (p, HASHSUFFIX) == 0)
662                    *p = '\0';  /* Don't want ext. in LibDict */
663                else
664                    (void) strcat (hashname, HASHSUFFIX);
665                if (LibDict != NULL)
666                    {
667                    p = rindex (LibDict, '/');
668                    if (p != NULL)
669                        LibDict = p + 1;
670                    }
671                break;
672            case 'V':           /* Display 8-bit characters as M-xxx */
673                if (arglen > 2)
674                    usage ();
675                vflag = 1;
676                break;
677            case 'w':
678                wchars = (*argv)+2;
679                if (*wchars == '\0')
680                    {
681                    argv++; argc--;
682                    if (argc == 0)
683                        usage ();
684                    wchars = *argv;
685                    }
686                break;
687            case 'W':
688                if ((*argv)[2] == '\0')
689                    {
690                    argv++; argc--;
691                    if (argc == 0)
692                        usage ();
693                    minword = atoi (*argv);
694                    }
695                else
696                    minword = atoi (*argv + 2);
697                break;
698            default:
699                usage ();
700            }
701        argv++;
702        argc--;
703        }
704
705    if (!argc  &&  !lflag  &&  !aflag   &&  !eflag  &&  !dumpflag)
706        usage ();
707
708    /*
709     * Because of the high cost of reading the dictionary, we stat
710     * the files specified first to see if they exist.  If at least
711     * one exists, we continue.
712     */
713    for (argno = 0;  argno < argc;  argno++)
714        {
715        if (access (argv[argno], 4) >= 0)
716            break;
717        }
718    if (argno >= argc  &&  !lflag  &&  !aflag  &&  !eflag  &&  !dumpflag)
719        {
720        (void) fprintf (stderr,
721          argc == 1 ? ISPELL_C_NO_FILE : ISPELL_C_NO_FILES);
722        exit (1);
723        }
724    if (linit () < 0)
725        exit (1);
726
727    if (preftype != NULL)
728        {
729        prefstringchar =
730          findfiletype (preftype, 1, deftflag < 0 ? &deftflag : (int *) NULL);
731        if (prefstringchar < 0
732          &&  strcmp (preftype, "tex") != 0
733          &&  strcmp (preftype, "nroff") != 0)
734            {
735            (void) fprintf (stderr, ISPELL_C_BAD_TYPE, preftype);
736            exit (1);
737            }
738        }
739    if (prefstringchar < 0)
740        defdupchar = 0;
741    else
742        defdupchar = prefstringchar;
743
744    if (compoundflag < 0)
745        compoundflag = hashheader.compoundflag;
746    if (tryhardflag < 0)
747        tryhardflag = hashheader.defhardflag;
748
749    initckch(wchars);
750
751    if (LibDict == NULL)       
752        {
753        (void) strcpy (libdictname, DEFHASH);
754        LibDict = libdictname;
755        p = rindex (libdictname, '.');
756        if (p != NULL  &&  strcmp (p, HASHSUFFIX) == 0)
757            *p = '\0';  /* Don't want ext. in LibDict */
758        }
759    if (!nodictflag)
760        treeinit (cpd, LibDict);
761
762    if (aflag)
763        {
764        askmode ();
765        treeoutput ();
766        exit (0);
767        }
768    else if (eflag)
769        {
770        expandmode (eflag);
771        exit (0);
772        }
773    else if (dumpflag)
774        {
775        dumpmode ();
776        exit (0);
777        }
778
779#ifndef __bsdi__
780    setbuf (stdout, outbuf);
781#endif /* __bsdi__ */
782    if (lflag)
783        {
784        infile = stdin;
785        outfile = stdout;
786        checkfile ();
787        exit (0);
788        }
789
790    terminit ();
791
792    while (argc--)
793        dofile (*argv++);
794
795    done (0);
796    /* NOTREACHED */
797    return 0;
798    }
799
800static void dofile (filename)
801    char *      filename;
802    {
803    struct stat statbuf;
804    char *      cp;
805
806    currentfile = filename;
807
808    /* See if the file is a .tex file.  If so, set the appropriate flags. */
809    tflag = deftflag;
810    if (tflag < 0)
811        tflag =
812          (cp = rindex (filename, '.')) != NULL  &&  strcmp (cp, ".tex") == 0;
813
814    if (prefstringchar < 0)
815        {
816        defdupchar =
817          findfiletype (filename, 0, deftflag < 0 ? &tflag : (int *) NULL);
818        if (defdupchar < 0)
819            defdupchar = 0;
820        }
821
822    if ((infile = fopen (filename, "r")) == NULL)
823        {
824        (void) fprintf (stderr, CANT_OPEN, filename);
825        (void) sleep ((unsigned) 2);
826        return;
827        }
828
829    readonly = access (filename, 2) < 0;
830    if (readonly)
831        {
832        (void) fprintf (stderr, ISPELL_C_CANT_WRITE, filename);
833        (void) sleep ((unsigned) 2);
834        }
835
836    (void) fstat (fileno (infile), &statbuf);
837    (void) strcpy (tempfile, TEMPNAME);
838    if (mktemp (tempfile) == NULL  ||  tempfile[0] == '\0'
839      ||  (outfile = fopen (tempfile, "w")) == NULL)
840        {
841        (void) fprintf (stderr, CANT_CREATE,
842          (tempfile == NULL  ||  tempfile[0] == '\0')
843            ? "temporary file" : tempfile);
844        (void) sleep ((unsigned) 2);
845        return;
846        }
847    (void) chmod (tempfile, statbuf.st_mode);
848
849    quit = 0;
850    changes = 0;
851
852    checkfile ();
853
854    (void) fclose (infile);
855    (void) fclose (outfile);
856
857    if (!cflag)
858        treeoutput ();
859
860    if (changes && !readonly)
861        update_file (filename, &statbuf);
862    (void) unlink (tempfile);
863    }
864
865static void update_file (filename, statbuf)
866    char *              filename;
867    struct stat *       statbuf;
868    {
869    char                bakfile[MAXPATHLEN];
870    int                 c;
871    char *              pathtail;
872
873    if ((infile = fopen (tempfile, "r")) == NULL)
874        {
875        (void) fprintf (stderr, ISPELL_C_TEMP_DISAPPEARED, tempfile);
876        (void) sleep ((unsigned) 2);
877        return;
878        }
879
880#ifdef TRUNCATEBAK
881    (void) strncpy (bakfile, filename, sizeof bakfile - 1);
882    bakfile[sizeof bakfile - 1] = '\0';
883    if (strcmp(BAKEXT, filename + strlen(filename) - sizeof BAKEXT - 1) != 0)
884        {
885        pathtail = rindex (bakfile, '/');
886        if (pathtail == NULL)
887            pathtail = bakfile;
888        else
889            pathtail++;
890        if (strlen (pathtail) > MAXNAMLEN - sizeof BAKEXT - 1)
891            pathtail[MAXNAMLEN - sizeof BAKEXT -1] = '\0';
892        (void) strcat (pathtail, BAKEXT);
893        }
894#else
895    (void) sprintf (bakfile, "%.*s%s", (int) (sizeof bakfile - sizeof BAKEXT),
896      filename, BAKEXT);
897#endif
898
899    pathtail = rindex (bakfile, '/');
900    if (pathtail == NULL)
901        pathtail = bakfile;
902    else
903        pathtail++;
904    if (strncmp (filename, bakfile, pathtail - bakfile + MAXNAMLEN) != 0)
905        (void) unlink (bakfile);        /* unlink so we can write a new one. */
906#ifdef HAS_RENAME
907    (void) rename (filename, bakfile);
908#else /* HAS_RENAME */
909    if (link (filename, bakfile) == 0)
910        (void) unlink (filename);
911#endif /* HAS_RENAME */
912
913    /* if we can't write new, preserve .bak regardless of xflag */
914    if ((outfile = fopen (filename, "w")) == NULL)
915        {
916        (void) fprintf (stderr, CANT_CREATE, filename);
917        (void) sleep ((unsigned) 2);
918        return;
919        }
920
921    (void) chmod (filename, statbuf->st_mode);
922
923    while ((c = getc (infile)) != EOF)
924        (void) putc (c, outfile);
925
926    (void) fclose (infile);
927    (void) fclose (outfile);
928
929    if (xflag
930      &&  strncmp (filename, bakfile, pathtail - bakfile + MAXNAMLEN) != 0)
931        (void) unlink (bakfile);
932    }
933
934static void expandmode (option)
935    int                 option;         /* How to print: */
936                                        /* 1 = expansions only */
937                                        /* 2 = original line + expansions */
938                                        /* 3 = original paired w/ expansions */
939                                        /* 4 = add length ratio */
940    {
941    char                buf[BUFSIZ];
942    int                 explength;      /* Total length of all expansions */
943    register char *     flagp;          /* Pointer to next flag char */
944    ichar_t             ibuf[BUFSIZ];
945    MASKTYPE            mask[MASKSIZE];
946    char                origbuf[BUFSIZ]; /* Original contents of buf */
947    char                ratiobuf[20];   /* Expansion/root length ratio */
948    int                 rootlength;     /* Length of root word */
949    register int        temp;
950
951    while (xgets (buf, sizeof buf, stdin) != NULL)
952        {
953        rootlength = strlen (buf);
954        if (buf[rootlength - 1] == '\n')
955          buf[--rootlength] = '\0';
956        (void) strcpy (origbuf, buf);
957        if ((flagp = index (buf, hashheader.flagmarker)) != NULL)
958            {
959            rootlength = flagp - buf;
960            *flagp++ = '\0';
961            }
962        if (option == 2  ||  option == 3  ||  option == 4)
963            (void) printf ("%s ", origbuf);
964        if (flagp != NULL)
965            {
966            if (flagp - buf > INPUTWORDLEN)
967                buf[INPUTWORDLEN] = '\0';
968            }
969        else
970            {
971            if ((int) strlen (buf) > INPUTWORDLEN - 1)
972                buf[INPUTWORDLEN] = '\0';
973            }
974        (void) fputs (buf, stdout);
975        if (flagp != NULL)
976            {
977            (void) bzero ((char *) mask, sizeof (mask));
978            while (*flagp != '\0'  &&  *flagp != '\n')
979                {
980                temp = CHARTOBIT ((unsigned char) *flagp);
981                if (temp >= 0  &&  temp <= LARGESTFLAG)
982                    SETMASKBIT (mask, temp);
983                else
984                    (void) fprintf (stderr, BAD_FLAG, (unsigned char) *flagp);
985                flagp++;
986                /* Accept old-format dicts with extra slashes */
987                if (*flagp == hashheader.flagmarker)
988                    flagp++;
989                }
990            if (strtoichar (ibuf, buf, sizeof ibuf, 1))
991                (void) fprintf (stderr, WORD_TOO_LONG (buf));
992            explength = expand_pre (origbuf, ibuf, mask, option, "");
993            explength += expand_suf (origbuf, ibuf, mask, 0, option, "");
994            explength += rootlength;
995            if (option == 4)
996                {
997                (void) sprintf (ratiobuf, " %f",
998                  (double) explength / (double) rootlength);
999                (void) fputs (ratiobuf, stdout);
1000                (void) expand_pre (origbuf, ibuf, mask, 3, ratiobuf);
1001                (void) expand_suf (origbuf, ibuf, mask, 0, 3, ratiobuf);
1002                }
1003            }
1004        (void) putchar ('\n');
1005        }
1006    }
Note: See TracBrowser for help on using the repository browser.