home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume4 / se / part3 / docmd1.c next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  28.4 KB  |  1,572 lines

  1. /*
  2. ** docmd1.c
  3. **
  4. ** main command processor.  routines for individual commands
  5. */
  6.  
  7. #include "se.h"
  8. #include "extern.h"
  9.  
  10. /* static data definitions -- variables only needed in this file */
  11. static char Tlpat[MAXPAT] = "";    /* saved character list for y/t command */
  12. static char Tabstr[MAXLINE] = "";    /* string representation of tab stops */
  13. static char Ddir = FORWARD;        /* delete direction */
  14. static int Compress;            /* compress/expand tabs on read/write */
  15.  
  16. /* docmd --- handle all commands except globals */
  17.  
  18. int docmd (lin, i, glob, status)
  19. char lin[];
  20. int i, glob, *status;
  21. {
  22.     char file[MAXLINE], sub[MAXPAT];
  23.     char kname;
  24.     int gflag, line3, pflag, flag, fflag, junk, allbut, tflag;
  25.     int append (), ckchar (), ckp (), ckupd (), copy ();
  26.     int delete (), domark (), doopt (), doprnt (), doread ();
  27.     int doshell ();
  28.     int dotlit (), doundo (), dowrit (), getfn (), getkn ();
  29.     int getone (), getrange (), getrhs (), getstr (), inject ();
  30.     int join (), makset (), move (), nextln (), optpat ();
  31.     int prevln (), substr (), draw_box ();
  32.     char *expand_env ();
  33.  
  34.  
  35.     *status = ERR;
  36.     if (intrpt ())  /* catch a pending interrupt */
  37.         return (*status);
  38.  
  39.     switch (lin[i]) {
  40.     case APPENDCOM:
  41.     case UCAPPENDCOM:
  42.         if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  43.         {
  44.             defalt (Curln, Curln);
  45.             if (lin[i + 1] == '\n')
  46.             {
  47.                 /* avoid updating with inline insertion */
  48.                 adjust_window (Line1, Line2);
  49.                 updscreen ();
  50.             }
  51.             *status = append (Line2, &lin[i + 1]);
  52.         }
  53.         break;
  54.  
  55.     case PRINTCUR:
  56.         if (lin[i + 1] == '\n')
  57.         {
  58.             defalt (Curln, Curln);
  59.             saynum (Line2);
  60.             *status = OK;
  61.         }
  62.         break;
  63.  
  64.     case OVERLAYCOM:
  65.     case UCOVERLAYCOM:
  66.         defalt (Curln, Curln);
  67.         if (lin[i + 1] == '\n')
  68.             overlay (status);
  69.         break;
  70.  
  71.     case CHANGE:
  72.     case UCCHANGE:
  73.         defalt (Curln, Curln);
  74.         if (Line1 <= 0)
  75.             Errcode = EORANGE;
  76.         else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  77.         {
  78.             if (lin[i + 1] == '\n')
  79.             {
  80.                 /* avoid updating with inline insertion */
  81.                 adjust_window (Line2, Line2);
  82.                 updscreen ();
  83.             }
  84.             First_affected = min (First_affected, Line1);
  85.             if (lin[i + 1] == '\n')
  86.                 warn_deleted (Line1, Line2);
  87.             *status = append (Line2, &lin[i + 1]);
  88.             if (*status != ERR)
  89.             {
  90.                 line3 = Curln;
  91.                 delete (Line1, Line2, status);
  92.                 Curln = line3 - (Line2 - Line1 + 1);
  93.                 /* adjust for deleted lines */
  94.             }
  95.         }
  96.         break;
  97.  
  98.     case DELCOM:
  99.     case UCDELCOM:
  100.         if (ckp (lin, i + 1, &pflag, status) == OK)
  101.         {
  102.             defalt (Curln, Curln);
  103.             if (delete (Line1, Line2, status) == OK
  104.                 && Ddir == FORWARD
  105.                 && nextln (Curln) != 0)
  106.                 Curln = nextln (Curln);
  107.         }
  108.         break;
  109.  
  110.     case INSERT:
  111.     case UCINSERT:
  112.         defalt (Curln, Curln);
  113.         if (Line1 <= 0)
  114.             Errcode = EORANGE;
  115.         else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
  116.         {
  117.             if (lin[i + 1] == '\n')
  118.             {
  119.                 /* avoid updating with inline insertion */
  120.                 adjust_window (Line1, Line2);
  121.                 updscreen ();
  122.             }
  123.             *status = append (prevln (Line2), &lin[i + 1]);
  124.         }
  125.         break;
  126.  
  127.     case MOVECOM:
  128.     case UCMOVECOM:
  129.         i++;
  130.         if (getone (lin, &i, &line3, status) == EOF)
  131.             *status = ERR;
  132.         if (*status == OK && ckp (lin, i, &pflag, status) == OK)
  133.         {
  134.             defalt (Curln, Curln);
  135.             *status = move (line3);
  136.         }
  137.         break;
  138.  
  139.     case COPYCOM:
  140.     case UCCOPYCOM:
  141.         if (! Unix_mode)
  142.             goto translit;    /* SWT uses 't' for translit */
  143.         /* else
  144.             fall through and act normally */
  145.     docopy:
  146.         i++;
  147.         if (getone (lin, &i, &line3, status) == EOF)
  148.             *status = ERR;
  149.         if (*status == OK && ckp (lin, i, &pflag, status) == OK)
  150.         {
  151.             defalt (Curln, Curln);
  152.             *status = copy (line3);
  153.         }
  154.         break;
  155.  
  156.     case SUBSTITUTE:
  157.     case UCSUBSTITUTE:
  158.         i++;
  159.         if (lin[i] == '\n')
  160.         {
  161.             /* turn "s\n" into "s//%/\n" */
  162.             lin[i+0] = '/';
  163.             lin[i+1] = '/';
  164.             lin[i+2] = Unix_mode ? '%' : '&';
  165.             lin[i+3] = '/';
  166.             lin[i+4] = '\n';
  167.             lin[i+5] = EOS;
  168.             Peekc = SKIP_RIGHT;
  169.         }
  170.         else
  171.         {
  172.             /* try to handle "s/stuff\n" */
  173.             int j, missing_delim;
  174.  
  175.             missing_delim = YES;
  176.             for (j = i + 1; lin[j] != '\n'; j++)
  177.                 if (lin[j] == ESCAPE && lin[j+1] == lin[i])
  178.                     j++;    /* skip esc, loop continues */
  179.                 else if (lin[j] == lin[i])
  180.                 {
  181.                     missing_delim = NO;
  182.                     break;    /* for */
  183.                 }
  184.  
  185.             if (missing_delim)
  186.             {
  187.                 for (; lin[j] != EOS; j++)
  188.                     ;
  189.                 j--;        /* j now at newline */
  190.  
  191.                 lin[j] = lin[i];    /* delim */
  192.                 lin[++j] = '\n';
  193.                 lin[++j] = EOS;
  194.                 Peekc = SKIP_RIGHT;
  195.                 /* rest of routines will continue to fix up */
  196.             }
  197.         }
  198.  
  199.         if (optpat (lin, &i) == OK
  200.             && getrhs (lin, &i, sub, &gflag) == OK
  201.             && ckp (lin, i + 1, &pflag, status) == OK)
  202.         {
  203.             defalt (Curln, Curln);
  204.             *status = subst (sub, gflag, glob);
  205.         }
  206.         break;
  207.  
  208.     case TLITCOM:
  209.     case UCTLITCOM:
  210.         if (! Unix_mode)
  211.             goto docopy;    /* SWT uses 'y' for copying */
  212.         /* else
  213.             fall through and act normally */
  214.     translit:
  215.         i++;
  216.         if (lin[i] == '\n')
  217.         {
  218.             /* turn "y\n" into "y//%/\n" */
  219.             lin[i+0] = '/';
  220.             lin[i+1] = '/';
  221.             lin[i+2] = Unix_mode ? '%' : '&';
  222.             lin[i+3] = '/';
  223.             lin[i+4] = '\n';
  224.             lin[i+5] = EOS;
  225.             Peekc = SKIP_RIGHT;
  226.         }
  227.         else
  228.         {
  229.             /* try to handle "y/stuff\n" */
  230.             int j, missing_delim;
  231.  
  232.             missing_delim = YES;
  233.             for (j = i + 1; lin[j] != '\n'; j++)
  234.                 if (lin[j] == ESCAPE && lin[j+1] == lin[i])
  235.                     j++;    /* skip esc, loop continues */
  236.                 else if (lin[j] == lin[i])
  237.                 {
  238.                     missing_delim = NO;
  239.                     break;    /* for */
  240.                 }
  241.  
  242.             if (missing_delim)
  243.             {
  244.                 for (; lin[j] != EOS; j++)
  245.                     ;
  246.                 j--;        /* j now at newline */
  247.  
  248.                 lin[j] = lin[i];    /* delim */
  249.                 lin[++j] = '\n';
  250.                 lin[++j] = EOS;
  251.                 Peekc = SKIP_RIGHT;
  252.                 /* rest of routines will continue to fix up */
  253.             }
  254.         }
  255.  
  256.         if (getrange (lin, &i, Tlpat, MAXPAT, &allbut) == OK
  257.             && makset (lin, &i, sub, MAXPAT) == OK
  258.             && ckp (lin, i + 1, &pflag, status) == OK)
  259.         {
  260.             defalt (Curln, Curln);
  261.             *status = dotlit (sub, allbut);
  262.         }
  263.         break;
  264.  
  265.     case JOINCOM:
  266.     case UCJOINCOM:
  267.         i++;
  268.         if (getstr (lin, &i, sub, MAXPAT) == OK
  269.             && ckp (lin, i + 1, &pflag, status) == OK)
  270.         {
  271.             defalt (prevln (Curln), Curln);
  272.             *status = join (sub);
  273.         }
  274.         break;
  275.  
  276.     case UNDOCOM:
  277.     case UCUNDOCOM:
  278.         i++;
  279.         defalt (Curln, Curln);
  280.         if (ckchar (UCDELCOM, DELCOM, lin, &i, &flag, status) == OK
  281.             && ckp (lin, i, &pflag, status) == OK)
  282.             *status = doundo (flag, status);
  283.         break;
  284.  
  285.     case ENTER:
  286.     case UCENTER:
  287.         i++;
  288.         if (Nlines != 0)
  289.             Errcode = EBADLNR;
  290.         else if (ckupd (lin, &i, ENTER, status) == OK
  291.             && ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
  292.             if (getfn (lin, i - 1, file) == OK)
  293.             {
  294.                 strcpy (Savfil, expand_env (file));
  295.                 mesg (Savfil, FILE_MSG);
  296.                 clrbuf ();
  297.                 mkbuf ();
  298.                 dfltsopt (file);
  299.                 *status = doread (0, file, tflag);
  300.                 First_affected = 0;
  301.                 Curln = min (1, Lastln);
  302.                 Buffer_changed = NO;
  303.             }
  304.             else
  305.                 *status = ERR;
  306.         break;
  307.  
  308.     case PRINTFIL:
  309.     case UCPRINTFIL:
  310.         if (Nlines != 0)
  311.             Errcode = EBADLNR;
  312.         else if (getfn (lin, i, file) == OK)
  313.         {
  314.             strcpy (Savfil, expand_env (file));
  315.             mesg (Savfil, FILE_MSG);
  316.             *status = OK;
  317.         }
  318.         break;
  319.  
  320.     case READCOM:
  321.     case UCREADCOM:
  322.         i++;
  323.         if (ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
  324.             if (getfn (lin, i - 1, file) == OK)
  325.             {
  326.                 defalt (Curln, Curln);
  327.                 *status = doread (Line2, file, tflag);
  328.             }
  329.         break;
  330.  
  331.     case WRITECOM:
  332.     case UCWRITECOM:
  333.         i++;
  334.         flag = NO;
  335.         fflag = NO;
  336.         junk = ckchar ('>', '+', lin, &i, &flag, &junk);
  337.         if (flag == NO)
  338.             junk = ckchar ('!', '!', lin, &i, &fflag, &junk);
  339.         junk = ckchar ('x', 'X', lin, &i, &tflag, &junk);
  340.         if (getfn (lin, i - 1, file) == OK)
  341.         {
  342.             defalt (1, Lastln);
  343.             *status = dowrit (Line1, Line2, file, flag, fflag, tflag);
  344.         }
  345.         break;
  346.  
  347.     case PRINT:
  348.     case UCPRINT:
  349.         if (lin[i + 1] == '\n')
  350.         {
  351.             defalt (1, Topln);
  352.             *status = doprnt (Line1, Line2);
  353.         }
  354.         break;
  355.  
  356.     case PAGECOM:
  357.         defalt (1, min (Lastln, Botrow - Toprow + Topln));
  358.         if (Line1 <= 0)
  359.             Errcode = EORANGE;
  360.         else if (lin[i + 1] == '\n')
  361.         {
  362.             Topln = Line2;
  363.             Curln = Line2;
  364.             First_affected = Line2;
  365.             *status = OK;
  366.         }
  367.         break;
  368.  
  369.     case NAMECOM:
  370.     case UCNAMECOM:
  371.         i++;
  372.         if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
  373.             && lin[i] == '\n')
  374.             uniquely_name (kname, status);
  375.         break;
  376.  
  377.     case MARKCOM:
  378.     case UCMARKCOM:
  379.         i++;
  380.         if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
  381.             && lin[i] == '\n')
  382.         {
  383.             defalt (Curln, Curln);
  384.             *status = domark (kname);
  385.         }
  386.         break;
  387.  
  388.     case '\n':
  389.         line3 = nextln (Curln);
  390.         defalt (line3, line3);
  391.         *status = doprnt (Line2, Line2);
  392.         break;
  393.  
  394.     case LOCATECMD:
  395.     case UCLOCATECMD:
  396.         if (lin[i+1] == '\n')
  397.         {
  398.             char *sysname ();
  399.  
  400.             remark (sysname ());
  401.             *status = OK;
  402.         }
  403.         break;
  404.  
  405.     case OPTCOM:
  406.     case UCOPTCOM:
  407.         if (Nlines == 0)
  408.             *status = doopt (lin, &i);
  409.         else
  410.             Errcode = EBADLNR;
  411.         break;
  412.  
  413.     case QUIT:
  414.     case UCQUIT:
  415.         i++;
  416.         if (Nlines != 0)
  417.             Errcode = EBADLNR;
  418.         else if (ckupd (lin, &i, QUIT, status) == OK)
  419.             if (lin[i] == '\n')
  420.                 *status = EOF;
  421.             else
  422.                 *status = ERR;
  423.         break;
  424.  
  425.     case HELP:
  426.     case UCHELP:
  427.         i++;
  428.         if (Nlines == 0)
  429.             dohelp (lin, &i, status);
  430.         else
  431.             Errcode = EBADLNR;
  432.         break;
  433.  
  434.     case MISCCOM:        /* miscellanious features */
  435.     case UCMISCCOM:
  436.         i++;
  437.         switch (lin[i]) {
  438.         case 'b':    /* draw box */
  439.         case 'B':
  440.             defalt (Curln, Curln);
  441.             i++;
  442.             *status = draw_box (lin, &i);
  443.             break;
  444.  
  445.         default:
  446.             Errcode = EWHATZAT;
  447.             break;
  448.         }
  449.         break;
  450.  
  451.     case SHELLCOM:
  452.         if (! Unix_mode)
  453.             error ("in docmd: can't happen.");
  454.     shellcom:
  455.         i++;
  456.         defalt (Curln, Curln);
  457.         *status = doshell (lin, &i);
  458.         break;
  459.  
  460.     case '~':
  461.         if (! Unix_mode)
  462.             goto shellcom;
  463.         /* else
  464.             fall through to default
  465.             which will generate an error */
  466.  
  467.     default:
  468.         Errcode = EWHATZAT;    /* command not recognized */
  469.         break;
  470.     }
  471.  
  472.     if (*status == OK)
  473.         Probation = NO;
  474.  
  475.     return (*status);
  476. }
  477.  
  478.  
  479. /* dohelp --- display documentation about editor */
  480.  
  481. dohelp (lin, i, status)
  482. char lin[];
  483. int *i, *status;
  484. {
  485.     char filename[MAXLINE];
  486.     char swt_filename[MAXLINE];
  487.     static char helpdir[] = "/usr/local/lib/se_h";    /* help scripts */
  488.     int j;
  489.     FILE *fp, *fopen ();
  490.  
  491.     SKIPBL (lin, *i);
  492.     if (lin[*i] == NEWLINE)
  493.         sprintf (filename, "%s/elp", helpdir);
  494.     else
  495.     {
  496.         /* build filename from text after "h" */
  497.         sprintf (filename, "%s/%s", helpdir, &lin[*i]);
  498.         j = strlen (filename);
  499.         filename[j-1] = EOS;    /* lop off newline */
  500.     }
  501.  
  502.     /* map to lower case */
  503.     for (j = 0; filename[j] != EOS; j++)
  504.         if (isupper (filename[j]))
  505.             filename[j] = tolower (filename[j]);
  506.  
  507.     sprintf (swt_filename, "%s_swt", filename);
  508.  
  509.     if (! Unix_mode && access (swt_filename, 4) == 0)
  510.         strcpy (filename, swt_filename);
  511.         /* SWT version of help file exists, use it */
  512.     /* else
  513.         use Unix or normal version of the help file */
  514.  
  515.     *status = OK;
  516.     if ((fp = fopen (filename, "r")) == NULL)
  517.     {
  518.         *status = ERR;
  519.         Errcode = ENOHELP;
  520.     }
  521.     else
  522.     {
  523. #ifdef u3b2
  524.         /* 3B2 seems to have problems with stdio and malloc... */
  525.         char buf[BUFSIZ];
  526.         setbuf (fp, buf);
  527. #endif
  528.  
  529.         /* status is OK */
  530.         display_message (fp);    /* display the help script */
  531.         fclose (fp);
  532.     }
  533. }
  534.  
  535.  
  536. /* doopt --- interpret option command */
  537.  
  538. int doopt (lin, i)
  539. char lin[];
  540. int *i;
  541. {
  542.     int temp, line, stat;
  543.     char tempstr[4];
  544.     int ret;
  545.     int dosopt ();
  546.     int ctoi ();
  547.  
  548.     (*i)++;
  549.     ret = ERR;
  550.  
  551.     switch (lin[*i]) {
  552.  
  553.     case 'g':        /* substitutes in a global can(not) fail */
  554.     case 'G':
  555.         if (lin[*i + 1] == '\n')
  556.         {
  557.             ret = OK;
  558.             Globals = ! Globals;    /* toggle */
  559.             if (Globals == YES)
  560.                 remark ("failed global substitutes continue");
  561.             else
  562.                 remark ("failed global substitutes stop");
  563.         }
  564.         break;
  565.  
  566.     case 'h':
  567.     case 'H':        /* do/don't use hardware insert/delete */
  568.         if (lin[*i + 1] == '\n')
  569.         {
  570.             ret = OK;
  571.             No_hardware = ! No_hardware;
  572.             if (No_hardware == YES)
  573.                 remark ("no line insert/delete");
  574.             else
  575.                 remark ("line insert/delete");
  576.         }
  577.         break;
  578.  
  579.     case 'k':        /* tell user if buffer saved or not */
  580.     case 'K':
  581.         if (lin[*i + 1] == '\n')
  582.         {
  583.             ret = OK;
  584.             if (Buffer_changed == YES)
  585.                 remark ("not saved");
  586.             else
  587.                 remark ("saved");
  588.         }
  589.         break;
  590.  
  591.  
  592.     case 'z':    /* suspend the editor process */
  593.     case 'Z':
  594.         if (lin[*i + 1] == '\n')
  595.         {
  596.             ret = OK;
  597. #ifdef BSD
  598.             if (Catching_stops)
  599.             {
  600.                 char *getenv ();
  601.  
  602.                 /*
  603.                  * order the test this way so that it fails
  604.                  * immediately in the usual case
  605.                  */
  606.                 if (getenv ("RSE") != NULL && At_gtics)
  607.                 {
  608.                     remark ("You may not suspend me");
  609.                     break;    /* switch */
  610.                 }
  611.                 else if (Buffer_changed == YES)
  612.                     fprintf (stderr, "WARNING: buffer not saved\n");
  613.                 kill (getpid(), SIGTSTP);
  614.                 /* stop_hdlr() will do all the work for us */
  615.             }
  616. #else
  617.             remark ("process suspension not available");
  618. #endif
  619.         }
  620.         break;
  621.  
  622.     case 't':    /* set or display tab stops for expanding tabs */
  623.     case 'T':
  624.         ++(*i);
  625.         if (lin[*i] == '\n')
  626.         {
  627.             remark (Tabstr);
  628.             ret = OK;
  629.         }
  630.         else
  631.         {
  632.             ret = settab (&lin[*i]);
  633.             if (ret == OK)
  634.                 strcpy (Tabstr, &lin[*i]);
  635.             else    /* defaults were set */
  636.                 strcpy (Tabstr, "+4");
  637.         }
  638.         break;
  639.  
  640.     case 'w':    /* set or display warning column */
  641.     case 'W':
  642.         ++(*i);
  643.         if (lin[*i] == '\n')
  644.             ret = OK;
  645.         else
  646.         {
  647.             temp = ctoi (lin, i);
  648.             if (lin[*i] == '\n')
  649.                 if (temp > 0 && temp < MAXLINE - 3)
  650.                 {
  651.                     ret = OK;
  652.                     Warncol = temp;
  653.                 }
  654.                 else
  655.                     Errcode = ENONSENSE;
  656.         }
  657.         if (ret == OK)
  658.             saynum (Warncol);
  659.         break;
  660.  
  661.     case '-':    /* fix window in place on screen, or erase it */
  662.         ++(*i);
  663.         if (getnum (lin, i, &line, &stat) == EOF)
  664.         {
  665.             mesg ("", HELP_MSG);
  666.             if (Toprow > 0)
  667.             {
  668.                 Topln = max (1, Topln - Toprow);
  669.                 Toprow = 0;
  670.                 First_affected = Topln;
  671.             }
  672.             ret = OK;
  673.         }
  674.         else if (stat != ERR && lin[*i] == '\n')
  675.             if (Toprow + (line - Topln + 1) < Cmdrow)
  676.             {
  677.                 Toprow += line - Topln + 1;
  678.                 Topln = line + 1;
  679.                 for (temp = 0; temp < Ncols; temp++)
  680.                     load ('-', Toprow - 1, temp);
  681.                 if (Topln > Lastln)
  682.                     adjust_window (1, Lastln);
  683.                 if (Curln < Topln)
  684.                     Curln = min (Topln, Lastln);
  685.                 ret = OK;
  686.             }
  687.             else
  688.                 Errcode = EORANGE;
  689.         break;
  690.  
  691.     case 'a':    /* toggle absolute line numbering */
  692.     case 'A':
  693.         if (lin[*i + 1] == '\n')
  694.         {
  695.             Absnos = ! Absnos;
  696.             ret = OK;
  697.         }
  698.         break;
  699.  
  700.     case 'c':    /* toggle case option */
  701.     case 'C':
  702.         if (lin[*i + 1] == '\n')
  703.         {
  704.             ret = OK;
  705.             Invert_case = ! Invert_case;
  706.             if (Rel_a == 'A')
  707.             {
  708.                 Rel_a = 'a';
  709.                 Rel_z = 'z';
  710.             }
  711.             else
  712.             {
  713.                 Rel_a = 'A';
  714.                 Rel_z = 'Z';
  715.             }
  716.         }
  717.  
  718.         mesg (Invert_case ? "CASE" : "", CASE_MSG);
  719.         break;
  720.  
  721.     case 'd':    /* set or display placement of "." after a delete */
  722.     case 'D':
  723.         if (lin[*i + 1] == '\n')
  724.         {
  725.             if (Ddir == FORWARD)
  726.                 remark (">");
  727.             else
  728.                 remark ("<");
  729.             ret = OK;
  730.         }
  731.         else if (lin[*i + 2] != '\n')
  732.             Errcode = EODLSSGTR;
  733.         else if (lin[*i + 1] == '>')
  734.         {
  735.             ret = OK;
  736.             Ddir = FORWARD;
  737.         }
  738.         else if (lin[*i + 1] == '<')
  739.         {
  740.             ret = OK;
  741.             Ddir = BACKWARD;
  742.         }
  743.         else
  744.             Errcode = EODLSSGTR;
  745.         break;
  746.  
  747.     case 'v':    /* set or display overlay column */
  748.     case 'V':
  749.         ++(*i);
  750.         if (lin[*i] == '\n')
  751.         {
  752.             if (Overlay_col == 0)
  753.                 remark ("$");
  754.             else
  755.                 saynum (Overlay_col);
  756.             ret = OK;
  757.         }
  758.         else
  759.         {
  760.             if (lin[*i] == '$' && lin[*i + 1] == '\n')
  761.             {
  762.                 Overlay_col = 0;
  763.                 ret = OK;
  764.             }
  765.             else
  766.             {
  767.                 temp = ctoi (lin, i);
  768.                 if (lin[*i] == '\n')
  769.                 {
  770.                     Overlay_col = temp;
  771.                     ret = OK;
  772.                 }
  773.                 else
  774.                     Errcode = ENONSENSE;
  775.             }
  776.         }
  777.         break;
  778.  
  779.     case 'u':    /* set or display character for unprintable chars */
  780.     case 'U':
  781.         if (lin[*i + 1] == '\n')
  782.         {
  783.             ret = OK;
  784.             tempstr[0] = tempstr[2] = '"';
  785.             tempstr[1] = Unprintable;
  786.             tempstr[3] = EOS;
  787.             remark (tempstr);
  788.         }
  789.         else if (lin[*i + 2] == '\n')
  790.         {
  791.             if (lin[*i + 1] < ' ' || lin[*i + 1] >= DEL)
  792.                 Errcode = ENONSENSE;
  793.             else 
  794.             {
  795.                 ret = OK;
  796.                 if (Unprintable != lin[*i + 1])
  797.                 {
  798.                     Unprintable = lin[*i + 1];
  799.                     First_affected = Topln;
  800.                 }
  801.             }
  802.         }
  803.         break;
  804.  
  805.     case 'l':    /* set or display line number display option */
  806.     case 'L':
  807.         if (lin[*i+1] == '\n')
  808.         {
  809.             Nchoise = EOS;
  810.             ret = OK;
  811.         }
  812.         else if (lin[*i + 2] == '\n' && 
  813.             (lin[*i + 1] == CURLINE || lin[*i + 1] == LASTLINE
  814.             || lin[*i + 1] == TOPLINE))
  815.         {
  816.             Nchoise = lin[*i + 1];
  817.             ret = OK;
  818.         }
  819.         else if (lin[*i + 1] == 'm' || lin[*i + 1] == 'M')
  820.         {
  821.             /* set or display the left margin */
  822.             (*i)++;
  823.             if (lin[*i + 1] == '\n')
  824.             {
  825.                 saynum (Firstcol + 1);
  826.                 ret = OK;
  827.             }
  828.             else 
  829.             {
  830.                 (*i)++;
  831.                 temp = ctoi (lin, i);
  832.                 if (lin[*i] == '\n')
  833.                     if (temp > 0 && temp < MAXLINE)
  834.                     {
  835.                         First_affected = Topln;
  836.                         Firstcol = temp - 1;
  837.                         ret = OK;
  838.                     }
  839.                     else
  840.                         Errcode = ENONSENSE;
  841.             }
  842.         }
  843.         break;
  844.  
  845.     case 'f':    /* fortran (ugh, yick, gross) options */
  846.     case 'F':
  847.         if (lin[*i + 1] == '\n')
  848.             ret = dosopt ("f");
  849.         break;
  850.  
  851.     case 's':    /* set source options */
  852.     case 'S':
  853.         ret = dosopt (&lin[*i + 1]);
  854.         break;
  855.  
  856.     case 'i':    /* set or display indent option */
  857.     case 'I':
  858.         ++(*i);
  859.         if (lin[*i] == '\n')
  860.             ret = OK;
  861.         else if ((lin[*i] == 'a' || lin[*i] == 'A') && lin[*i + 1] == '\n')
  862.         {
  863.             Indent = 0;
  864.             ret = OK;
  865.         }
  866.         else
  867.         {
  868.             temp = ctoi (lin, i);
  869.             if (lin[*i] == '\n')
  870.                 if (temp > 0 && temp < MAXLINE - 3)
  871.                 {
  872.                     ret = OK;
  873.                     Indent = temp;
  874.                 }
  875.                 else
  876.                     Errcode = ENONSENSE;
  877.         }
  878.         if (ret == OK)
  879.             if (Indent > 0)
  880.                 saynum (Indent);
  881.             else
  882.                 remark ("auto");
  883.         break;
  884.  
  885.     case 'm':    /* toggle mail notification */
  886.     case 'M':
  887.         if (lin[*i + 1] == '\n')
  888.         {
  889.             Notify = ! Notify;    /* toggle notification */
  890.             remark (Notify ? "notify on" : "notify off");
  891.             ret = OK;
  892.         }
  893.         break;
  894.  
  895.     case 'p':        /* toggle pattern and command style */
  896.     case 'P':        /* if additional letter there, it forces mode */
  897.         ret = OK;
  898.         switch (lin[*i + 1]) {
  899.         case EOS:
  900.         case '\n':    /* toggle */
  901.             if (Unix_mode)
  902.                 goto no_unix;
  903.                 /* currently in Unix mode */
  904.                 /* switch to SWT style patterns */
  905.             else
  906.                 goto yes_unix;
  907.                 /* currently in SWT mode */
  908.                 /* switch to Unix style patterns */
  909.  
  910.             break;
  911.  
  912.         case 's':    /* force SWT mode */
  913.         case 'S':
  914.     no_unix:    Unix_mode = NO;
  915.             BACKSCAN = '\\';
  916.             NOTINCCL = '~';
  917.             XMARK = '!';
  918.             ESCAPE = '@';
  919.             break;
  920.  
  921.         case 'u':    /* force UNIX mode */
  922.         case 'U':
  923.     yes_unix:    Unix_mode = YES;
  924.             BACKSCAN = '?';
  925.             NOTINCCL = '^';
  926.             XMARK = '~';
  927.             ESCAPE = '\\';
  928.             break;
  929.         
  930.         default:
  931.             Errcode = EOWHAT;
  932.             ret = ERR;
  933.             goto out_of_here;
  934.         }
  935.         set_patterns (Unix_mode);
  936.         mesg (Unix_mode ? "UNIX" : "SWT", MODE_MSG);
  937.     out_of_here:
  938.         break;
  939.     
  940.     case 'x':
  941.     case 'X':    /* toggle tab compression */
  942.         if (lin[*i + 1] == '\n')
  943.         {
  944.             ret = OK;
  945.             Compress = ! Compress;
  946.             mesg (Compress ? "XTABS" : "", COMPRESS_MSG);
  947.         }
  948.         break;
  949.  
  950.     case 'y':    /* encrypt files */
  951.     case 'Y':
  952.         if (lin[*i + 1] == '\n')
  953.         {
  954.         crypt_toggle:
  955.             ret = OK;
  956.             Crypting = ! Crypting;
  957.             if (Crypting )
  958.                 do {
  959.                     getkey ();
  960.                     if (Key[0] == EOS)
  961.                         remark ("Empty keys are not allowed.\n");
  962.                 } while (Key[0] == EOS);
  963.             else
  964.                 Key[0] = EOS;
  965.         }
  966.         else
  967.         {
  968.             register int j;
  969.  
  970.             ret = OK;
  971.             (*i)++;        /* *i was the 'y' */
  972.             while (isspace (lin[*i]) && lin[*i] != '\n')
  973.                 (*i)++;
  974.             if (lin[*i] != '\n' && lin[*i] != EOS)
  975.             {
  976.                 for (j = 0; lin[*i] != '\n' && lin[*i] != EOS;
  977.                     j++, (*i)++)
  978.                     Key[j] = lin[*i];
  979.                 Key[j] = EOS;
  980.                 Crypting = YES;
  981.             }
  982.             else
  983.                 goto crypt_toggle;
  984.         }
  985.         mesg (Crypting ? "ENCRYPT" : "", CRYPT_MSG);
  986.         break;
  987.  
  988.     default:
  989.         Errcode = EOWHAT;
  990.  
  991.     }
  992.  
  993.     return (ret);
  994. }
  995.  
  996.  
  997. /* domark --- name lines line1 through line2 as kname */
  998.  
  999. int domark (kname)
  1000. char kname;
  1001. {
  1002.     int line;
  1003.     int ret;
  1004.     register LINEDESC *k;
  1005.     LINEDESC *getind ();
  1006.  
  1007.     if (Line1 <= 0)
  1008.     {
  1009.         Errcode = EORANGE;
  1010.         ret = ERR;
  1011.     }
  1012.     else
  1013.     {
  1014.         k = getind (Line1);
  1015.         for (line = Line1; line <= Line2; line++)
  1016.         {
  1017.             if (intrpt())
  1018.                 return (ERR);
  1019.             k -> Markname = kname;
  1020.             k = NEXTLINE(k);
  1021.         }
  1022.         ret = OK;
  1023.     }
  1024.     return (ret);
  1025. }
  1026.  
  1027.  
  1028. /* doprnt --- set curln, locate window */
  1029.  
  1030. int doprnt (from, to)
  1031. int from, to;
  1032. {
  1033.  
  1034.     if (from <= 0)
  1035.     {
  1036.         Errcode = EORANGE;
  1037.         return (ERR);
  1038.     }
  1039.  
  1040.     adjust_window (from, to);
  1041.     Curln = to;
  1042.     return (OK);
  1043. }
  1044.  
  1045.  
  1046. /* doread --- read "file" after "line" */
  1047.  
  1048. int doread (line, file, tflag)
  1049. int line;
  1050. char *file;
  1051. int tflag;
  1052. {
  1053.     register int count, len, i;
  1054.     int ret;
  1055.     int strlen ();
  1056.     FILE *fd;
  1057.     FILE *fopen (), *crypt_open ();
  1058.     char lin1[MAXLINE], lin2[MAXLINE];
  1059.     char *fgets ();
  1060.     register LINEDESC *ptr;
  1061.     LINEDESC *sp_inject ();
  1062.     LINEDESC *getind ();
  1063.     char *expand_env ();
  1064.  
  1065.     file = expand_env (file);    /* expand $HOME, etc. */
  1066.  
  1067.     if (Savfil[0] == EOS)
  1068.     {
  1069.         strcpy (Savfil, file);
  1070.         mesg (Savfil, FILE_MSG);
  1071.     }
  1072.  
  1073.     if (Crypting)
  1074.         fd = crypt_open (file, "r");
  1075.     else
  1076.         fd = fopen (file, "r");
  1077.  
  1078.     if (fd == NULL)
  1079.     {
  1080.         ret = ERR;
  1081.         Errcode = ECANTREAD;
  1082.     }
  1083.     else
  1084.     {
  1085.         First_affected = min (First_affected, line + 1);
  1086.         ptr = getind (line);
  1087.         ret = OK;
  1088. #ifndef OLD_SCRATCH
  1089.         Curln = line;
  1090. #endif
  1091.         remark ("reading");
  1092.         for (count = 0; fgets (lin1, MAXLINE, fd) != NULL; count++)
  1093.         {
  1094.             if (intrpt ())
  1095.             {
  1096.                 ret = ERR;
  1097.                 break;
  1098.             }
  1099.             if (Compress == NO && tflag == NO)
  1100.                 ptr = sp_inject (lin1, strlen (lin1), ptr);
  1101.             else
  1102.             {
  1103.                 len = 0;
  1104.                 for (i = 0; lin1[i] != EOS && len < MAXLINE - 1; i++)
  1105.                     if (lin1[i] != '\t')
  1106.                         lin2[len++] = lin1[i];
  1107.                     else
  1108.                         do
  1109.                             lin2[len++] = ' ';
  1110.                         while (len % 8 != 0 
  1111.                             && len < MAXLINE - 1);
  1112.                 lin2[len] = EOS;
  1113.                 if (len >= MAXLINE)
  1114.                 {
  1115.                     ret = ERR;
  1116.                     Errcode = ETRUNC;
  1117.                 }
  1118.                 ptr = sp_inject (lin2, len, ptr);
  1119.             }
  1120.             if (ptr == NOMORE)
  1121.             {
  1122.                 ret = ERR;
  1123.                 break;
  1124.             }
  1125.         }
  1126.         if (Crypting)
  1127.             crypt_close (fd);
  1128.         else
  1129.             fclose (fd);
  1130.         saynum (count);
  1131.         Curln = line + count;
  1132.         svins (line, count);
  1133.     }
  1134.  
  1135.     return (ret);
  1136. }
  1137.  
  1138.  
  1139. /* dosopt --- set source language-related options */
  1140.  
  1141. int dosopt (lin)
  1142. char lin[];
  1143. {
  1144.     char lang[8];
  1145.     int i;
  1146.     int strbsr ();
  1147.     static struct {
  1148.         char *txt;
  1149.         int val;
  1150.     } ltxt[] = {    
  1151.         "",     1,
  1152.         "as",   2,
  1153.         "c",    3,
  1154.         "d",    1,
  1155.         "data", 1,
  1156.         "f",    4,
  1157.         "h",    3,
  1158.         "n",    1,
  1159.         "nr",   1,
  1160.         "nroff",1,
  1161.         "p",    3,
  1162.         "r",    3,
  1163.         "s",    2,
  1164.     };
  1165.  
  1166.     i = 0;
  1167.     getwrd (lin, &i, lang, 8);
  1168.  
  1169.     strmap (lang, 'a');
  1170.  
  1171.     i = strbsr ((char *)ltxt, sizeof (ltxt), sizeof (ltxt[0]), lang);
  1172.     if (i == EOF)
  1173.     {
  1174.         Errcode = ENOLANG;
  1175.         return (ERR);
  1176.     }
  1177.  
  1178.     switch (ltxt[i].val) {
  1179.     case 1:
  1180.         Warncol = 74;
  1181.         Rel_a = 'A';
  1182.         Rel_z = 'Z';
  1183.         Invert_case = NO;
  1184.         strcpy (Tabstr, "+4");
  1185.         settab (Tabstr);
  1186.         Compress = NO;
  1187.         break;
  1188.  
  1189.     case 3:
  1190.         Warncol = 74;
  1191.         Rel_a = 'A';
  1192.         Rel_z = 'Z';
  1193.         Invert_case = NO;
  1194.         strcpy (Tabstr, "+8");
  1195.         settab (Tabstr);
  1196.         Compress = YES;
  1197.         break;
  1198.     case 4:
  1199.         Warncol = 72;
  1200.         Rel_a = 'A';
  1201.         Rel_z = 'Z';
  1202.         Invert_case = NO;
  1203.         strcpy (Tabstr, "7+3");
  1204.         settab (Tabstr);
  1205.         Compress = YES;
  1206.         break;
  1207.  
  1208.     case 2:
  1209.         Warncol = 72;
  1210.         Rel_a = 'A';
  1211.         Rel_z = 'Z';
  1212.         Invert_case = NO;
  1213.         strcpy (Tabstr, "17+8");
  1214.         settab (Tabstr);
  1215.         Compress = YES;
  1216.         break;
  1217.     }
  1218.  
  1219.     mesg (Invert_case == YES ? "CASE" : "", CASE_MSG);
  1220.     mesg (Compress == YES ? "XTABS" : "", COMPRESS_MSG);
  1221.  
  1222.     return (OK);
  1223. }
  1224.  
  1225.  
  1226. /* dotlit --- transliterate characters */
  1227.  
  1228. int dotlit (sub, allbut)
  1229. char sub[];
  1230. int allbut;
  1231. {
  1232.     char new[MAXLINE];
  1233.     char kname;
  1234.     int collap, x, i, j, line, lastsub, status;
  1235.     int ret;
  1236.     LINEDESC *inx;
  1237.     LINEDESC *gettxt (), *getind ();
  1238.  
  1239.     ret = ERR;
  1240.     if (Line1 <= 0)
  1241.     {
  1242.         Errcode = EORANGE;
  1243.         return (ret);
  1244.     }
  1245.  
  1246.     if (First_affected > Line1)
  1247.         First_affected = Line1;
  1248.  
  1249.     lastsub = strlen (sub) - 1;
  1250.     if ((strlen (Tlpat)  - 1) > lastsub || allbut == YES)
  1251.         collap = YES;
  1252.     else
  1253.         collap = NO;
  1254.  
  1255.     for (line = Line1; line <= Line2; line++)
  1256.     {
  1257.         if (intrpt ())    /* check for interrupts */
  1258.             return (ERR);
  1259.  
  1260.         inx = gettxt (line);    /* get text of line into txt, return index */
  1261.         j = 0;
  1262.         for (i = 0; Txt[i] != EOS && Txt[i] != '\n'; i++)
  1263.         {
  1264.             x = xindex (Tlpat, Txt[i], allbut, lastsub);
  1265.             if (collap == YES && x >= lastsub && lastsub >= 0)    /* collapse */
  1266.             {
  1267.                 new[j] = sub[lastsub];
  1268.                 j++;
  1269.                 for (i++; Txt[i] != EOS && Txt[i] != '\n'; i++)
  1270.                 {
  1271.                     x = xindex (Tlpat, Txt[i], allbut, lastsub);
  1272.                     if (x < lastsub)
  1273.                         break;
  1274.                 }
  1275.             }
  1276.             if (Txt[i] == EOS || Txt[i] == '\n')
  1277.                 break;
  1278.             if (x >= 0 && lastsub >= 0)    /* transliterate */
  1279.             {
  1280.                 new[j] = sub[x];
  1281.                 j++;
  1282.             }
  1283.             else if (x < 0)        /* copy */
  1284.             {
  1285.                 new[j] = Txt[i];
  1286.                 j++;
  1287.             }
  1288.             /* else
  1289.                 delete */
  1290.         }
  1291.  
  1292.         if (Txt[i] == '\n')    /* add a newline, if necessary */
  1293.         {
  1294.             new[j] = '\n';
  1295.             j++;
  1296.         }
  1297.         new[j] = EOS;        /* add the EOS */
  1298.  
  1299.         kname = inx -> Markname;    /* save the markname */
  1300.         delete (line, line, &status);
  1301.         ret = inject (new);
  1302.         if (ret == ERR)
  1303.             break;
  1304.         inx = getind (Curln);
  1305.         inx -> Markname = kname;    /* set markname */
  1306.         ret = OK;
  1307.         Buffer_changed = YES;
  1308.     }
  1309.  
  1310.     return (ret);
  1311. }
  1312.  
  1313. /* doundo --- restore last set of lines deleted */
  1314.  
  1315. int doundo (dflg, status)
  1316. int dflg;
  1317. int *status;
  1318. {
  1319.     LINEDESC *l1, *l2, *k1, *k2;
  1320.     LINEDESC *getind ();
  1321.     int oldcnt;
  1322.     int nextln (), prevln ();
  1323.  
  1324.     *status = ERR;
  1325.     if (dflg == NO && Line1 <= 0)
  1326.         Errcode = EORANGE;
  1327.     else if (Limbo == NOMORE)
  1328.         Errcode = ENOLIMBO;
  1329.     else if (Line1 > Line2)
  1330.         Errcode = EBACKWARD;
  1331.     else if (Line2 > Lastln)
  1332.         Errcode = ELINE2;
  1333.     else
  1334.     {
  1335.         *status = OK;
  1336.         Curln = Line2;
  1337. #ifdef OLD_SCRATCH
  1338.         k1 = getind (Line2);
  1339.         k2 = getind (nextln (Line2));
  1340.         l1 = Limbo;
  1341.         l2 = l1 -> Prevline;
  1342.         relink (k1, l1, l2, k2);
  1343.         relink (l2, k2, k1, l1);
  1344. #else
  1345.         blkmove (Limbo - Buf, MAXBUF - 1, Line2);
  1346. #endif
  1347.         svins (Line2, Limcnt);
  1348.         oldcnt = Limcnt;
  1349.         Limcnt = 0;
  1350.         Limbo = NOMORE;
  1351.         Lastln += oldcnt;
  1352.         if (dflg == NO)
  1353.             delete (Line1, Line2, status);
  1354.         Curln += oldcnt;
  1355.         if (First_affected > Line1)
  1356.             First_affected = Line1;
  1357.     }
  1358.  
  1359.     return (*status);
  1360. }
  1361.  
  1362. /* dowrit --- write "from" through "to" into file */
  1363.  
  1364. int dowrit (from, to, file, aflag, fflag, tflag)
  1365. int from, to, aflag, fflag, tflag;
  1366. char *file;
  1367. {
  1368.     FILE *fd;
  1369.     FILE *fopen (), *crypt_open ();
  1370.     register int line, ret, i, j;
  1371.     int strcmp (), access ();
  1372.     char tabs[MAXLINE];
  1373.     register LINEDESC *k;
  1374.     LINEDESC *getind ();
  1375.     char *expand_env ();
  1376.  
  1377.     ret = ERR;
  1378.     if (from <= 0)
  1379.         Errcode = EORANGE;
  1380.  
  1381.     else
  1382.     {
  1383.         file = expand_env (file);    /* expand $HOME, etc. */
  1384.  
  1385.         if (aflag == YES)
  1386.         {
  1387.             if (Crypting)
  1388.                 fd = crypt_open (file, "a");
  1389.             else
  1390.                 fd = fopen (file, "a");
  1391.         }
  1392.         else if (strcmp (file, Savfil) == 0 || fflag == YES
  1393.             || Probation == WRITECOM || access (file, 0) == -1)
  1394.         {
  1395.             if (Crypting)
  1396.                 fd = crypt_open (file, "w");
  1397.             else
  1398.                 fd = fopen (file, "w");
  1399.         }
  1400.         else
  1401.         {
  1402.             Errcode = EFEXISTS;
  1403.             Probation = WRITECOM;
  1404.             return (ret);
  1405.         }
  1406.         if (fd == NULL)
  1407.             Errcode = ECANTWRITE;
  1408.         else
  1409.         {
  1410.             ret = OK;
  1411.             remark ("writing");
  1412.             k = getind (from);
  1413.             for (line = from; line <= to; line++)
  1414.             {
  1415.                 if (intrpt ())
  1416.                     return (ERR);
  1417.                 gtxt (k);
  1418.                 if (Compress == NO && tflag == NO)
  1419.                     fputs (Txt, fd);
  1420.                 else
  1421.                 {
  1422.                     for (i = 0; Txt[i] == ' '; i++)
  1423.                         ;
  1424.                     for (j = 0; j < i / 8; j++)
  1425.                         tabs[j] = '\t';
  1426.                     tabs[j] = EOS;
  1427.                     fputs (tabs, fd);
  1428.                     fputs (&Txt[j * 8], fd);
  1429.                 }
  1430.                 k = NEXTLINE(k);
  1431.             }
  1432.             if (Crypting)
  1433.                 crypt_close (fd);
  1434.             else
  1435.                 fclose (fd);
  1436.             sync ();    /* just in case the system crashes */
  1437.             saynum (line - from);
  1438.             if (from == 1 && line - 1 == Lastln)
  1439.                 Buffer_changed = NO;
  1440.         }
  1441.     }
  1442.     return (ret);
  1443. }
  1444.  
  1445. /* expand_env --- expand environment variables in file names */
  1446.  
  1447. char *expand_env (file)
  1448. register char *file;
  1449. {
  1450.     register int i, j, k;    /* indices */
  1451.     char *getenv ();
  1452.     char var[MAXLINE];        /* variable name */
  1453.     char *val;            /* value of environment variable */
  1454.     static char buf[MAXLINE * 2];    /* expanded file name, static to not go away */
  1455.  
  1456.  
  1457.     i = j = k = 0;
  1458.     while (file[i] != EOS)
  1459.     {
  1460.         if (file[i] == ESCAPE)
  1461.         {
  1462.             if (file[i+1] == '$')
  1463.             {
  1464.                 buf[j++] = file[++i];    /* the actual $ */
  1465.                 i++;    /* for next time around the loop */
  1466.             }
  1467.             else
  1468.                 buf[j++] = file[i++];    /* the \ */
  1469.         }
  1470.         else if (file[i] != '$')    /* normal char */
  1471.             buf[j++] = file[i++];
  1472.         else            /* environment var */
  1473.         {
  1474.             i++;    /* skip $ */
  1475.             k = 0;
  1476.             while (file[i] != '/' && file[i] != EOS)
  1477.                 var[k++] = file[i++];    /* get var name */
  1478.             var[k] = EOS;
  1479.  
  1480.             if ((val = getenv (var)) != NULL)
  1481.                 for (k = 0; val[k] != EOS; k++)
  1482.                     buf[j++] = val[k];
  1483.                     /* copy val into file name */
  1484.             /* else
  1485.                 var not in enviroment; leave file
  1486.                 name alone, multiple slashes are legal */
  1487.         }
  1488.     }
  1489.     buf[j] = EOS;
  1490.  
  1491.     return (buf);
  1492. }
  1493.  
  1494. /* crypt_open -- run files through crypt */
  1495.  
  1496. FILE *crypt_open (file, mode)
  1497. char *file, *mode;
  1498. {
  1499.     char buf[MAXLINE];
  1500.     FILE *fp, *popen ();
  1501.  
  1502.     if (! Crypting)
  1503.         return (NULL);
  1504.  
  1505.     while (Key[0] == EOS)
  1506.     {
  1507.         getkey ();
  1508.         if (Key[0] == EOS)
  1509.             printf ("The key must be non-empty!\n");
  1510.     }
  1511.  
  1512.     switch (mode[0]) {
  1513.     case 'r':
  1514.         sprintf (buf, "crypt %s < %s", Key, file);
  1515.         fp = popen (buf, "r");
  1516.         return (fp);        /* caller checks for NULL or not */
  1517.         break;
  1518.  
  1519.     case 'w':
  1520.         sprintf (buf, "crypt %s > %s", Key, file);
  1521.         fp = popen (buf, "w");
  1522.         return (fp);        /* caller checks for NULL or not */
  1523.         break;
  1524.  
  1525.     case 'a':
  1526.         sprintf (buf, "crypt %s >> %s", Key, file);
  1527.         fp = popen (buf, "w");
  1528.         return (fp);        /* caller checks for NULL or not */
  1529.         break;
  1530.     
  1531.     default:
  1532.         return (NULL);
  1533.     }
  1534. }
  1535.  
  1536. crypt_close (fp)
  1537. FILE *fp;
  1538. {
  1539.     pclose (fp);
  1540. }
  1541.  
  1542. /* getkey -- get an encryption key from the user */
  1543.  
  1544. #define repeat        do
  1545. #define until(cond)    while(!(cond))
  1546.  
  1547. getkey ()
  1548. {
  1549.     char *getpass ();    /* get input w/out echoing on screen */
  1550.  
  1551.     clrscreen ();        /* does NOT wipe out Screen_image */
  1552.     tflush ();
  1553.  
  1554.     ttynormal ();
  1555.  
  1556.     repeat
  1557.     {
  1558.         strcpy (Key, getpass ("Enter encryption key: "));
  1559.         if (strcmp (Key, getpass ("Again: ")) != 0)
  1560.         {
  1561.             Key[0] = EOS;
  1562.             fprintf (stderr, "didn't work. try again.\n");
  1563.         }
  1564.         /* else
  1565.             all ok */
  1566.     } until (Key[0] != EOS);
  1567.  
  1568.     ttyedit ();
  1569.  
  1570.     restore_screen ();
  1571. }
  1572.