home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / se / part01 / docmd1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-01-25  |  26.9 KB  |  1,499 lines

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