home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / wp_dtp / ispell.lha / ispell.c < prev    next >
C/C++ Source or Header  |  1991-01-05  |  34KB  |  1,741 lines

  1. /*
  2.  * ispell.c - An interactive spelling corrector.
  3.  *
  4.  * Copyright (c), 1983, by Pace Willisson
  5.  * Permission for non-profit use is hereby granted.
  6.  * All other rights reserved.
  7.  *
  8.  * 1987, Robert McQueer, added:
  9.  *    -w option & handling of extra legal word characters
  10.  *    -d option for alternate dictionary file
  11.  *    -p option & WORDLIST variable for alternate personal dictionary
  12.  *    -x option to suppress .bak files.
  13.  *    8 bit text & config.h parameters
  14.  * 1987, Geoff Kuenning, added:
  15.  *    -c option for creating suffix suggestions from raw words
  16.  *    suffixes in personal dictionary file
  17.  *    hashed personal dictionary file
  18.  *    -S option for unsorted word lists
  19.  * 1987, Greg Schaffer, added:
  20.  *    -T option (for TeX and LaTeX instead of troff) [later changed to -t]
  21.  *       passes over \ till next whitespace.
  22.  *       does not recognize % (comment)
  23.  * 1989, Tomas Rokicki, added:
  24.  *      ispell'local'words to indicate rest of line for local words
  25.  *      -L option to write local words when done
  26.  *      fixed `sleep' so some error messages could be seen.
  27.  * 1989, Loren J. Rittle, added:
  28.  *    Fixed ISpell to use proper STDOUT/STDIN streams when used in
  29.  *       non-interactive modes.
  30.  *    ARexx Server Mode, invoke with -r option ( for rexx )
  31.  *    Thanks to Tomas Rokicki for MinRexx! and example code.
  32.  * 1990, Loren J. Rittle, reworked:
  33.  *    Converted to SAS/C v5.10.
  34.  *    Added full prototype checking.
  35.  *    Fixed more bugs, many memory related.
  36.  *    Finally left UNIX behind completely.
  37.  *    Got rid of alot of (what I would call) kludge code, left
  38.  *       over from the original port job.  See amiga.c for more details.
  39.  * 1991, Loren J. Rittle, added:
  40.  *    many new ARexx Server Mode commands.
  41.  *    better WorkBench startup support, will read tool types and
  42.  *       process files that were selected with the ISpell icon, or
  43.  *       whose default tools were set to ISpell.
  44.  */
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <ctype.h>
  50. #include <fcntl.h>
  51. #include <libraries/dosextens.h>
  52. #include <proto/all.h>
  53. #include "minrexx.h"
  54. #include "config.h"
  55. #include "ispell.h"
  56. #include "version.h"
  57.  
  58. struct rexxCommandList rcl[] =
  59. {
  60.   {"add", &rexxadd},
  61.   {"quickadd", &rexxquickadd},
  62.   {"check", &rexxcheck},
  63.   {"quickcheck", &rexxquickcheck},
  64.   {"lookup", &rexxlookup},
  65.   {"filecheck", &rexxfilecheck},
  66.   {"version", &rexxversion},
  67.   {"exit", &rexxexit},
  68.   {NULL, NULL}
  69. };
  70.  
  71. SHORT KeepGoing = TRUE;    /* main loop control value */
  72.  
  73. char rootword[BUFSIZ];
  74. struct dent *lastdent;
  75.  
  76. char *hashstrings;
  77. struct hashheader hashheader;
  78.  
  79. char tempfile[200];
  80.  
  81. #define ISTEXTERM(c)   (((c) == '{') || \
  82.             ((c) == '}') || \
  83.             ((c) == '[') || \
  84.             ((c) == ']'))
  85.  
  86. int li, co;    /* lines, columns */
  87.  
  88. FILE *infile;
  89. FILE *outfile;
  90.  
  91. char hashname[MAXPATHLEN];
  92.  
  93. /*
  94. ** we use extended character set range specifically to allow intl.
  95. ** character set characters.  We are being REALLY paranoid about indexing
  96. ** this array - explicitly cast into unsigned INTEGER, then mask
  97. ** If NO8BIT is set, text will be masked to ascii range.
  98. */
  99.      static int Trynum;
  100. #ifdef NO8BIT
  101.      static char Try[128];
  102.      static char Checkch[128];
  103. #define iswordch(X) (Checkch[((unsigned)(X))&0x7f])
  104. #else
  105.      static char Try[256];
  106.      static char Checkch[256];
  107. #define iswordch(X) (Checkch[((unsigned)(X))&0xff])
  108. #endif
  109.  
  110.      static int sortit = 1;
  111.  
  112. void givehelp (void)
  113. {
  114.   erase ();
  115.   printcon (Version_ID);
  116.   printcon ("\n");
  117.   printcon ("Whenever a word is found that is not in the dictionary,\n");
  118.   printcon ("it is printed on the first line of the screen.  If the dictionary\n");
  119.   printcon ("contains any similar words, they are listed with a single digit\n");
  120.   printcon ("next to each one.  You have the option of replacing the word\n");
  121.   printcon ("completely, or choosing one of the suggested words.\n");
  122.   printcon ("\n");
  123.   printcon ("Commands are:\n\n");
  124.   printcon ("R       Replace the misspelled word completely.\n");
  125.   printcon ("Space   Accept the word this time only\n");
  126.   printcon ("A       Accept the word for the rest of this file.\n");
  127.   printcon ("I       Accept the word, and put it in your private dictionary.\n");
  128.   printcon ("0-9     Replace with one of the suggested words.\n");
  129.   printcon ("L       Look up words via regular expression.\n");
  130.   printcon ("Q       Write the rest of this file, ignoring misspellings, ");
  131.   printcon ("and start next file.\n");
  132.   printcon ("X       Exit immediately.  Asks for confirmation.  ");
  133.   printcon ("Leaves file unchanged.\n");
  134.   printcon ("^L      Redraw screen.\n");
  135.   printcon ("\n\n");
  136.   printcon ("-- Type space to continue --");
  137.   while (getccon () != ' ')
  138.     ;
  139. }
  140.  
  141. char *getline ();
  142.  
  143. int cflag = 0;
  144. int lflag = 0;
  145. int incfileflag = 0;
  146. int aflag = 0;
  147. int fflag = 0;
  148. int sflag = 0;
  149. int xflag = 0;
  150. int tflag = 0;
  151. int llflag = 0;
  152. int rflag = 0;
  153.  
  154. #define MAXPOSSIBLE    100    /* Max no. of possibilities to generate */
  155.  
  156. char possibilities[MAXPOSSIBLE][BUFSIZ];
  157. int pcount;
  158. int maxposslen;
  159.  
  160. char *askfilename;
  161.  
  162. static char *Cmd;
  163.  
  164. void usage (void)
  165. {
  166.   fprintf (stderr,
  167.     "Usage: %s [-dfile | -pfile | -wchars | -t | -x | -S] file .....\n",
  168.        Cmd);
  169.   fprintf (stderr,
  170.        "       %s -r\n",
  171.        Cmd);
  172.   fprintf (stderr,
  173.        "       %s [-dfile | -pfile | -wchars] -l\n",
  174.        Cmd);
  175.   fprintf (stderr,
  176.        "       %s [-dfile | -pfile | -ffile | -s] {-a | -A}\n",
  177.        Cmd);
  178.   fprintf (stderr, "       %s [-wchars] -c\n", Cmd);
  179.   fprintf (stderr, "       %s -v\n", Cmd);
  180.   exit (1);
  181. }
  182.  
  183. static void initckch (void)
  184. {
  185.   register int c;
  186.  
  187.   Trynum = 0;
  188. #ifdef NO8BIT
  189.   for (c = 0; c < 128; ++c)
  190.     {
  191. #else
  192.   for (c = 0; c < 256; ++c)
  193.     {
  194. #endif
  195.       if (myalpha ((char) c))
  196.     {
  197.       Checkch[c] = (char) 1;
  198.       if (myupper ((char) c))
  199.         {
  200.           Try[Trynum] = (char) c;
  201.           ++Trynum;
  202.         }
  203.     }
  204.       else
  205.     Checkch[c] = (char) 0;
  206.     }
  207. }
  208.  
  209. void main (int argc, char **argv)
  210. {
  211.   char *p;
  212.   char *cpd;
  213.   char num[4];
  214.   unsigned mask;
  215.   static char outbuf[BUFSIZ];
  216.  
  217.   Cmd = *argv;
  218.  
  219.   initckch ();
  220.   sprintf (hashname, "%s%s", LIBDIR, DEFHASH);
  221.  
  222.   cpd = NULL;
  223.  
  224.   argv++;
  225.   argc--;
  226.   while (argc && **argv == '-')
  227.     {
  228.       switch ((*argv)[1])
  229.     {
  230.     case 'r':
  231.       rflag++;
  232.       lflag++;
  233.       break;
  234.     case 'v':
  235.       printf ("%s\n", Version_ID);
  236.       exit (0);
  237.     case 't':
  238.       tflag++;
  239.       break;
  240.     case 'A':
  241.       incfileflag = 1;
  242.       aflag = 1;
  243.       break;
  244.     case 'a':
  245.       aflag++;
  246.       break;
  247.     case 'c':
  248.       cflag++;
  249.       lflag++;
  250.       break;
  251.     case 'x':
  252.       xflag++;
  253.       break;
  254.     case 'f':
  255.       fflag++;
  256.       p = (*argv) + 2;
  257.       if (*p == '\0')
  258.         {
  259.           argv++;
  260.           argc--;
  261.           if (argc == 0)
  262.         usage ();
  263.           p = *argv;
  264.         }
  265.       askfilename = p;
  266.       break;
  267.     case 'l':
  268.       lflag++;
  269.       break;
  270.     case 'L':
  271.       llflag++;
  272.       break;
  273.     case 's':
  274.       sflag++;
  275.       break;
  276.     case 'S':
  277.       sortit = 0;
  278.       break;
  279.     case 'p':
  280.       cpd = (*argv) + 2;
  281.       if (*cpd == '\0')
  282.         {
  283.           argv++;
  284.           argc--;
  285.           if (argc == 0)
  286.         usage ();
  287.           cpd = *argv;
  288.         }
  289.       break;
  290.     case 'd':
  291.       p = (*argv) + 2;
  292.       if (*p == '\0')
  293.         {
  294.           argv++;
  295.           argc--;
  296.           if (argc == 0)
  297.         usage ();
  298.           p = *argv;
  299.         }
  300.       if (*p == '/')
  301.         strcpy (hashname, p);
  302.       else
  303.         sprintf (hashname, "%s%s", LIBDIR, p);
  304.       break;
  305.     case 'w':
  306.       num[3] = '\0';
  307. #ifdef NO8BIT
  308.       mask = 0x7f;
  309. #else
  310.       mask = 0xff;
  311. #endif
  312.       p = (*argv) + 2;
  313.       if (*p == '\0')
  314.         {
  315.           argv++;
  316.           argc--;
  317.           if (argc == 0)
  318.         usage ();
  319.           p = *argv;
  320.         }
  321.       while (Trynum <= mask && *p != '\0')
  322.         {
  323.           if (*p != 'n' && *p != '\\')
  324.         {
  325.           Checkch[((unsigned) (*p)) & mask] = (char) 1;
  326.           Try[Trynum] = *p & mask;
  327.           ++p;
  328.         }
  329.           else
  330.         {
  331.           ++p;
  332.           num[0] = '\0';
  333.           num[1] = '\0';
  334.           num[2] = '\0';
  335.           num[3] = '\0';
  336.           if (isdigit (p[0]))
  337.             num[0] = p[0];
  338.           if (isdigit (p[1]))
  339.             num[1] = p[1];
  340.           if (isdigit (p[2]))
  341.             num[2] = p[2];
  342.           if (p[-1] == 'n')
  343.             {
  344.               p += strlen (num);
  345.               num[0] = atoi (num);
  346.             }
  347.           else
  348.             {
  349.               p += strlen (num);
  350.               if (num[0])
  351.             num[0] -= '0';
  352.               if (num[1])
  353.             {
  354.               num[0] <<= 3;
  355.               num[0] += num[1] - '0';
  356.             }
  357.               if (num[2])
  358.             {
  359.               num[0] <<= 3;
  360.               num[0] += num[2] - '0';
  361.             }
  362.             }
  363.           Try[Trynum] = num[0] & mask;
  364.           Checkch[num[0] & mask] = 1;
  365.         }
  366.           ++Trynum;
  367.         }
  368.       break;
  369.     default:
  370.       usage ();
  371.     }
  372.       argv++;
  373.       argc--;
  374.     }
  375.  
  376.   if (!argc && !lflag && !aflag && !rflag)
  377.     usage ();
  378.  
  379.   if (linit () < 0)
  380.     exit (0);
  381.  
  382.   treeinit (cpd);
  383.  
  384.   if (rflag)
  385.     {
  386.       servermode ();
  387.       exit (0);
  388.     }
  389.  
  390.   if (aflag)
  391.     {
  392.       askmode ();
  393.       exit (0);
  394.     }
  395.  
  396.   setbuf (stdout, outbuf);
  397.   if (lflag)
  398.     {
  399.       infile = stdin;
  400.       checkfile ();
  401.       exit (0);
  402.     }
  403.  
  404.   terminit ();
  405.  
  406.   while (argc--)
  407.     dofile (*argv++);
  408.  
  409.   done ();
  410. }
  411.  
  412. char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
  413. char *currentchar;
  414. char token[BUFSIZ];
  415.  
  416. int quit;
  417.  
  418. char *currentfile = NULL;
  419.  
  420. void dofile (char *filename)
  421. {
  422.   int c;
  423.   char bakfile[256];
  424.   char *cp;
  425.  
  426.   currentfile = filename;
  427.  
  428.   if ((infile = fopen (filename, "r")) == NULL)
  429.     {
  430.       fprintf (stderr, "Can't open %s\n", filename);
  431.       sleep (2);
  432.       return;
  433.     }
  434.  
  435.   if (access (filename, 2) < 0)
  436.     {
  437.       fprintf (stderr, "Can't write to %s\n", filename);
  438.       sleep (2);
  439.       return;
  440.     }
  441.  
  442.   tmpnam (tempfile);
  443.   if ((outfile = fopen (tempfile, "w")) == NULL)
  444.     {
  445.       fprintf (stderr, "Can't create %s\n", tempfile);
  446.       sleep (2);
  447.       return;
  448.     }
  449.  
  450.   quit = 0;
  451.  
  452.   /* See if the file is a .tex file.  If so, set the appropriate flag. */
  453.   if ((cp = strrchr (filename, '.')) != NULL && strcmp (cp, ".tex") == 0)
  454.     tflag = 1;
  455.   checkfile ();
  456.  
  457.   fclose (infile);
  458.   fclose (outfile);
  459.  
  460.   if (!cflag)
  461.     treeoutput ();
  462.  
  463.   if ((infile = fopen (tempfile, "r")) == NULL)
  464.     {
  465.       fprintf (stderr, "temporary file disappeared (%s)\n", tempfile);
  466.       sleep (2);
  467.       return;
  468.     }
  469.  
  470.   sprintf (bakfile, "%s%s", filename, BAKEXT);
  471.   remove (bakfile);
  472.   if (rename (filename, bakfile))
  473.     {
  474.       fprintf (stderr, "can't rename %s to %s\n", filename, bakfile);
  475.       sleep (2);
  476.       return;
  477.     }
  478.  
  479.   /* if we can't write new, preserve .bak regardless of xflag */
  480.   if ((outfile = fopen (filename, "w")) == NULL)
  481.     {
  482.       fprintf (stderr, "can't create %s\n", filename);
  483.       sleep (2);
  484.       return;
  485.     }
  486.  
  487.   while ((c = getc (infile)) != EOF)
  488.     putc (c, outfile);
  489.  
  490.   fclose (infile);
  491.   fclose (outfile);
  492.  
  493.   remove (tempfile);
  494.   if (xflag)
  495.     remove (bakfile);
  496. }
  497.  
  498. void checkfile (void)
  499. {
  500.   register char *p;
  501.   register int len;
  502.   int addflag;
  503.  
  504.   secondbuf[0] = 0;
  505.  
  506.   while (1)
  507.     {
  508.       strcpy (firstbuf, secondbuf);
  509.       if (quit)
  510.     {            /* quit can't be set in l mode */
  511.       while (fgets (secondbuf, sizeof secondbuf, infile) != NULL)
  512.         fputs (secondbuf, outfile);
  513.       break;
  514.     }
  515.  
  516.       if (fgets (secondbuf, sizeof secondbuf, infile) == NULL)
  517.     break;
  518.       currentchar = secondbuf;
  519.       addflag = 0;
  520.       len = strlen (secondbuf) - 1;
  521.  
  522.       if (!tflag)
  523.     {
  524.       /* skip over .if */
  525.       if (strncmp (currentchar, ".if t", 5) == 0
  526.           || strncmp (currentchar, ".if n", 5) == 0)
  527.         {
  528.           copyout (¤tchar, 5);
  529.           while (*currentchar && isspace (*currentchar))
  530.         copyout (¤tchar, 1);
  531.         }
  532.  
  533.       /* skip over .ds XX or .nr XX */
  534.       if (strncmp (currentchar, ".ds ", 4) == 0
  535.           || strncmp (currentchar, ".de ", 4) == 0
  536.           || strncmp (currentchar, ".nr ", 4) == 0)
  537.         {
  538.           copyout (¤tchar, 3);
  539.           while (*currentchar && isspace (*currentchar))
  540.         copyout (¤tchar, 1);
  541.           while (*currentchar && !isspace (*currentchar))
  542.         copyout (¤tchar, 1);
  543.           if (*currentchar == 0)
  544.         {
  545.           if (!lflag)
  546.             putc ('\n', outfile);
  547.           continue;
  548.         }
  549.         }
  550.     }
  551.  
  552.       if (secondbuf[len] == '\n')
  553.     secondbuf[len] = 0;
  554.  
  555.       /* if this is a formatter command, skip over it */
  556.       if (!tflag && *currentchar == '.')
  557.     {
  558.       while (*currentchar && !myspace (*currentchar))
  559.         {
  560.           if (!lflag)
  561.         putc (*currentchar, outfile);
  562.           currentchar++;
  563.         }
  564.       if (*currentchar == 0)
  565.         {
  566.           if (!lflag)
  567.         putc ('\n', outfile);
  568.           continue;
  569.         }
  570.     }
  571.  
  572.       while (1)
  573.     {
  574.       while (*currentchar && !iswordch (*currentchar))
  575.         {
  576.           if (tflag)    /* TeX or LaTeX stuff */
  577.         {
  578.           if (*currentchar == '\\')
  579.             {
  580.               /* skip till whitespace */
  581.               while (*currentchar &&
  582.                  (!isspace (*currentchar) &&
  583.                   !ISTEXTERM (*currentchar)))
  584.             {
  585.               if (!lflag)
  586.                 putc (*currentchar, outfile);
  587.               currentchar++;
  588.             }
  589.               continue;
  590.             }
  591.         }
  592.           else
  593.         {
  594.           /* formatting escape sequences */
  595.           if (*currentchar == '\\')
  596.             {
  597.               switch (currentchar[1])
  598.             {
  599.             case 'f':
  600.               if (currentchar[2] != '(')
  601.                 {
  602.                   /* font change: \fX */
  603.                   copyout (¤tchar, 3);
  604.                 }
  605.               else
  606.                 {
  607.                   /* font change: \f(XY */
  608.                   copyout (¤tchar, 5);
  609.                 }
  610.               continue;
  611.             case 's':
  612.               /* size change */
  613.               p = currentchar + 2;
  614.               if (*p == '+' || *p == '-')
  615.                 p++;
  616.               /* This looks wierd 'cause we assume
  617.               ** *p is now a digit.
  618.               */
  619.               if (isdigit (p[1]))
  620.                 p++;
  621.               copyout (¤tchar,
  622.                    p - currentchar + 1);
  623.               continue;
  624.             case '(':
  625.               /* extended char set escape: \(XX */
  626.               copyout (¤tchar, 4);
  627.               continue;
  628.             case '*':
  629.               if (currentchar[2] != '(')
  630.                 copyout (¤tchar, 3);
  631.               else
  632.                 copyout (¤tchar, 5);
  633.               continue;
  634.             default:
  635.               break;
  636.             }
  637.             }
  638.         }
  639.  
  640.           if (!lflag)
  641.         putc (*currentchar, outfile);
  642.           currentchar++;
  643.         }
  644.  
  645.       if (*currentchar == 0)
  646.         break;
  647.  
  648.       p = token;
  649.       while (iswordch (*currentchar) ||
  650.          (*currentchar == '\'' &&
  651.           iswordch (*(currentchar + 1))))
  652.         *p++ = *currentchar++;
  653.       *p = 0;
  654. /*
  655.  *   mods by tom rokicki to handle local document words automagically
  656.  */
  657.       if (token[0] == 'i' &&
  658.           strcmp (token, "ispell'local'words") == 0)
  659.         {
  660.           addflag = 1;
  661.         }
  662.       else
  663.         {
  664.           if (addflag)
  665.         {
  666.           if (!good (token))
  667.             {
  668.               treeinsert (token, 0);
  669.             }
  670.         }
  671.           if (lflag)
  672.         {
  673.           if (!good (token) && !cflag)
  674.             if (rflag)
  675.               fprintf (outfile, "%s\n", token);
  676.             else
  677.               fprintf (stdout, "%s\n", token);
  678.         }
  679.           else
  680.         {
  681.           if (!quit)
  682.             correct (token, ¤tchar);
  683.         }
  684.         }
  685.       if (!lflag)
  686.         fprintf (outfile, "%s", token);
  687.     }
  688.       if (!lflag)
  689.     putc ('\n', outfile);
  690.     }
  691.   if (llflag)
  692.     {
  693.       lldump ();
  694.     }
  695. }
  696.  
  697. void correct (char *token, char **currentchar)
  698. {
  699.   register int c;
  700.   register int i;
  701.   int col_ht;
  702.   int ncols;
  703.   char *start_l2;
  704.   char *begintoken;
  705.  
  706.   begintoken = *currentchar - strlen (token);
  707.  
  708. checkagain:
  709.   if (good (token))
  710.     return;
  711.  
  712.   erase ();
  713.   printcon ("    %s", token);
  714.   if (currentfile)
  715.     printcon ("              File: %s", currentfile);
  716.   printcon ("\n\n");
  717.  
  718.   makepossibilities (token);
  719.  
  720.   /*
  721.    * Make sure we have enough room on the screen to hold the
  722.    * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
  723.    * is the maximum number of columns that will fit.
  724.    */
  725.   col_ht = li - 6;        /* Height of columns of words */
  726.   ncols = co / (maxposslen + 8);
  727.   if (pcount > ncols * col_ht)
  728.     pcount = ncols * col_ht;
  729.  
  730. #ifdef EQUAL_COLUMNS
  731.   /*
  732.    * Equalize the column sizes.  The last column will be short.
  733.    */
  734.   col_ht = (pcount + ncols - 1) / ncols;
  735. #endif
  736.  
  737.   for (i = 0; i < pcount; i++)
  738.     {
  739.       move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
  740.       printcon ("%2d: %s", i, possibilities[i]);
  741.     }
  742.  
  743.   move (li - 3, 0);
  744.   show_line (firstbuf, firstbuf, 0);
  745.  
  746.   start_l2 = secondbuf;
  747.   if (line_size (secondbuf, *currentchar) > co - 1)
  748.     {
  749.       start_l2 = begintoken - (co / 2);
  750.       while (start_l2 < begintoken)
  751.     {
  752.       i = line_size (start_l2, *currentchar) + 1;
  753.       if (i <= co)
  754.         break;
  755.       start_l2 += i - co;
  756.     }
  757.       if (start_l2 > begintoken)
  758.     start_l2 = begintoken;
  759.       if (start_l2 < secondbuf)
  760.     start_l2 = secondbuf;
  761.     }
  762.   show_line (start_l2, begintoken, strlen (token));
  763.  
  764.   while (1)
  765.     {
  766.       switch (c = (getccon () & NOPARITY))
  767.     {
  768.     case 'Z' & 037:
  769.       stop ();
  770.       erase ();
  771.       goto checkagain;
  772.     case ' ':
  773.       erase ();
  774.       return;
  775.     case 'x':
  776.     case 'X':
  777.       printcon ("Are you sure you want to throw away your changes? ");
  778.       c = (getccon () & NOPARITY);
  779.       if (c == 'y' || c == 'Y')
  780.         {
  781.           erase ();
  782.           done ();
  783.         }
  784.       putchar (7);
  785.       goto checkagain;
  786.     case 'i':
  787.     case 'I':
  788.       treeinsert (token, 1);
  789.       erase ();
  790.       return;
  791.     case 'a':
  792.     case 'A':
  793.       treeinsert (token, 0);
  794.       if (llflag)
  795.         llinsert (token);
  796.       erase ();
  797.       return;
  798.     case 'L' & 037:
  799.       goto checkagain;
  800.     case '?':
  801.       givehelp ();
  802.       goto checkagain;
  803.     case 'r':
  804.     case 'R':
  805.       move (li - 1, 0);
  806.       printcon ("Replace with: ");
  807.       if (getline (token) == NULL)
  808.         {
  809.           putccon (7);
  810.           erase ();
  811.           goto checkagain;
  812.         }
  813.       inserttoken (secondbuf, begintoken, token, currentchar);
  814.       erase ();
  815.       goto checkagain;
  816.     case '0':
  817.     case '1':
  818.     case '2':
  819.     case '3':
  820.     case '4':
  821.     case '5':
  822.     case '6':
  823.     case '7':
  824.     case '8':
  825.     case '9':
  826.       i = c - '0';
  827.       if (pcount > 10
  828.           && i > 0 && i <= (pcount - 1) / 10)
  829.         {
  830.           c = getccon () & NOPARITY;
  831.           if (c >= '0' && c <= '9')
  832.         i = i * 10 + c - '0';
  833.           else if (c != '\n')
  834.         {
  835.           putccon (7);
  836.           break;
  837.         }
  838.         }
  839.       if (i < pcount)
  840.         {
  841.           strcpy (token, possibilities[i]);
  842.           inserttoken (secondbuf, begintoken,
  843.                token, currentchar);
  844.           erase ();
  845.           return;
  846.         }
  847.       putccon (7);
  848.       break;
  849.     case '\r':        /* This makes typing \n after single digits */
  850.     case '\n':        /* ..less obnoxious */
  851.       break;
  852.     case 'l':
  853.     case 'L':
  854.       {
  855.         char buf[100];
  856.         move (li - 1, 0);
  857.         printcon ("Lookup string ('*' is wildcard): ");
  858.         if (getline (buf) == NULL)
  859.           {
  860.         putccon (7);
  861.         erase ();
  862.         goto checkagain;
  863.           }
  864.         printcon ("\n\n");
  865.         lookharder (buf);
  866.         erase ();
  867.         goto checkagain;
  868.       }
  869.     case 'q':
  870.     case 'Q':
  871.       quit = 1;
  872.       erase ();
  873.       return;
  874.     default:
  875.       putccon (7);
  876.       break;
  877.     }
  878.     }
  879. }
  880.  
  881. void show_line (char *line, char *invstart, int invlen)
  882. {
  883.   register int width;
  884.  
  885.   width = 0;
  886.   while (line != invstart && width < co - 1)
  887.     width += show_char (*line++, width);
  888.   if (invlen)
  889.     {
  890.       inverse ();
  891.       while (--invlen >= 0 && width < co - 1)
  892.     width += show_char (*line++, width);
  893.       normal ();
  894.     }
  895.   while (*line && width < co - 1)
  896.     width += show_char (*line++, width);
  897.   printcon ("\n");
  898. }
  899.  
  900. int show_char (int ch, int linew)
  901. {
  902.   if (ch == '\t')
  903.     {
  904.       putccon ('\t');
  905.       return 8 - (linew & 0x07);
  906.     }
  907.   else if (ch < ' ')
  908.     {
  909.       putccon ('^');
  910.       putccon (ch + 'A' - '\001');
  911.       return 2;
  912.     }
  913.   putccon (ch);
  914.   return 1;
  915. }
  916.  
  917. int line_size (char *buf, char *bufend)
  918. {
  919.   register int width;
  920.  
  921.   for (width = 0; buf < bufend && *buf; buf++)
  922.     {
  923.       if (*buf == '\t')
  924.     width = (width + 8) & ~0x07;
  925.       else if (*buf < ' ')
  926.     width += 2;
  927.       else
  928.     width++;
  929.     }
  930.   return width;
  931. }
  932.  
  933. void inserttoken (char *buf, char *start, char *token, char **currentchar)
  934. {
  935.   char copy[BUFSIZ];
  936.   register char *p, *q;
  937.  
  938.   strcpy (copy, buf);
  939.  
  940.   for (p = buf, q = copy; p != start; p++, q++)
  941.     *p = *q;
  942.   q += *currentchar - start;
  943.   while (*token && iswordch (*token))
  944.     *p++ = *token++;
  945.   *currentchar = p;
  946.   if (*token)
  947.     {
  948.  
  949.       /*
  950.       ** The token changed to two words.  Split it up and save the
  951.       ** second one for later.
  952.       */
  953.  
  954.       *p++ = *token;
  955.       *token++ = '\0';
  956.       while (*token)
  957.     *p++ = *token++;
  958.     }
  959.   while (*p++ = *q++)
  960.     ;
  961. }
  962.  
  963. int casecmp (char *a, char *b)
  964. {
  965.   register char *ap;
  966.   register char *bp;
  967.  
  968.   for (ap = a, bp = b; *ap; ap++, bp++)
  969.     {
  970.       if (mylower (*ap))
  971.     {
  972.       if (mylower (*bp))
  973.         {
  974.           if (*ap != *bp)
  975.         return *ap - *bp;
  976.         }
  977.       else
  978.         {
  979.           if (toupper (*ap) != *bp)
  980.         return toupper (*ap) - *bp;
  981.         }
  982.     }
  983.       else
  984.     {
  985.       if (myupper (*bp))
  986.         {
  987.           if (*ap != *bp)
  988.         return *ap - *bp;
  989.         }
  990.       else
  991.         {
  992.           if (tolower (*ap) != *bp)
  993.         return tolower (*ap) - *bp;
  994.         }
  995.     }
  996.     }
  997.   if (*bp != '\0')
  998.     return -*bp;
  999.   return strcmp (a, b);
  1000. }
  1001.  
  1002. void makepossibilities (char *word)
  1003. {
  1004.   register int i;
  1005.  
  1006.   for (i = 0; i < MAXPOSSIBLE; i++)
  1007.     possibilities[i][0] = 0;
  1008.   pcount = 0;
  1009.   maxposslen = 0;
  1010.  
  1011. #ifdef CAPITALIZE
  1012.   wrongcapital (word);
  1013. #endif
  1014.   if (pcount < MAXPOSSIBLE)
  1015.     wrongletter (word);
  1016.   if (pcount < MAXPOSSIBLE)
  1017.     extraletter (word);
  1018.   if (pcount < MAXPOSSIBLE)
  1019.     missingletter (word);
  1020.   if (pcount < MAXPOSSIBLE)
  1021.     transposedletter (word);
  1022.  
  1023.   if (sortit && pcount)
  1024.     qsort ((char *) possibilities, pcount,
  1025.        sizeof (possibilities[0]), casecmp);
  1026. }
  1027.  
  1028. int insert (char *word)
  1029. {
  1030.   register int i;
  1031.  
  1032.   for (i = 0; i < pcount; i++)
  1033.     if (strcmp (possibilities[i], word) == 0)
  1034.       return (0);
  1035.  
  1036.   strcpy (possibilities[pcount++], word);
  1037.   i = strlen (word);
  1038.   if (i > maxposslen)
  1039.     maxposslen = i;
  1040.   if (pcount >= MAXPOSSIBLE)
  1041.     return (-1);
  1042.   else
  1043.     return (0);
  1044. }
  1045.  
  1046. #ifdef CAPITALIZE
  1047. int wrongcapital (char *word)
  1048. {
  1049.   char newword[BUFSIZ];
  1050.  
  1051.   /*
  1052.   ** All-uppercase is always legal.  If the word matches, "ins_cap"
  1053.   ** will recapitalize it correctly.
  1054.   */
  1055.   strcpy (newword, word);
  1056.   upcase (newword);
  1057.   if (good (newword))
  1058.     return ins_cap (newword, word);
  1059.   return 0;
  1060. }
  1061.  
  1062. #endif
  1063.  
  1064. void wrongletter (char *word)
  1065. {
  1066.   register int i, j, c, n;
  1067.   char newword[BUFSIZ];
  1068.  
  1069.   n = strlen (word);
  1070.   strcpy (newword, word);
  1071. #ifdef CAPITALIZE
  1072.   upcase (newword);
  1073. #endif
  1074.  
  1075.   for (i = 0; i < n; i++)
  1076.     {
  1077.       for (j = 0; j < Trynum; ++j)
  1078.     {
  1079.       newword[i] = Try[j];
  1080.       if (good (newword))
  1081.         {
  1082.           if (ins_cap (newword, word) < 0)
  1083.         return;
  1084.         }
  1085.     }
  1086. #ifdef CAPITALIZE
  1087.       c = word[i];
  1088.       if (islower (c))
  1089.     newword[i] = toupper (c);
  1090.       else
  1091.     newword[i] = c;
  1092. #else
  1093.       newword[i] = word[i];
  1094. #endif
  1095.     }
  1096. }
  1097.  
  1098. void extraletter (char *word)
  1099. {
  1100.   char newword[BUFSIZ];
  1101.   register char *p, *s, *t;
  1102.  
  1103.   if (strlen (word) < 3)
  1104.     return;
  1105.  
  1106.   for (p = word; *p; p++)
  1107.     {
  1108.       for (s = word, t = newword; *s; s++)
  1109.     if (s != p)
  1110.       *t++ = *s;
  1111.       *t = 0;
  1112. #ifdef CAPITALIZE
  1113.       if (good (upcase (newword)))
  1114.     {
  1115.       if (ins_cap (newword, word) < 0)
  1116.         return;
  1117.     }
  1118. #else
  1119.       if (good (newword))
  1120.     {
  1121.       if (ins_cap (newword, word) < 0)
  1122.         return;
  1123.     }
  1124. #endif
  1125.     }
  1126. }
  1127.  
  1128. void missingletter (char *word)
  1129. {
  1130.   char newword[BUFSIZ];
  1131.   register char *p, *r, *s, *t;
  1132.   register int i;
  1133.  
  1134.   for (p = word; p == word || p[-1]; p++)
  1135.     {
  1136.       for (s = newword, t = word; t != p; s++, t++)
  1137.     *s = *t;
  1138.       r = s++;
  1139.       while (*t)
  1140.     *s++ = *t++;
  1141.       *s = 0;
  1142.       for (i = 0; i < Trynum; ++i)
  1143.     {
  1144.       *r = Try[i];
  1145. #ifdef CAPITALIZE
  1146.       if (good (upcase (newword)))
  1147.         {
  1148.           if (ins_cap (newword, word) < 0)
  1149.         return;
  1150.         }
  1151. #else
  1152.       if (good (newword))
  1153.         {
  1154.           if (ins_cap (newword, word) < 0)
  1155.         return;
  1156.         }
  1157. #endif
  1158.     }
  1159.     }
  1160. }
  1161.  
  1162. void transposedletter (char *word)
  1163. {
  1164.   char newword[BUFSIZ];
  1165.   register int t;
  1166.   register char *p;
  1167.  
  1168.   strcpy (newword, word);
  1169.   for (p = newword; p[1]; p++)
  1170.     {
  1171.       t = p[0];
  1172.       p[0] = p[1];
  1173.       p[1] = t;
  1174. #ifdef CAPITALIZE
  1175.       if (good (upcase (newword)))
  1176.     {
  1177.       if (ins_cap (newword, word) < 0)
  1178.         return;
  1179.     }
  1180. #else
  1181.       if (good (newword))
  1182.     {
  1183.       if (ins_cap (newword, word) < 0)
  1184.         return;
  1185.     }
  1186. #endif
  1187.       t = p[0];
  1188.       p[0] = p[1];
  1189.       p[1] = t;
  1190.     }
  1191. }
  1192.  
  1193. /* Insert one or more correctly capitalized versions of pattern */
  1194. int ins_cap (char *word, char *pattern)
  1195. {
  1196.   static char newword[BUFSIZ];
  1197.   register char *p;
  1198.   char *psave;
  1199.   register int wcount;
  1200.  
  1201.   if (*word == 0)
  1202.     return 0;
  1203.  
  1204.   strcpy (newword, word);
  1205. #ifdef CAPITALIZE
  1206.   if (lastdent->allcaps)
  1207.     return insert (upcase (newword));    /* Uppercase required */
  1208.   for (p = pattern; *p; p++)
  1209.     if (mylower (*p))
  1210.       break;
  1211.   if (*p == '\0')
  1212.     return insert (upcase (newword));    /* Pattern was all caps */
  1213.   for (p = pattern; *p; p++)
  1214.     if (myupper (*p))
  1215.       break;
  1216.   if (*p == '\0')
  1217.     {                /* Pattern was all lower */
  1218.       if (!lastdent->followcase && !lastdent->capitalize)
  1219.     return insert (lowcase (newword));
  1220.       /*
  1221.       ** If there's a followcase version that's all-lower,
  1222.       ** insert only that version.
  1223.       */
  1224.       if (lastdent->followcase)
  1225.     {
  1226.       p = lastdent->word;
  1227.       p += strlen (p) + 1;
  1228.       wcount = (*p++ & 0xFF);
  1229.       while (--wcount >= 0)
  1230.         {
  1231.           for (psave = ++p;
  1232.            *p && !myupper (*p);
  1233.            p++)
  1234.         ;
  1235.           if (*p == '\0')    /* Was it all lowercase? */
  1236.         return insert (psave);    /* Yup, quit */
  1237.           while (*p++)
  1238.         ;        /* Skip to next case sample */
  1239.         }
  1240.     }
  1241.     }
  1242.   /*
  1243.   ** The sample wasn't all-upper, and either it wasn't all-lower or
  1244.   ** all-lower is illegal.  Insert all legal capitalizations.  In
  1245.   ** some cases, this may include all-lowercase.
  1246.   */
  1247.   if (lastdent->capitalize)
  1248.     {
  1249.       lowcase (newword);
  1250.       if (mylower (newword[0]))
  1251.     newword[0] = toupper (newword[0]);
  1252.       insert (newword);
  1253.     }
  1254.   if (lastdent->followcase)
  1255.     {
  1256.       p = lastdent->word;
  1257.       p += strlen (p) + 1;
  1258.       wcount = (*p++ & 0xFF);
  1259.       while (--wcount >= 0)
  1260.     {
  1261.       /* Insert every variation;  it's easier */
  1262.       if (insert (++p) < 0)
  1263.         return -1;
  1264.       while (*p++)
  1265.         ;            /* Skip to end of sample */
  1266.     }
  1267.       return 0;
  1268.     }
  1269.   if (lastdent->capitalize)
  1270.     return 0;
  1271.   /*
  1272.   ** We get here only if none of the special capitalization flags are
  1273.   ** set.  If first letter of the pattern is capitalized, capitalize
  1274.   ** the first letter of the result.  Otherwise produce all lowercase.
  1275.   */
  1276.   lowcase (newword);
  1277.   if (myupper (pattern[0]) && mylower (newword[0]))
  1278.     newword[0] = toupper (newword[0]);
  1279.   return insert (newword);
  1280. #else
  1281.   if (myupper (pattern[0]))
  1282.     {
  1283.       if (myupper (pattern[1]))
  1284.     {
  1285.       for (p = word, q = newword; *p; p++, q++)
  1286.         {
  1287.           if (mylower (*p))
  1288.         *q = toupper (*p);
  1289.           else
  1290.         *q = *p;
  1291.         }
  1292.       *q = 0;
  1293.     }
  1294.       else
  1295.     {
  1296.       if (mylower (word[0]))
  1297.         newword[0] = toupper (word[0]);
  1298.       else
  1299.         newword[0] = word[0];
  1300.  
  1301.       for (p = word + 1, q = newword + 1; *p; p++, q++)
  1302.         if (myupper (*p))
  1303.           *q = tolower (*p);
  1304.         else
  1305.           *q = *p;
  1306.  
  1307.       *q = 0;
  1308.     }
  1309.     }
  1310.   else
  1311.     {
  1312.       for (p = word, q = newword; *p; p++, q++)
  1313.     if (myupper (*p))
  1314.       *q = tolower (*p);
  1315.     else
  1316.       *q = *p;
  1317.       *q = 0;
  1318.     }
  1319.   return insert (newword);
  1320. #endif
  1321. }
  1322.  
  1323. char *getline (char *s)
  1324. {
  1325.   register char *p;
  1326.   register int c;
  1327.  
  1328.   p = s;
  1329.  
  1330.   while (1)
  1331.     {
  1332.       c = (getccon () & NOPARITY);
  1333.       if (c == '\\')
  1334.     {
  1335.       putccon ('\\');
  1336.       c = (getccon () & NOPARITY);
  1337.       backup ();
  1338.       putccon (c);
  1339.       *p++ = c;
  1340.     }
  1341.       else if (c == ('G' & 037))
  1342.     {
  1343.       return (NULL);
  1344.     }
  1345.       else if ((c == '\n') || (c == '\r'))
  1346.     {
  1347.       *p = 0;
  1348.       return (s);
  1349.     }
  1350.       else if (c == '\b')
  1351.     {
  1352.       if (p != s)
  1353.         {
  1354.           p--;
  1355.           backup ();
  1356.           putccon (' ');
  1357.           backup ();
  1358.         }
  1359.     }
  1360.       else
  1361.     {
  1362.       *p++ = c;
  1363.       putccon (c);
  1364.     }
  1365.     }
  1366. }
  1367.  
  1368. void servermode (void)
  1369. {
  1370.   long rexxbit;
  1371.   long returnbits;
  1372.   rexxbit = upRexxPort ("IRexxSpell", rcl, NULL, &disp);
  1373.  
  1374.   setbuf (stdin, NULL);
  1375.   setbuf (stdout, NULL);
  1376.  
  1377.   while (KeepGoing)
  1378.     {
  1379.       returnbits = Wait (rexxbit | SIGBREAKF_CTRL_C);
  1380.       if (returnbits & SIGBREAKF_CTRL_C)
  1381.     KeepGoing = 0;
  1382.       if (returnbits & rexxbit)
  1383.     dispRexxPort ();
  1384.     }
  1385. /*
  1386.  *   With Rexx, we need to bring the port down.  You might make this
  1387.  *   part of exit() for programs that have multiple paths to exit.
  1388.  */
  1389.   dnRexxPort ();
  1390. }
  1391.  
  1392.  
  1393. /*
  1394.  *   Now we get into the actual code necessary for our REXX port; functions
  1395.  *   that do the real work.  Note that this program was not structured
  1396.  *   particularly nicely for Rexx; I had to write each of these functions.
  1397.  *   Many programs have these subroutines already in place; they are called
  1398.  *   as part of the event loop.  This progam, however, just has one big
  1399.  *   switch statement with different actions . . .
  1400.  *
  1401.  *   First, our locals.
  1402.  */
  1403. int userreplied;        /* has the current message been replied to yet? */
  1404. /*
  1405.  *   This is our main dispatch function.
  1406.  */
  1407. void disp (struct RexxMsg *msg, struct rexxCommandList *dat, char *p)
  1408. {
  1409.   dat->userdata(msg, p);
  1410.   return;
  1411. }
  1412.  
  1413. /*
  1414.  *   This handler adds a word to the `global personal dictionary.'
  1415.  *
  1416.  *   Now, in English, the word is added to whatever personal
  1417.  *   dictionary was found when ISpell was started up in ARexx
  1418.  *   server mode. (Under a multiuser system, we might want to
  1419.  *   restrict who can add words to this dictionary.  For now
  1420.  *   we just do it!  Yes, the AmigaOS is multiuser, hehe :-).
  1421.  *   No protection, the way true hackers like it, you (the 
  1422.  *   user) get more rope to hang yourself :-), err the system 
  1423.  *   with :-).
  1424.  */
  1425. void rexxadd (struct RexxMsg *msg, char *p)
  1426. {
  1427.   userreplied = 1;
  1428.   if (p[1])
  1429.     treeinsert (&(p[1]), 1);
  1430.   treeoutput ();
  1431.   replyRexxCmd (msg, 0L, 0L, "ok");
  1432. }
  1433.  
  1434. /*
  1435.  *   The quick version does not write the changes to disk.
  1436.  *   Useful if you will be adding many words.  Be sure to
  1437.  *   call rexxadd at the end of the list (pass a null word,
  1438.  *   or a valid new word to be added).
  1439.  */
  1440. void rexxquickadd (struct RexxMsg *msg, char *p)
  1441. {
  1442.   userreplied = 1;
  1443.   treeinsert (&(p[1]), 1);
  1444.   replyRexxCmd (msg, 0L, 0L, "ok");
  1445. }
  1446.  
  1447. /*
  1448.  *   This handler checks the spelling of a word.
  1449.  */
  1450. void rexxcheck (struct RexxMsg *msg, char *p)
  1451. {
  1452.   char buf[512];
  1453.   register int i;
  1454.  
  1455.   userreplied = 1;
  1456.   p++;
  1457.   if (good (p))
  1458.     {
  1459.       if (rootword[0] == 0)
  1460.     strcpy (buf, "*");
  1461.       else
  1462.     sprintf (buf, "+ %s", rootword);
  1463.     }
  1464.   else
  1465.     {
  1466.       makepossibilities (p);
  1467.       if (possibilities[0][0])
  1468.     {
  1469.       int bufend = 1;
  1470.       int possibilitysize;
  1471.  
  1472.       strcpy (buf, "&");
  1473.       for (i = 0; i < MAXPOSSIBLE; i++)
  1474.         {
  1475.           if (possibilities[i][0] == 0)
  1476.         break;
  1477.           possibilitysize = strlen(possibilities[i]);
  1478.           if ((possibilitysize + bufend) > 511)
  1479.         break;
  1480.           strcpy (&(buf[bufend++]), " ");
  1481.           strcpy (&(buf[bufend]), possibilities[i]);
  1482.           bufend += possibilitysize;
  1483.         }
  1484.     }
  1485.       else
  1486.     strcpy (buf, "#");
  1487.     }
  1488.   replyRexxCmd (msg, 0L, 0L, buf);
  1489. }
  1490.  
  1491. /*
  1492.  *   This handler checks the spelling of a word, it does
  1493.  *   not try to find replacement words as above.  It only
  1494.  *   determines whether or not the word is in the dictoinary.
  1495.  */
  1496. void rexxquickcheck (struct RexxMsg *msg, char *p)
  1497. {
  1498.   userreplied = 1;
  1499.   if (good (&(p[1])))
  1500.     {
  1501.       if (rootword[0] == 0)
  1502.     replyRexxCmd (msg, 0L, 0L, "ok");
  1503.       else
  1504.     replyRexxCmd (msg, 0L, 0L, "ok");
  1505.     }
  1506.   else
  1507.     replyRexxCmd (msg, 0L, 0L, "bad");
  1508. }
  1509.  
  1510. void rexxlookup (struct RexxMsg *msg, char *p)
  1511. {
  1512.   char buf[512];
  1513.   char cmd[512];
  1514.   char *rval;
  1515.   int whence = 0;
  1516.   int bufend = 1;
  1517.   int lookupsize;
  1518.  
  1519.   userreplied = 1;
  1520.   strcpy (buf, "&");
  1521.   sprintf (cmd, "^%s$", &(p[1]));
  1522.   while ((rval = do_regex_lookup (cmd, whence++)) != NULL)
  1523.     {
  1524.       lookupsize = strlen(rval);
  1525.       if ((lookupsize + bufend) > 511)
  1526.     break;
  1527.       strcpy (&(buf[bufend++]), " ");
  1528.       strcpy (&(buf[bufend]), rval);
  1529.       bufend += lookupsize;
  1530.     }
  1531.   replyRexxCmd (msg, 0L, 0L, buf);
  1532. }
  1533.  
  1534. /*
  1535.  *   This handler checks the spelling of a file.
  1536.  */
  1537. void rexxfilecheck (struct RexxMsg *msg, char *p)
  1538. {
  1539.   char *cp;
  1540.  
  1541.   userreplied = 1;
  1542.   currentfile = &(p[1]);
  1543.  
  1544.   if ((infile = fopen (&(p[1]), "r")) == NULL)
  1545.     {
  1546.       replyRexxCmd (msg, 0L, 0L, "Error: Can't open input file");
  1547.       return;
  1548.     }
  1549.  
  1550.   tmpnam (tempfile);
  1551.  
  1552.   if ((outfile = fopen (tempfile, "w")) == NULL)
  1553.     {
  1554.       replyRexxCmd (msg, 0L, 0L, "Error: Can't open output file");
  1555.       return;
  1556.     }
  1557.  
  1558.   quit = 0;
  1559.  
  1560.   /* See if the file is a .tex file.  If so, set the appropriate flag. */
  1561.   if ((cp = strrchr (&(p[1]), '.')) != NULL && strcmp (cp, ".tex") == 0)
  1562.     tflag = 1;
  1563.   else
  1564.     tflag = 0;
  1565.  
  1566.   lflag = 1;
  1567.  
  1568.   checkfile ();
  1569.  
  1570.   fclose (infile);
  1571.   fclose (outfile);
  1572.  
  1573.   replyRexxCmd (msg, 0L, 0L, tempfile);
  1574. }
  1575.  
  1576. /*
  1577.  *   This handler returns the version of the program.
  1578.  */
  1579. void rexxversion (struct RexxMsg *msg, char *p)
  1580. {
  1581.   char buf[512];
  1582.   int bufend = strlen(Version_ID);
  1583.   int namesize;
  1584.   int i;
  1585.  
  1586.   userreplied = 1;
  1587.   strcpy(buf, Version_ID);
  1588.   buf[bufend++] = '\n';
  1589.   for (i = 0; rcl[i].name != NULL; i++)
  1590.     {
  1591.       namesize = strlen(rcl[i].name);
  1592.       if ((namesize + bufend) > 511)
  1593.     break;
  1594.       strcpy (&(buf[bufend++]), " ");
  1595.       strcpy (&(buf[bufend]), rcl[i].name);
  1596.       bufend += namesize;
  1597.     }
  1598.   replyRexxCmd (msg, 0L, 0L, buf);
  1599. }
  1600.  
  1601. /*
  1602.  *   This handler sets the exit flag.
  1603.  */
  1604. void rexxexit (struct RexxMsg *msg, char *p)
  1605. {
  1606.   userreplied = 1;
  1607.   KeepGoing = 0;
  1608.   replyRexxCmd (msg, 0L, 0L, "bye");
  1609. }
  1610.  
  1611. void askmode (void)
  1612. {
  1613.   char buf[BUFSIZ];
  1614.   register int i;
  1615.  
  1616.   if (fflag)
  1617.     {
  1618.       if (freopen (askfilename, "w", stdout) == NULL)
  1619.     {
  1620.       fprintf (stderr, "Can't create %s\n", askfilename);
  1621.       exit (1);
  1622.     }
  1623.     }
  1624.  
  1625.   setbuf (stdin, NULL);
  1626.   setbuf (stdout, NULL);
  1627.  
  1628.   while (xgets (buf) != NULL)
  1629.     {
  1630.       /* *line is like `i', @line is like `a' */
  1631.       if (buf[0] == '*' || buf[0] == '@')
  1632.     {
  1633.       treeinsert (buf + 1, buf[0] == '*');
  1634.       fprintf (stdout, "*\n");
  1635.       treeoutput ();
  1636.     }
  1637.       else if (good (buf))
  1638.     {
  1639.       if (rootword[0] == 0)
  1640.         {
  1641.           fprintf (stdout, "*\n");    /* perfect match */
  1642.         }
  1643.       else
  1644.         {
  1645.           fprintf (stdout, "+ %s\n", rootword);
  1646.         }
  1647.     }
  1648.       else
  1649.     {
  1650.       makepossibilities (buf);
  1651.       if (possibilities[0][0])
  1652.         {
  1653.           fprintf (stdout, "& ");
  1654.           for (i = 0; i < MAXPOSSIBLE; i++)
  1655.         {
  1656.           if (possibilities[i][0] == 0)
  1657.             break;
  1658.           fprintf (stdout, "%s ", possibilities[i]);
  1659.         }
  1660.           fprintf (stdout, "\n");
  1661.         }
  1662.       else
  1663.         {
  1664.           fprintf (stdout, "#\n");
  1665.         }
  1666.     }
  1667.       if (sflag)
  1668.     {
  1669.       stop ();
  1670.       if (fflag)
  1671.         {
  1672.           rewind (stdout);
  1673.           creat (askfilename, 0666);
  1674.         }
  1675.     }
  1676.     }
  1677. }
  1678.  
  1679. /* Copy/ignore "cnt" number of characters pointed to by *cc. */
  1680. void copyout (char **cc, int cnt)
  1681. {
  1682.   while (--cnt >= 0)
  1683.     {
  1684.       if (*(*cc) == 0)
  1685.     break;
  1686.       if (!lflag)
  1687.     putc (*(*cc), outfile);
  1688.       (*cc)++;
  1689.     }
  1690. }
  1691.  
  1692. void lookharder (char *string)
  1693. {
  1694.   char cmd[150], grepstr[100];
  1695.   register char *g, *s;
  1696.  
  1697.   g = grepstr;
  1698.   for (s = string; *s != '\0'; s++)
  1699.     if (*s == '*')
  1700.       {
  1701.     *g++ = '.';
  1702.     *g++ = '*';
  1703.       }
  1704.     else
  1705.       *g++ = *s;
  1706.   *g = '\0';
  1707.   if (grepstr[0])
  1708.     regex_dict_lookup (cmd, grepstr);
  1709. }
  1710.  
  1711. void regex_dict_lookup (char *cmd, char *grepstr)
  1712. {
  1713.   char *do_regex_lookup ();
  1714.   char *rval;
  1715.   int whence = 0;
  1716.   int quit = 0;
  1717.   int count = 0;
  1718.   sprintf (cmd, "^%s$", grepstr);
  1719.   while (!quit && (rval = do_regex_lookup (cmd, whence++)) != NULL)
  1720.     {
  1721.       int ch;
  1722.       printcon ("%s\n", rval);;
  1723.       if ((count++ % (li - 1)) == 0)
  1724.     {
  1725.       inverse ();
  1726.       printcon ("-- more --");
  1727.       normal ();
  1728.       if ((ch = getccon ()) == 'q' || ch == 'Q' || ch == 'x' || ch == 'X')
  1729.         quit = 1;
  1730.       printcon ("\r                             \r");
  1731.     }
  1732.     }
  1733.   if (rval == NULL)
  1734.     {
  1735.       inverse ();
  1736.       printcon ("--eow--");
  1737.       normal ();
  1738.       getccon ();
  1739.     }
  1740. }
  1741.