home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / gnu / ispell-4.0-src.lha / ispell-4.0 / ispell.c < prev    next >
C/C++ Source or Header  |  1993-06-01  |  28KB  |  910 lines

  1. /* Copyright (C) 1990, 1993  Free Software Foundation, Inc.
  2.  
  3.    This file is part of GNU ISPELL.
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* ISPELL is an interactive spelling corrector generates a list
  20.    of near misses for each misspelled word.  The direct parantage
  21.    of this version seems to have begun in California in the
  22.    early 70's.  A child of that version was known as SPELL on
  23.    the MIT ITS systems, and later ISPELL on MIT TOPS-20 systems.
  24.    I wrote the first C implementation in 1983, and then developed
  25.    this version in 1988.  See the History section of ispell.texinfo
  26.    for more information.
  27.  
  28.    Pace Willisson
  29.    pace@ai.mit.edu  pace@hx.lcs.mit.edu
  30.    (617) 625-3452
  31.  
  32.    See ChangeLog for further author information. */
  33.  
  34. #include <stdio.h>
  35. #include <ctype.h>
  36. #include <signal.h>
  37.  
  38. #ifdef HAVE_MALLOC_H
  39. #include <malloc.h>
  40. #endif
  41.  
  42. #include "getopt.h"
  43.  
  44. #include "ispell.h"
  45. #include "hash.h"
  46. #include "charset.h"
  47.  
  48. static void show_warranty (NOARGS);
  49. static void show_copying (NOARGS);
  50. static void show_signon (NOARGS);
  51.  
  52. char **lexdecode = NULL;
  53.  
  54. /* this array contains letters to use when generating near misses */
  55. char near_miss_letters[256];
  56. int nnear_miss_letters;
  57.  
  58. /* this array has 1 for any character that is in near_miss_letters */
  59. char near_map[256];
  60.  
  61. enum formatter formatter;
  62.  
  63. /* set to 1 if any interaction takes place */
  64. int interaction_flag = 1;
  65.  
  66. int lflag;
  67. int aflag;
  68. int dflag;
  69. int pflag;
  70. int Sflag;
  71. int askflag;
  72. int Dflag;
  73. int Eflag;
  74. int hflag;
  75. int uflag;
  76. int iflag;
  77. char *dname;
  78. char *privname;
  79. int intr_typed;
  80.  
  81. FILE *sortf;
  82.  
  83.  
  84. void
  85. usage ()
  86. {
  87.   (void) fprintf (stderr, "Usage: ispell [-d dict] [-p privdict] file\n");
  88.   (void) fprintf (stderr, "or:    ispell [-a | -l]\n");
  89.   exit (1);
  90. }
  91.  
  92.  
  93. RETSIGTYPE
  94. intr ()
  95. {
  96.   signal (SIGINT, (RETSIGTYPE (*)()) intr);
  97.   intr_typed = 1;
  98. }
  99.  
  100.  
  101. void
  102. done ()
  103. {
  104.   extern char tempfile[];
  105.  
  106.   if (tempfile[0])
  107.     {
  108.       (void) unlink (tempfile);
  109.       tempfile[0] = 0;
  110.     }
  111.   termuninit ();
  112.   exit (0);
  113. }
  114.  
  115.  
  116. int
  117. main (argc, argv)
  118.   int argc;
  119.   char **argv;
  120. {
  121.   int c;
  122.   extern char *optarg;
  123.   extern int optind;
  124.   char *p;
  125.   int i;
  126.  
  127.   for (i = 0; i < 256; i++)
  128.     if (charset[i].word_component)
  129.       (ctbl + 1)[i] |= LEXLETTER;
  130.  
  131.   /* if invoked by the name 'spell', set uflag */
  132.   if ((p = (char *) strrchr (argv[0], '/')))
  133.     p++;
  134.   else
  135.     p = argv[0];
  136.  
  137.   if (strcmp (p, "spell") == 0)
  138.     {
  139.       uflag = 1;
  140.       lflag = 1;
  141.     }
  142.  
  143.   formatter = formatter_generic;
  144.  
  145.   while ((c = getopt (argc, argv, "alp:d:SDEhuvbixtWC")) != EOF)
  146.     {
  147.       switch (c)
  148.     {
  149.     case 'W':
  150.       show_warranty ();
  151.       exit (0);
  152.     case 'C':
  153.       show_copying ();
  154.       exit (0);
  155.     case 't':
  156.       formatter = formatter_tex;
  157.       break;
  158.       /* traditional spell options */
  159.       /* ignore these */
  160.     case 'v':        /* don't trust original suffix stripper */
  161.     case 'b':        /* check british spelling */
  162.       break;
  163.     case 'i':        /* don't follow any .so's or .nx's */
  164.       iflag = 1;
  165.       break;
  166.       /* case 'l': */
  167.       /* follow nroff .so's, and .nx's into /usr/lib */
  168.       /* in ispell, this means make a list.  luckily,
  169.              * if the user wants old style, lflag is turned
  170.              * on anyway
  171.              */
  172.  
  173.     case 'x':        /* print stems with '='s */
  174.       (void) fprintf (stderr, "-x is not supported\n");
  175.       exit (1);
  176.  
  177.       /* end of traditional options */
  178.  
  179.     case 'u':
  180.       uflag = 1;
  181.       lflag = 1;
  182.       break;
  183.     case 'h':
  184.       hflag = 1;
  185.       break;
  186.     default:
  187.       usage ();
  188.     case 'D':
  189.       Dflag = 1;
  190.       break;
  191.     case 'E':
  192.       Eflag = 1;
  193.       break;
  194.     case 'p':
  195.       pflag = 1;
  196.       privname = optarg;
  197.       break;
  198.     case 'd':
  199.       dflag = 1;
  200.       dname = optarg;
  201.       break;
  202.     case 'a':
  203.       aflag = 1;
  204.       break;
  205.     case 'l':
  206.       lflag = 1;
  207.       break;
  208.     case 'S':
  209.       Sflag = 1;
  210.       break;
  211.     }
  212.     }
  213.  
  214.   if (optind < argc && argv[optind][0] == '+')
  215.     {
  216.       /* this is for traditional spell - add words in
  217.          * named file to OK list
  218.          */
  219.       (void) p_load (argv[optind] + 1, 0);
  220.       optind++;
  221.     }
  222.  
  223.   if (dflag == 0)
  224.     {
  225.       dname = (char *) getenv ("ISPELL_DICTIONARY");
  226.       if (dname == NULL)
  227.     {
  228.       dname = (char *) xmalloc ((unsigned) strlen (DICT_LIB) + 30);
  229.       (void) strcpy (dname, DICT_LIB);
  230.       (void) strcat (dname, "/ispell.dict");
  231.     }
  232.     }
  233.  
  234.   if (access (dname, 4) < 0)
  235.     {
  236.       (void) fprintf (stderr, "can't read dictionary %s\n", dname);
  237.       exit (1);
  238.     }
  239.  
  240.   if (!Dflag && !Eflag && !Sflag && !aflag && !lflag)
  241.     show_signon ();
  242.  
  243.   if (hash_init (dname) < 0)
  244.     {
  245.       (void) fprintf (stderr, "hash_init failed\n");
  246.       exit (1);
  247.     }
  248.  
  249.   if (hflag)
  250.     {
  251.       prhashchain ();
  252.       exit (0);
  253.     }
  254.  
  255.   if (Dflag)
  256.     {
  257.       hash_awrite (stdout);
  258.       exit (0);
  259.     }
  260.  
  261.   if (Eflag)
  262.     {
  263.       hash_ewrite (stdout);
  264.       exit (0);
  265.     }
  266.  
  267.   if (pflag == 0)
  268.     {
  269.       if ((p = (char *) getenv ("HOME")) != NULL)
  270.     {
  271.       privname = (char *) xmalloc ((unsigned) (strlen (p) + 50));
  272.       (void) strcpy (privname, p);
  273.       (void) strcat (privname, "/ispell.words");
  274.     }
  275.     }
  276.  
  277.   if (privname)
  278.     (void) p_load (privname, 1);
  279.  
  280.   if (Sflag)
  281.     {
  282.       submode ();
  283.     }
  284.   else if (aflag)
  285.     {
  286.       askmode (0);
  287.     }
  288.   else if (uflag)
  289.     {
  290.       spellmode (argc, argv, optind);
  291.       exit (0);
  292.     }
  293.   else if (lflag)
  294.     {
  295.       checkfile (stdin, (FILE *) NULL, (long) 0);
  296.       exit (0);
  297.     }
  298.   else
  299.     {
  300.       /* normal interactive mode */
  301.       if (optind == argc)
  302.     {
  303.       askmode (1);
  304.       exit (0);
  305.     }
  306.       signal (SIGINT, (RETSIGTYPE (*)()) intr);
  307.       terminit ();
  308.       while (optind < argc)
  309.     dofile (argv[optind++]);
  310.  
  311.       if (interaction_flag == 0)
  312.     printf ("No errors detected\r\n");
  313.     }
  314.  
  315.   if (privname)
  316.     (void) p_dump (privname);
  317.  
  318.   done ();
  319.   exit (0);
  320. }
  321.  
  322. extern struct sp_corrections corrections;
  323. static char stdoutbuf[BUFSIZ];
  324.  
  325. void
  326. submode (NOARGS)
  327. {
  328.   char buf[BUFSIZ];
  329.   int i;
  330.   int c;
  331.   int len;
  332.  
  333.   signal (SIGINT, SIG_IGN);
  334.   setbuf (stdin, (char *) NULL);
  335.   setbuf (stdout, stdoutbuf);
  336.   (void) printf ("(1 \"%s\")", VERSION_STRING);
  337.  
  338.   while (1)
  339.     {
  340.     again:
  341.       intr_typed = 0;
  342.       putchar ('=');
  343.       fflush (stdout);
  344.  
  345.       if (fgets (buf, sizeof buf, stdin) == NULL)
  346.     break;
  347.       len = strlen (buf);
  348.       if (len && buf[len - 1] == '\n')
  349.     {
  350.       buf[--len] = 0;
  351.     }
  352.       else
  353.     {
  354.       /* line was too long to hold newline -
  355.              * just return an error without otherwise
  356.              * looking at it
  357.              */
  358.       while (1)
  359.         {
  360.           if ((c = getchar ()) == EOF)
  361.         return;
  362.           if (c == '\n')
  363.         {
  364.           (void) printf ("nil\n");
  365.           goto again;
  366.         }
  367.         }
  368.     }
  369.       if (buf[0] == 0)
  370.     continue;
  371.  
  372.       if (buf[0] == ':')
  373.     {
  374.       if (subcmd (buf) < 0)
  375.         (void) printf ("nil\n");
  376.       else
  377.         (void) printf ("t\n");
  378.       continue;
  379.     }
  380.       if (good (buf, strlen (buf), 0))
  381.     {
  382.       (void) printf ("t\n");
  383.     }
  384.       else
  385.     {
  386.       makepossibilities (buf);
  387.       if (corrections.posbuf[0][0])
  388.         {
  389.           (void) printf ("(");
  390.           for (i = 0; i < 10; i++)
  391.         {
  392.           if (corrections.posbuf[i][0] == 0)
  393.             break;
  394.           (void) printf ("\"%s\" ",
  395.                  corrections.posbuf[i]);
  396.         }
  397.           (void) printf (")\n");
  398.         }
  399.       else
  400.         {
  401.           (void) printf ("nil\n");
  402.         }
  403.     }
  404.     }
  405. }
  406.  
  407. struct cmd
  408. {
  409.   char *name;
  410. #ifdef __STDC__
  411.   int (*func) (char *);
  412. #else
  413.   int (*func) ();
  414. #endif
  415. };
  416.  
  417. extern struct cmd subcmds[];
  418.  
  419. int
  420. subcmd (buf)
  421.   char *buf;
  422. {
  423.   char *p;
  424.   struct cmd *cp;
  425.  
  426.   buf++;            /* skip colon */
  427.   for (p = buf; *p && !isspace (*p); p++)
  428.     ;
  429.   if (*p)
  430.     *p++ = 0;
  431.  
  432.   for (cp = subcmds; cp->name; cp++)
  433.     if (strcmp (cp->name, buf) == 0)
  434.       break;
  435.   if (cp->name == NULL)
  436.     return (-1);
  437.  
  438.   return ((*cp->func) (p));
  439. }
  440.  
  441.  
  442. int
  443. cmd_insert (arg)
  444.      char *arg;
  445. {
  446.   return (p_enter (arg, 1, 1));
  447. }
  448.  
  449.  
  450. int
  451. cmd_accept (arg)
  452.   char *arg;
  453.