home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d191 / ispell.lha / ISpell / src.zoo / ispell.c < prev    next >
C/C++ Source or Header  |  1989-02-22  |  28KB  |  1,409 lines

  1. /* -*- Mode:Text -*- */
  2.  
  3. #define MAIN
  4.  
  5. /*
  6.  * ispell.c - An interactive spelling corrector.
  7.  *
  8.  * Copyright (c), 1983, by Pace Willisson
  9.  * Permission for non-profit use is hereby granted.
  10.  * All other rights reserved.
  11.  *
  12.  * 1987, Robert McQueer, added:
  13.  *    -w option & handling of extra legal word characters
  14.  *    -d option for alternate dictionary file
  15.  *    -p option & WORDLIST variable for alternate personal dictionary
  16.  *    -x option to suppress .bak files.
  17.  *    8 bit text & config.h parameters
  18.  * 1987, Geoff Kuenning, added:
  19.  *    -c option for creating suffix suggestions from raw words
  20.  *    suffixes in personal dictionary file
  21.  *    hashed personal dictionary file
  22.  *    -S option for unsorted word lists
  23.  * 1987, Greg Schaffer, added:
  24.  *    -T option (for TeX and LaTeX instead of troff) [later changed to -t]
  25.  *       passes over \ till next whitespace.
  26.  *       does not recognize % (comment)
  27.  * 1989, Tomas Rokicki, added:
  28.  *      ispell'local'words to indicate rest of line for local words
  29.  *      -L option to write local words when done
  30.  *      fixed `sleep' so some error messages could be seen.
  31.  */
  32.  
  33. #include <stdio.h>
  34. #include <ctype.h>
  35. #ifdef AMIGA
  36. #include <stat.h>
  37. #else
  38. #include <sys/param.h>
  39. #ifdef USG
  40. #include <sys/types.h>
  41. #endif
  42. #include <sys/stat.h>
  43. #endif
  44. #include "config.h"
  45. #include "ispell.h"
  46. #include "version.h"
  47.  
  48. #define ISTEXTERM(c)   (((c) == '{') || \
  49.             ((c) == '}') || \
  50.             ((c) == '[') || \
  51.             ((c) == ']'))
  52.  
  53. FILE *infile;
  54. FILE *outfile;
  55.  
  56. char hashname[MAXPATHLEN];
  57.  
  58. extern struct dent *treeinsert();
  59. extern char *upcase ();
  60. extern char *lowcase ();
  61.  
  62. extern char *rindex();
  63. extern char *strcpy ();
  64.  
  65. /*
  66. ** we use extended character set range specifically to allow intl.
  67. ** character set characters.  We are being REALLY paranoid about indexing
  68. ** this array - explicitly cast into unsigned INTEGER, then mask
  69. ** If NO8BIT is set, text will be masked to ascii range.
  70. */
  71. static int Trynum;
  72. #ifdef NO8BIT
  73. static char Try[128];
  74. static char Checkch[128];
  75. #define iswordch(X) (Checkch[((unsigned)(X))&0x7f])
  76. #else
  77. static char Try[256];
  78. static char Checkch[256];
  79. #define iswordch(X) (Checkch[((unsigned)(X))&0xff])
  80. #endif
  81.  
  82. static int sortit = 1;
  83.  
  84. givehelp ()
  85. {
  86.     erase ();
  87.     printf ("Whenever a word is found that is not in the dictionary,\r\n");
  88.     printf ("it is printed on the first line of the screen.  If the dictionary\r\n");
  89.     printf ("contains any similar words, they are listed with a single digit\r\n");
  90.     printf ("next to each one.  You have the option of replacing the word\r\n");
  91.     printf ("completely, or choosing one of the suggested words.\r\n");
  92.     printf ("\r\n");
  93.     printf ("Commands are:\r\n\r\n");
  94.     printf ("R       Replace the misspelled word completely.\r\n");
  95.     printf ("Space   Accept the word this time only\r\n");
  96.     printf ("A       Accept the word for the rest of this file.\r\n");
  97.     printf ("I       Accept the word, and put it in your private dictionary.\r\n");
  98.     printf ("0-9     Replace with one of the suggested words.\r\n");
  99.     printf ("L       Look up words in system dictionary.\r\n");
  100.     printf ("Q       Write the rest of this file, ignoring misspellings, ");
  101.     printf (         "and start next file.\r\n");
  102.     printf ("X       Exit immediately.  Asks for confirmation.  ");
  103.     printf (         "Leaves file unchanged.\r\n");
  104.     printf ("!       Shell escape.\r\n");
  105.     printf ("^L      Redraw screen.\r\n");
  106.     printf ("\r\n\r\n");
  107.     printf ("-- Type space to continue --");
  108.     fflush (stdout);
  109.     while (getchar () != ' ')
  110.         ;
  111. }
  112.  
  113.  
  114. char *getline();
  115.  
  116. int cflag = 0;
  117. int lflag = 0;
  118. int incfileflag = 0;
  119. int aflag = 0;
  120. int fflag = 0;
  121. #ifndef USG
  122. int sflag = 0;
  123. #endif
  124. int xflag = 0;
  125. int tflag = 0;
  126. int llflag = 0 ;
  127.  
  128. char *askfilename;
  129.  
  130. static char *Cmd;
  131.  
  132. usage ()
  133. {
  134.     fprintf (stderr,
  135.         "Usage: %s [-dfile | -pfile | -wchars | -t | -x | -S] file .....\n",
  136.         Cmd);
  137.     fprintf (stderr,
  138.         "       %s [-dfile | -pfile | -wchars | -t] -l\n",
  139.         Cmd);
  140. #ifndef USG
  141.     fprintf (stderr,
  142.         "       %s [-dfile | -pfile | -ffile | -t | -s] {-a | -A}\n",
  143.         Cmd);
  144. #else
  145.     fprintf (stderr,
  146.         "       %s [-dfile | -pfile | -ffile | -t] {-a | -A}\n",
  147.         Cmd);
  148. #endif
  149.     fprintf (stderr, "       %s [-wchars] -c\n", Cmd);
  150.     fprintf (stderr, "       %s -v\n", Cmd);
  151.     exit (1);
  152. }
  153.  
  154. static initckch()
  155. {
  156.     register int c;
  157.  
  158.     Trynum = 0;
  159. #ifdef NO8BIT
  160.     for (c = 0; c < 128; ++c) {
  161. #else
  162.     for (c = 0; c < 256; ++c) {
  163. #endif
  164.         if (myalpha((char) c)) {
  165.             Checkch[c] = (char) 1;
  166.             if (myupper((char) c)) {
  167.                 Try[Trynum] = (char) c;
  168.                 ++Trynum;
  169.             }
  170.         }
  171.         else
  172.             Checkch[c] = (char) 0;
  173.     }
  174. }
  175.  
  176. main (argc, argv)
  177. char **argv;
  178. {
  179.     char *p;
  180.     char *cpd;
  181.     char num[4];
  182.     unsigned mask;
  183.     static char outbuf[BUFSIZ];
  184.  
  185. #ifdef AMIGA
  186.     _Heapsize = HEAPSIZE;
  187. #endif
  188.  
  189.     Cmd = *argv;
  190.  
  191.     initckch();
  192.     sprintf(hashname,"%s/%s",LIBDIR,DEFHASH);
  193.  
  194.     cpd = NULL;
  195.  
  196.     argv++;
  197.     argc--;
  198.     while (argc && **argv == '-') {
  199.         switch ((*argv)[1]) {
  200.         case 'v':
  201.             printf ("%s\n", Version_ID);
  202.             exit (0);
  203.         case 't':
  204.             tflag++;
  205.             break;
  206.         case 'A':
  207.             incfileflag = 1;
  208.             aflag = 1;
  209.             break;
  210.         case 'a':
  211.             aflag++;
  212.             break;
  213.         case 'c':
  214.             cflag++;
  215.             lflag++;
  216.             break;
  217.         case 'x':
  218.             xflag++;
  219.             break;
  220.         case 'f':
  221.             fflag++;
  222.             p = (*argv)+2;
  223.             if (*p == '\0') {
  224.                 argv++; argc--;
  225.                 if (argc == 0)
  226.                     usage ();
  227.                 p = *argv;
  228.             }
  229.             askfilename = p;
  230.             break;
  231.         case 'l':
  232.             lflag++;
  233.             break;
  234.                 case 'L':
  235.                         llflag++ ;
  236.                         break ;
  237. #ifndef USG
  238.         case 's':
  239.             sflag++;
  240.             break;
  241. #endif
  242.         case 'S':
  243.             sortit = 0;
  244.             break;
  245.         case 'p':
  246.             cpd = (*argv)+2;
  247.             if (*cpd == '\0') {
  248.                 argv++; argc--;
  249.                 if (argc == 0)
  250.                     usage ();
  251.                 cpd = *argv;
  252.             }
  253.             break;
  254.         case 'd':
  255.             p = (*argv)+2;
  256.             if (*p == '\0') {
  257.                 argv++; argc--;
  258.                 if (argc == 0)
  259.                     usage ();
  260.                 p = *argv;
  261.             }
  262.             if (*p == '/')
  263.                 strcpy(hashname,p);
  264.             else
  265.                 sprintf(hashname,"%s/%s",LIBDIR,p);
  266.             break;
  267.         case 'w':
  268.             num[3] = '\0';
  269. #ifdef NO8BIT
  270.             mask = 0x7f;
  271. #else
  272.             mask = 0xff;
  273. #endif
  274.             p = (*argv)+2;
  275.             if (*p == '\0') {
  276.                 argv++; argc--;
  277.                 if (argc == 0)
  278.                     usage ();
  279.                 p = *argv;
  280.             }
  281.             while (Trynum <= mask && *p != '\0') {
  282.                 if (*p != 'n'  &&  *p != '\\') {
  283.                     Checkch[((unsigned)(*p))&mask] = (char) 1;
  284.                     Try[Trynum] = *p & mask;
  285.                     ++p;
  286.                 }
  287.                 else {
  288.                     ++p;
  289.                     num[0] = '\0'; 
  290.                     num[1] = '\0'; 
  291.                     num[2] = '\0'; 
  292.                     num[3] = '\0';
  293.                     if (isdigit (p[0]))
  294.                         num[0] = p[0];
  295.                     if (isdigit (p[1]))
  296.                         num[1] = p[1];
  297.                     if (isdigit (p[2]))
  298.                         num[2] = p[2];
  299.                     if (p[-1] == 'n') {
  300.                         p += strlen (num);
  301.                         num[0] = atoi (num);
  302.                     }
  303.                     else {
  304.                         p += strlen (num);
  305.                         if (num[0])
  306.                             num[0] -= '0';
  307.                         if (num[1]) {
  308.                             num[0] <<= 3;
  309.                             num[0] += num[1] - '0';
  310.                         }
  311.                         if (num[2]) {
  312.                             num[0] <<= 3;
  313.                             num[0] += num[2] - '0';
  314.                         }
  315.                     }
  316.                     Try[Trynum] = num[0] & mask;
  317.                     Checkch[num[0] & mask] = 1;
  318.                 }
  319.                 ++Trynum;
  320.             }
  321.             break;
  322.         default:
  323.             usage();
  324.         }
  325.         argv++; argc--;
  326.     }
  327.  
  328.     if (!argc && !lflag && !aflag)
  329.         usage ();
  330.  
  331.     if (linit () < 0)
  332.         exit (0);
  333.  
  334.     treeinit (cpd);
  335.  
  336.     if (aflag) {
  337.         askmode ();
  338.         exit (0);
  339.     }
  340.  
  341.     setbuf (stdout, outbuf);
  342.     if (lflag) {
  343.         infile = stdin;
  344.         checkfile ();
  345.         exit (0);
  346.     }
  347.  
  348.     terminit ();
  349.  
  350.     while (argc--)
  351.         dofile (*argv++);
  352.  
  353.     done ();
  354. }
  355.  
  356. char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
  357. char *currentchar;
  358. char token[BUFSIZ];
  359.  
  360. int quit;
  361.  
  362. char *currentfile = NULL;
  363.  
  364. dofile (filename)
  365. char *filename;
  366. {
  367.     int c;
  368.     char    bakfile[256];
  369.     struct stat statbuf;
  370.     char *cp;
  371.  
  372.     currentfile = filename;
  373.  
  374.     if ((infile = fopen (filename, "r")) == NULL) {
  375.         fprintf (stderr, "Can't open %s\r\n", filename);
  376.         sleep (2);
  377.         return;
  378.     }
  379.  
  380.     if (access (filename, 2) < 0) {
  381.         fprintf (stderr, "Can't write to %s\r\n", filename);
  382.         sleep (2);
  383.         return;
  384.     }
  385.  
  386. #ifndef AMIGA
  387.     fstat (fileno (infile), &statbuf);
  388. #endif
  389.     strcpy(tempfile, TEMPNAME);
  390.     mktemp (tempfile);
  391. #ifndef AMIGA    
  392.      chmod (tempfile, statbuf.st_mode);
  393. #endif
  394.     if ((outfile = fopen (tempfile, "w")) == NULL) {
  395.         fprintf (stderr, "Can't create %s\r\n", tempfile);
  396.         sleep (2);
  397.         return;
  398.     }
  399.  
  400.     quit = 0;
  401.  
  402.     /* See if the file is a .tex file.  If so, set the appropriate flag. */
  403.     if ((cp = rindex (filename, '.')) != NULL  &&  strcmp (cp, ".tex") == 0)
  404.         tflag = 1;
  405.     checkfile ();
  406.  
  407.     fclose (infile);
  408.     fclose (outfile);
  409.  
  410.     if (!cflag)
  411.         treeoutput ();
  412.  
  413.     if ((infile = fopen (tempfile, "r")) == NULL) {
  414.         fprintf (stderr, "temporary file disappeared (%s)\r\n", tempfile);    
  415.         sleep (2);
  416.         return;
  417.     }
  418.  
  419.     sprintf(bakfile, "%s%s", filename, BAKEXT);
  420.     if(link(filename, bakfile) == 0)
  421.         unlink(filename);
  422.  
  423.     /* if we can't write new, preserve .bak regardless of xflag */
  424.     if ((outfile = fopen (filename, "w")) == NULL) {
  425.         fprintf (stderr, "can't create %s\r\n", filename);
  426.         sleep (2);
  427.         return;
  428.     }
  429.  
  430. #ifndef AMIGA
  431.     chmod (filename, statbuf.st_mode);
  432. #endif
  433.  
  434.     while ((c = getc (infile)) != EOF)
  435.         putc (c, outfile);
  436.  
  437.     fclose (infile);
  438.     fclose (outfile);
  439.  
  440.     unlink (tempfile);
  441.     if (xflag)
  442.         unlink(bakfile);
  443. }
  444.  
  445. checkfile ()
  446. {
  447.     register int c;
  448.     register char *p;
  449.     register int len;
  450.         int addflag ;
  451.  
  452.     secondbuf[0] = 0;
  453.  
  454.     while (1) {
  455.         strcpy (firstbuf, secondbuf);
  456.         if (quit) {    /* quit can't be set in l mode */
  457.             while (fgets (secondbuf, sizeof secondbuf, infile) != NULL)
  458.                 fputs (secondbuf, outfile);
  459.             break;
  460.         }
  461.  
  462.         if (fgets (secondbuf, sizeof secondbuf, infile) == NULL)
  463.             break;
  464.         currentchar = secondbuf;
  465.         addflag = 0 ;
  466.         len = strlen (secondbuf) - 1;
  467.  
  468.         if(!tflag) {
  469.             /* skip over .if */
  470.             if (strncmp(currentchar,".if t",5) == 0 
  471.             ||  strncmp(currentchar,".if n",5) == 0) {
  472.                 copyout(¤tchar,5);
  473.                 while (*currentchar && isspace(*currentchar)) 
  474.                     copyout(¤tchar, 1);
  475.             }
  476.  
  477.             /* skip over .ds XX or .nr XX */
  478.             if (strncmp(currentchar,".ds ",4) == 0 
  479.             ||  strncmp(currentchar,".de ",4) == 0
  480.             ||  strncmp(currentchar,".nr ",4) == 0) {
  481.                 copyout(¤tchar, 3);
  482.                 while (*currentchar && isspace(*currentchar)) 
  483.                     copyout(¤tchar, 1);
  484.                 while (*currentchar && !isspace(*currentchar))
  485.                     copyout(¤tchar, 1);
  486.                 if (*currentchar == 0) {
  487.                     if (!lflag) putc ('\n', outfile);
  488.                     continue;
  489.                 }
  490.             }
  491.         }
  492.  
  493.         if (secondbuf [ len ] == '\n')
  494.             secondbuf [ len ] = 0;
  495.  
  496.         /* if this is a formatter command, skip over it */
  497.         if (!tflag && *currentchar == '.') {
  498.             while (*currentchar && !myspace (*currentchar)) {
  499.                 if (!lflag)
  500.                     putc (*currentchar, outfile);
  501.                 currentchar++;
  502.             }
  503.             if (*currentchar == 0) {
  504.                 if (!lflag)
  505.                     putc ('\n', outfile);
  506.                 continue;
  507.             }
  508.         }
  509.  
  510.         while (1) {
  511.             while (*currentchar && !iswordch(*currentchar)) {
  512.                 if (tflag)        /* TeX or LaTeX stuff */
  513.                 {
  514.                 if (*currentchar == '\\') {
  515.                     /* skip till whitespace */
  516.                     while (*currentchar && 
  517.                     (!isspace(*currentchar) &&
  518.                      !ISTEXTERM(*currentchar))) {
  519.                         if (!lflag)
  520.                         putc(*currentchar, outfile);
  521.                         currentchar++;
  522.                     }
  523.                     continue;
  524.                 }
  525.                 }
  526.                 else
  527.                 {
  528.                 /* formatting escape sequences */
  529.                 if (*currentchar == '\\') {
  530.                 switch ( currentchar [1] ) {
  531.                 case 'f':
  532.                     if(currentchar[2] != '(') {
  533.                         /* font change: \fX */
  534.                         copyout(¤tchar, 3);
  535.                     }
  536.                     else {
  537.                         /* font change: \f(XY */
  538.                         copyout(¤tchar, 5);
  539.                     }
  540.                     continue;
  541.                 case 's':
  542.                     /* size change */
  543.                     p = currentchar + 2;
  544.                     if (*p == '+'  ||  *p == '-')
  545.                         p++;
  546.                     /* This looks wierd 'cause we assume
  547.                     ** *p is now a digit.
  548.                     */
  549.                     if (isdigit (p[1]))
  550.                         p++;
  551.                     copyout (¤tchar,
  552.                             p - currentchar + 1);
  553.                     continue;
  554.                 case '(':
  555.                     /* extended char set escape: \(XX */
  556.                     copyout(¤tchar, 4);
  557.                     continue;
  558.                 case '*':
  559.                     if ( currentchar[2] != '(' )
  560.                         copyout(¤tchar, 3);
  561.                     else
  562.                         copyout(¤tchar, 5);
  563.                     continue;
  564.                 default:
  565.                     break;
  566.                     }
  567.                 }
  568.                 }
  569.  
  570.                 if (!lflag)
  571.                     putc (*currentchar, outfile);
  572.                 currentchar++;
  573.             }
  574.  
  575.             if (*currentchar == 0)
  576.                 break;
  577.  
  578.             p = token;
  579.             while (iswordch(*currentchar) ||
  580.                    (*currentchar == '\'' &&
  581.                 iswordch(*(currentchar + 1))))
  582.               *p++ = *currentchar++;
  583.             *p = 0;
  584. /*
  585.  *   mods by tom rokicki to handle local document words automagically
  586.  */
  587.             if (token[0] == 'i' &&
  588.                             strcmp(token, "ispell'local'words")==0) {
  589.                            addflag = 1 ;
  590.                         } else {
  591.                if (addflag) {
  592.                   if (! good(token)) {
  593.                      treeinsert(token, 0) ;
  594.                               }
  595.                            }
  596.                if (lflag) {
  597.                    if (!good (token)  &&  !cflag)
  598.                        printf ("%s\n", token);
  599.                } else {
  600.                    if (!quit)
  601.                    correct (token, ¤tchar);
  602.                }
  603.             }
  604.             if (!lflag)
  605.                 fprintf (outfile, "%s", token);
  606.         }   
  607.         if (!lflag)
  608.             putc ('\n', outfile);
  609.     }
  610.     if (llflag) {
  611.        lldump() ;
  612.         }
  613. }
  614.  
  615. #define MAXPOSSIBLE    100    /* Max no. of possibilities to generate */
  616.  
  617. char possibilities[MAXPOSSIBLE][BUFSIZ];
  618. int pcount;
  619. int maxposslen;
  620.  
  621. correct (token, currentchar)
  622. char *token;
  623. char **currentchar;
  624. {
  625.     register int c;
  626.     register int i;
  627.     int col_ht;
  628.     int ncols;
  629.     register char *p;
  630.     char *start_l2;
  631.     char *begintoken;
  632.  
  633.     begintoken = *currentchar - strlen (token);
  634.  
  635. checkagain:
  636.     if (good (token))
  637.         return;
  638.  
  639.     erase ();
  640.     printf ("    %s", token);
  641.     if (currentfile)
  642.         printf ("              File: %s", currentfile);
  643.     printf ("\r\n\r\n");
  644.  
  645.     makepossibilities (token);
  646.  
  647.     /*
  648.      * Make sure we have enough room on the screen to hold the
  649.      * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
  650.      * is the maximum number of columns that will fit.
  651.      */
  652.     col_ht = li - 6;        /* Height of columns of words */
  653.     ncols = co / (maxposslen + 8);
  654.     if (pcount > ncols * col_ht)
  655.         pcount = ncols * col_ht;
  656.  
  657. #ifdef EQUAL_COLUMNS
  658.     /*
  659.      * Equalize the column sizes.  The last column will be short.
  660.      */
  661.     col_ht = (pcount + ncols - 1) / ncols;
  662. #endif
  663.  
  664.     for (i = 0; i < pcount; i++) {
  665.         move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
  666.         printf ("%2d: %s", i, possibilities[i]);
  667.     }
  668.  
  669.     move (li - 3, 0);
  670.     show_line (firstbuf, firstbuf, 0);
  671.  
  672.     start_l2 = secondbuf;
  673.     if (line_size (secondbuf, *currentchar) > co - 1) {
  674.         start_l2 = begintoken - (co / 2);
  675.         while (start_l2 < begintoken) {
  676.             i = line_size (start_l2, *currentchar) + 1;
  677.             if (i <= co)
  678.                 break;
  679.             start_l2 += i - co;
  680.         }
  681.         if (start_l2 > begintoken)
  682.             start_l2 = begintoken;
  683.         if (start_l2 < secondbuf)
  684.             start_l2 = secondbuf;
  685.     }
  686.     show_line (start_l2, begintoken, strlen (token));
  687.  
  688.  
  689.     while (1) {
  690.         fflush (stdout);
  691.         switch (c = (getchar () & NOPARITY)) {
  692. #ifndef USG
  693.         case 'Z' & 037:
  694.             stop ();
  695.             erase ();
  696.             goto checkagain;
  697. #endif
  698.         case ' ':
  699.             erase ();
  700.             fflush (stdout);
  701.             return;
  702.         case 'x': case 'X':
  703.             printf ("Are you sure you want to throw away your changes? ");
  704.             fflush (stdout);
  705.             c = (getchar () & NOPARITY);
  706.             if (c == 'y' || c == 'Y') {
  707.                 erase ();
  708.                 fflush (stdout);
  709.                 done ();
  710.             }
  711.             putchar (7);
  712.             goto checkagain;
  713.         case 'i': case 'I':
  714.             treeinsert (token, 1);
  715.             erase ();
  716.             fflush (stdout);
  717.             return;
  718.         case 'a': case 'A':
  719.             treeinsert (token, 0);
  720.             if (llflag)
  721.                llinsert(token) ;
  722.             erase ();
  723.             fflush (stdout);
  724.             return;
  725.         case 'L' & 037:
  726.             goto checkagain;
  727.         case '?':
  728.             givehelp ();
  729.             goto checkagain;
  730.         case '!':
  731.             {
  732.                 char buf[200];
  733.                 move (li - 1, 0);
  734.                 putchar ('!');
  735.                 if (getline (buf) == NULL) {
  736.                     putchar (7);
  737.                     erase ();
  738.                     fflush (stdout);
  739.                     goto checkagain;
  740.                 }
  741.                 printf ("\r\n");
  742.                 fflush (stdout);
  743.                 shellescape (buf);
  744.                 erase ();
  745.                 goto checkagain;
  746.             }
  747.         case 'r': case 'R':
  748.             move (li - 1, 0);
  749.             printf ("Replace with: ");
  750.             if (getline (token) == NULL) {
  751.                 putchar (7);
  752.                 erase ();
  753.                 goto checkagain;
  754.             }
  755.             inserttoken (secondbuf, begintoken, token, currentchar);
  756.             erase ();
  757.             goto checkagain;
  758.         case '0': case '1': case '2': case '3': case '4':
  759.         case '5': case '6': case '7': case '8': case '9':
  760.             i = c - '0';
  761.             if (pcount > 10
  762.                 &&  i > 0  &&  i <= (pcount - 1) / 10) {
  763.                 c = getchar () & NOPARITY;
  764.                 if (c >= '0'  &&  c <= '9')
  765.                     i = i * 10 + c - '0';
  766.                 else if (c != '\r'  &&  c != '\n') {
  767.                     putchar (7);
  768.                     break;
  769.                 }
  770.             }
  771.             if (i < pcount) {
  772.                 strcpy (token, possibilities[i]);
  773.                 inserttoken (secondbuf, begintoken,
  774.                     token, currentchar);
  775.                 erase ();
  776.                 return;
  777.             }
  778.             putchar (7);
  779.             break;
  780.         case '\r':    /* This makes typing \n after single digits */
  781.         case '\n':    /* ..less obnoxious */
  782.             break;
  783.         case 'l': case 'L':
  784.             {
  785.                 char buf[100];
  786.                 move (li - 1, 0);
  787.                 printf ("Lookup string ('*' is wildcard): ");
  788.                 if (getline (buf) == NULL) {
  789.                     putchar (7);
  790.                     erase ();
  791.                     goto checkagain;
  792.                 }
  793.                 printf ("\r\n\r\n");
  794.                 fflush (stdout);
  795.                 lookharder (buf);
  796.                 erase ();
  797.                 goto checkagain;
  798.             }
  799.         case 'q': case 'Q':
  800.             quit = 1;
  801.             erase ();
  802.             fflush (stdout);
  803.             return;
  804.         default:
  805.             putchar (7);
  806.             break;
  807.         }
  808.     }
  809. }
  810.  
  811. show_line (line, invstart, invlen)
  812. register char *line;
  813. register char *invstart;
  814. register int invlen;
  815. {
  816.     register int width;
  817.  
  818.     width = 0;
  819.     while (line != invstart  &&  width < co - 1)
  820.         width += show_char (*line++, width);
  821.     if (invlen) {
  822.         inverse ();
  823.         while (--invlen >= 0  &&  width < co - 1)
  824.             width += show_char (*line++, width);
  825.         normal ();
  826.     }
  827.     while (*line  &&  width < co - 1)
  828.         width += show_char (*line++, width);
  829.     printf ("\r\n");
  830. }
  831.  
  832. show_char (ch, linew)
  833. register int ch;
  834. int linew;
  835. {
  836.     if (ch == '\t') {
  837.         putchar ('\t');
  838.         return 8 - (linew & 0x07);
  839.     }
  840.     else if (ch < ' ') {
  841.         putchar ('^');
  842.         putchar (ch + 'A' - '\001');
  843.         return 2;
  844.     }
  845.     putchar (ch);
  846.     return 1;
  847. }
  848.  
  849. line_size (buf, bufend)
  850. register char *buf;
  851. register char *bufend;
  852. {
  853.     register int width;
  854.  
  855.     for (width = 0;  buf < bufend  &&  *buf;  buf++) {
  856.         if (*buf == '\t')
  857.             width = (width + 8) & ~0x07;
  858.         else if (*buf < ' ')
  859.             width += 2;
  860.         else
  861.             width++;
  862.     }
  863.     return width;
  864. }
  865.  
  866. inserttoken (buf, start, token, currentchar)
  867. char *buf, *start; 
  868. register char *token;
  869. char **currentchar;
  870. {
  871.     char copy[BUFSIZ];
  872.     register char *p, *q;
  873.  
  874.     strcpy (copy, buf);
  875.  
  876.     for (p = buf, q = copy; p != start; p++, q++)
  877.         *p = *q;
  878.     q += *currentchar - start;
  879.     while (*token  &&  iswordch (*token))
  880.         *p++ = *token++;
  881.     *currentchar = p;
  882.     if (*token) {
  883.  
  884.         /*
  885.         ** The token changed to two words.  Split it up and save the
  886.         ** second one for later.
  887.         */
  888.  
  889.         *p++ = *token;
  890.         *token++ = '\0';
  891.         while (*token)
  892.             *p++ = *token++;
  893.     }
  894.     while (*p++ = *q++)
  895.         ;
  896. }
  897.  
  898. int casecmp (a, b)
  899. char *a;
  900. char *b;
  901. {
  902.     register char *ap;
  903.     register char *bp;
  904.  
  905.     for (ap = a, bp = b;  *ap;  ap++, bp++) {
  906.         if (mylower (*ap)) {
  907.             if (mylower (*bp)) {
  908.                 if (*ap != *bp)
  909.                     return *ap - *bp;
  910.             }
  911.             else {
  912.                 if (toupper (*ap) != *bp)
  913.                     return toupper (*ap) - *bp;
  914.             }
  915.         }
  916.         else {
  917.             if (myupper (*bp)) {
  918.                 if (*ap != *bp)
  919.                     return *ap - *bp;
  920.             }
  921.             else {
  922.                 if (tolower (*ap) != *bp)
  923.                     return tolower (*ap) - *bp;
  924.             }
  925.         }
  926.     }
  927.     if (*bp != '\0')
  928.         return -*bp;
  929.     return strcmp (a, b);
  930. }
  931.  
  932. makepossibilities (word)
  933. register char *word;
  934. {
  935.     register int i;
  936.  
  937.     for (i = 0; i < MAXPOSSIBLE; i++)
  938.         possibilities[i][0] = 0;
  939.     pcount = 0;
  940.     maxposslen = 0;
  941.  
  942. #ifdef CAPITALIZE
  943.     wrongcapital (word);
  944. #endif
  945.     if (pcount < MAXPOSSIBLE) wrongletter (word);
  946.     if (pcount < MAXPOSSIBLE) extraletter (word);
  947.     if (pcount < MAXPOSSIBLE) missingletter (word);
  948.     if (pcount < MAXPOSSIBLE) transposedletter (word);
  949.  
  950.     if (sortit  &&  pcount)
  951.         qsort ((char *) possibilities, pcount,
  952.             sizeof (possibilities[0]), casecmp);
  953. }
  954.  
  955. insert (word)
  956. register char *word;
  957. {
  958.     register int i;
  959.  
  960.     for (i = 0; i < pcount; i++)
  961.         if (strcmp (possibilities[i], word) == 0)
  962.             return (0);
  963.  
  964.     strcpy (possibilities[pcount++], word);
  965.     i = strlen (word);
  966.     if (i > maxposslen)
  967.         maxposslen = i;
  968.     if (pcount >= MAXPOSSIBLE)
  969.         return (-1);
  970.     else
  971.         return (0);
  972. }
  973.  
  974. #ifdef CAPITALIZE
  975. wrongcapital (word)
  976. register char *word;
  977. {
  978.     char newword[BUFSIZ];
  979.  
  980.     /*
  981.     ** All-uppercase is always legal.  If the word matches, "ins_cap"
  982.     ** will recapitalize it correctly.
  983.     */
  984.     strcpy (newword, word);
  985.     upcase (newword);
  986.     if (good (newword))
  987.         return ins_cap (newword, word);
  988.     return 0;
  989. }
  990. #endif
  991.  
  992. wrongletter (word)
  993. register char *word;
  994. {
  995.     register int i, j, c, n;
  996.     char newword[BUFSIZ];
  997.  
  998.     n = strlen (word);
  999.     strcpy (newword, word);
  1000. #ifdef CAPITALIZE
  1001.     upcase (newword);
  1002. #endif
  1003.  
  1004.     for (i = 0; i < n; i++) {
  1005.         for (j=0; j < Trynum; ++j) {
  1006.             newword[i] = Try[j];
  1007.             if (good (newword)) {
  1008.                 if (ins_cap (newword, word) < 0)
  1009.                     return;
  1010.             }
  1011.         }
  1012. #ifdef CAPITALIZE
  1013.         c = word[i];
  1014.         if (islower (c))
  1015.             newword[i] = toupper (c);
  1016.         else
  1017.             newword[i] = c;
  1018. #else
  1019.         newword[i] = word[i];
  1020. #endif
  1021.     }
  1022. }
  1023.  
  1024. extraletter (word)
  1025. register char *word;
  1026. {
  1027.     char newword[BUFSIZ];
  1028.     register char *p, *s, *t;
  1029.  
  1030.     if (strlen (word) < 3)
  1031.         return;
  1032.  
  1033.     for (p = word; *p; p++) {
  1034.         for (s = word, t = newword; *s; s++)
  1035.             if (s != p)
  1036.                 *t++ = *s;
  1037.         *t = 0;
  1038. #ifdef CAPITALIZE
  1039.         if (good (upcase (newword))) {
  1040.             if (ins_cap (newword, word) < 0)
  1041.                 return;
  1042.         }
  1043. #else
  1044.         if (good (newword)) {
  1045.             if (ins_cap (newword, word) < 0)
  1046.                 return;
  1047.         }
  1048. #endif
  1049.     }
  1050. }
  1051.  
  1052. missingletter (word)
  1053. char word[];
  1054. {
  1055.     char newword[BUFSIZ]; 
  1056.     register char *p, *r, *s, *t;
  1057.     register int i;
  1058.  
  1059.     for (p = word; p == word || p[-1]; p++) {
  1060.         for (s = newword, t = word; t != p; s++, t++)
  1061.             *s = *t;
  1062.         r = s++;
  1063.         while (*t)
  1064.             *s++ = *t++;
  1065.         *s = 0;
  1066.         for (i=0; i < Trynum; ++i) {
  1067.             *r = Try[i];
  1068. #ifdef CAPITALIZE
  1069.             if (good (upcase (newword))) {
  1070.                 if (ins_cap (newword, word) < 0)
  1071.                     return;
  1072.             }
  1073. #else
  1074.             if (good (newword)) {
  1075.                 if (ins_cap (newword, word) < 0)
  1076.                     return;
  1077.             }
  1078. #endif
  1079.         }
  1080.     }
  1081. }
  1082.  
  1083. transposedletter (word)
  1084. register char *word;
  1085. {
  1086.     char newword[BUFSIZ];
  1087.     register int t;
  1088.     register char *p;
  1089.  
  1090.     strcpy (newword, word);
  1091.     for (p = newword; p[1]; p++) {
  1092.         t = p[0];
  1093.         p[0] = p[1];
  1094.         p[1] = t;
  1095. #ifdef CAPITALIZE
  1096.         if (good (upcase (newword))) {
  1097.             if (ins_cap (newword, word) < 0)
  1098.                 return;
  1099.         }
  1100. #else
  1101.         if (good (newword)) {
  1102.             if (ins_cap (newword, word) < 0)
  1103.                 return;
  1104.         }
  1105. #endif
  1106.         t = p[0];
  1107.         p[0] = p[1];
  1108.         p[1] = t;
  1109.     }
  1110. }
  1111.  
  1112. /* Insert one or more correctly capitalized versions of pattern */
  1113. ins_cap (word, pattern)
  1114. register char *word, *pattern;
  1115. {
  1116.     static char newword[BUFSIZ];
  1117.     register char *p, *q;
  1118.     char *psave;
  1119.     register int wcount;
  1120.  
  1121.     if (*word == 0)
  1122.         return;
  1123.  
  1124.     strcpy (newword, word);
  1125. #ifdef CAPITALIZE
  1126.     if (lastdent->allcaps)
  1127.         return insert (upcase (newword)); /* Uppercase required */
  1128.     for (p = pattern;  *p;  p++)
  1129.         if (mylower (*p))
  1130.             break;
  1131.     if (*p == '\0')
  1132.         return insert (upcase (newword)); /* Pattern was all caps */
  1133.     for (p = pattern;  *p;  p++)
  1134.         if (myupper (*p))
  1135.             break;
  1136.     if (*p == '\0') {            /* Pattern was all lower */
  1137.         if (!lastdent->followcase  &&  !lastdent->capitalize)
  1138.             return insert (lowcase (newword));
  1139.         /*
  1140.         ** If there's a followcase version that's all-lower,
  1141.         ** insert only that version.
  1142.         */
  1143.         if (lastdent->followcase) {
  1144.             p = lastdent->word;
  1145.             p += strlen (p) + 1;
  1146.             wcount = (*p++ & 0xFF);
  1147.             while (--wcount >= 0) {
  1148.                 for (psave = ++p;
  1149.                     *p  &&  !myupper (*p);
  1150.                     p++)
  1151.                     ;
  1152.                 if (*p == '\0')    /* Was it all lowercase? */
  1153.                     return insert (psave);    /* Yup, quit */
  1154.                 while (*p++)
  1155.                     ;    /* Skip to next case sample */
  1156.             }
  1157.         }
  1158.     }
  1159.     /*
  1160.     ** The sample wasn't all-upper, and either it wasn't all-lower or
  1161.     ** all-lower is illegal.  Insert all legal capitalizations.  In
  1162.     ** some cases, this may include all-lowercase.
  1163.     */
  1164.     if (lastdent->capitalize) {
  1165.         lowcase (newword);
  1166.         if (mylower (newword[0]))
  1167.             newword[0] = toupper (newword[0]);
  1168.         insert (newword);
  1169.     }
  1170.     if (lastdent->followcase) {
  1171.         p = lastdent->word;
  1172.         p += strlen (p) + 1;
  1173.         wcount = (*p++ & 0xFF);
  1174.         while (--wcount >= 0) {
  1175.             /* Insert every variation;  it's easier */
  1176.             if (insert (++p) < 0)
  1177.                 return -1;
  1178.             while (*p++)
  1179.                 ;        /* Skip to end of sample */
  1180.         }
  1181.         return 0;
  1182.     }
  1183.     if (lastdent->capitalize)
  1184.         return 0;
  1185.     /*
  1186.     ** We get here only if none of the special capitalization flags are
  1187.     ** set.  If first letter of the pattern is capitalized, capitalize
  1188.     ** the first letter of the result.  Otherwise produce all lowercase.
  1189.     */
  1190.     lowcase (newword);
  1191.     if (myupper (pattern[0])  &&  mylower (newword[0]))
  1192.         newword[0] = toupper (newword[0]);
  1193.     return insert (newword);
  1194. #else
  1195.     if (myupper (pattern[0])) {
  1196.         if (myupper (pattern[1])) {
  1197.             for (p = word, q = newword; *p; p++, q++) {
  1198.                 if (mylower (*p))
  1199.                     *q = toupper (*p);
  1200.                 else
  1201.                     *q = *p;
  1202.             }
  1203.             *q = 0;
  1204.         } else {
  1205.             if (mylower (word [0]))
  1206.                 newword[0] = toupper (word[0]);
  1207.             else
  1208.                 newword[0] = word[0];
  1209.  
  1210.             for (p = word + 1, q = newword + 1; *p; p++, q++)
  1211.                 if (myupper (*p))
  1212.                     *q = tolower (*p);
  1213.                 else
  1214.                     *q = *p;
  1215.  
  1216.             *q = 0;
  1217.         }
  1218.     } else {
  1219.         for (p = word, q = newword; *p; p++, q++)
  1220.             if (myupper (*p))
  1221.                 *q = tolower (*p);
  1222.             else
  1223.                 *q = *p;
  1224.         *q = 0;
  1225.     }
  1226.     return insert (newword);
  1227. #endif
  1228. }
  1229.  
  1230. char *
  1231. getline (s)
  1232. register char *s;
  1233. {
  1234.     register char *p;
  1235.     register int c;
  1236.  
  1237.     p = s;
  1238.  
  1239.     while (1) {
  1240.         fflush (stdout);
  1241.         c = (getchar () & NOPARITY);
  1242.         if (c == '\\') {
  1243.             putchar ('\\');
  1244.             fflush (stdout);
  1245.             c = (getchar () & NOPARITY);
  1246.             backup ();
  1247.             putchar (c);
  1248.             *p++ = c;
  1249.         } else if (c == ('G' & 037)) {
  1250.             return (NULL);
  1251.         } else if (c == '\n' || c == '\r') {
  1252.             *p = 0;
  1253.             return (s);
  1254.         } else if (c == erasechar) {
  1255.             if (p != s) {
  1256.                 p--;
  1257.                 backup ();
  1258.                 putchar (' ');
  1259.                 backup ();
  1260.             }
  1261.         } else if (c == killchar) {
  1262.             while (p != s) {
  1263.                 p--;
  1264.                 backup ();
  1265.                 putchar (' ');
  1266.                 backup ();
  1267.             }
  1268.         } else {
  1269.             *p++ = c;
  1270.             putchar (c);
  1271.         }
  1272.     }
  1273. }
  1274.  
  1275. askmode ()
  1276. {
  1277.     char buf[BUFSIZ];
  1278.     register int i;
  1279.  
  1280.     if (fflag) {
  1281.         if (freopen (askfilename, "w", stdout) == NULL) {
  1282.             fprintf (stderr, "Can't create %s\n", askfilename);
  1283.             exit (1);
  1284.         }
  1285.     }
  1286.  
  1287.     setbuf (stdin, NULL);
  1288.     setbuf (stdout, NULL);
  1289.  
  1290.     while (xgets (buf) != NULL) {
  1291.         /* *line is like `i', @line is like `a' */
  1292.         if (buf[0] == '*' || buf[0] == '@') {
  1293.             treeinsert(buf + 1, buf[0] == '*');
  1294.             printf("*\n");
  1295.             treeoutput ();
  1296.         } else if (good (buf)) {
  1297.             if (rootword[0] == 0) {
  1298.                 printf ("*\n");    /* perfect match */
  1299.             } else {
  1300.                 printf ("+ %s\n", rootword);
  1301.             }
  1302.         } else {
  1303.             makepossibilities (buf);
  1304.             if (possibilities[0][0]) {
  1305.                 printf ("& ");
  1306.                 for (i = 0; i < MAXPOSSIBLE; i++) {
  1307.                     if (possibilities[i][0] == 0)
  1308.                         break;
  1309.                     printf ("%s ", possibilities[i]);
  1310.                 }
  1311.                 printf ("\n");
  1312.             } else {
  1313.                 printf ("#\n");
  1314.             }
  1315.         }
  1316. #ifndef USG
  1317.         if (sflag) {
  1318.             stop ();
  1319.             if (fflag) {
  1320.                 rewind (stdout);
  1321.                 creat (askfilename, 0666);
  1322.             }
  1323.         }
  1324. #endif
  1325.     }
  1326. }
  1327.  
  1328. /* Copy/ignore "cnt" number of characters pointed to by *cc. */
  1329. copyout(cc, cnt)
  1330. register char    **cc;
  1331. register cnt;
  1332. {
  1333.     while (--cnt >= 0) {
  1334.         if (*(*cc) == 0)
  1335.             break;
  1336.         if (!lflag)
  1337.             putc (*(*cc), outfile);
  1338.         (*cc)++;
  1339.     }
  1340. }
  1341.  
  1342. lookharder(string)
  1343. char *string;
  1344. {
  1345.     char cmd[150], grepstr[100];
  1346.     register char *g, *s;
  1347.     register int wild = 0;
  1348.  
  1349.     g = grepstr;
  1350.     for (s = string; *s != '\0'; s++)
  1351.         if (*s == '*') {
  1352.             wild++;
  1353.             *g++ = '.';
  1354.             *g++ = '*';
  1355.         } else
  1356.             *g++ = *s;
  1357.     *g = '\0';
  1358.     if (grepstr[0]) {
  1359. #ifdef REGEX
  1360.         regex_dict_lookup(cmd,grepstr);
  1361. #else
  1362. #ifdef LOOK
  1363.         if (wild)
  1364.             /* string has wild card characters */
  1365.             sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
  1366.         else
  1367.             /* no wild, use look(1) */
  1368.             sprintf (cmd, "%s %s %s", LOOK, grepstr, WORDS);
  1369. #else
  1370.         sprintf (cmd, "%s '^%s$' %s", EGREPCMD, grepstr, WORDS);
  1371. #endif
  1372.         shellescape (cmd);
  1373. #endif
  1374.     }
  1375. }
  1376.  
  1377. #ifdef REGEX
  1378. regex_dict_lookup(cmd,grepstr)
  1379. char *cmd;
  1380. char *grepstr;
  1381. {
  1382.     char *do_regex_lookup();
  1383.     char *rval;
  1384.     int  whence = 0;
  1385.     int  quit = 0;
  1386.     int  count = 0;
  1387.     sprintf (cmd, "^%s$",grepstr);
  1388.     while ( !quit && (rval=do_regex_lookup(cmd, whence++)) != NULL ) {
  1389.     int ch;
  1390.         printf("%s\n",rval);;
  1391.     if ( (count++ % (li-1)) == 0 ) {
  1392.         inverse();
  1393.         printf("-- more --");
  1394.         normal();
  1395.         if ((ch=getchar()) == 'q' || ch == 'Q' || ch == 'x' || ch == 'X' )
  1396.              quit = 1;
  1397.         printf("\r                             \r");
  1398.     }
  1399.     }
  1400.     if ( rval == NULL ) {
  1401.     inverse();
  1402.     printf("--eow--");
  1403.     normal();
  1404.     getchar();    
  1405.     }
  1406. }
  1407.  
  1408. #endif
  1409.