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

  1. #ifndef lint
  2. static char RCSid[] = "$Header: docmd2.c,v 1.3 86/07/17 17:20:29 arnold Exp $";
  3. #endif
  4.  
  5. /*
  6.  * $Log:    docmd2.c,v $
  7.  * Revision 1.3  86/07/17  17:20:29  arnold
  8.  * Some general code cleaning up.
  9.  * 
  10.  * Revision 1.2  86/07/11  15:11:04  osadr
  11.  * Removed Georgia Tech specific code.
  12.  * 
  13.  * Revision 1.1  86/05/06  13:36:57  osadr
  14.  * Initial revision
  15.  * 
  16.  * 
  17.  */
  18.  
  19. /*
  20. ** docmd2.c
  21. **
  22. ** routines to actually execute commands
  23. */
  24.  
  25. #include "se.h"
  26. #include "extern.h"
  27.  
  28.  
  29. /* append --- append lines after "line" */
  30.  
  31. append (line, str)
  32. int line;
  33. char str[];
  34. {
  35.     char lin[MAXLINE];
  36.     char term;
  37.     int ret;
  38.     int len, i, dpos, dotseen;
  39.     int inject ();
  40.  
  41.     Curln = line;
  42.  
  43.     if (str[0] == ':')    /* text to be added is in the command line */
  44.         ret = inject (&str[1]);
  45.     else
  46.     {
  47.         Cmdrow = Toprow + (Curln - Topln) + 1;  /* 1 below Curln */
  48.         lin[0] = EOS;
  49.         if (Indent > 0 || line <= 0)
  50.             len = max (0, Indent - 1);
  51.         else /* do auto indent */
  52.         {
  53.             LINEDESC *k, *gettxt ();
  54.             k = gettxt (line);
  55.             for (len = 0; Txt[len] == ' '; len++)
  56.                 ;
  57.         }
  58.         dpos = len;     /* position for terminating '.' */
  59.  
  60.         for (ret = NOSTATUS; ret == NOSTATUS; )
  61.         {
  62.             if (! hwinsdel())   /* do it the old, slow way */
  63.             {
  64.                 if (Cmdrow > Botrow)
  65.                 {
  66.                     Cmdrow = Toprow + 1;
  67.                     cprow (Botrow, Toprow);
  68.                     adjust_window (Curln, Curln);
  69.                     if (First_affected > Topln)
  70.                         First_affected = Topln;
  71.                 }
  72.                 clrrow (Cmdrow);
  73.                 if (Cmdrow < Botrow)
  74.                     clrrow (Cmdrow + 1);
  75.             }
  76.             else    /* try to be smart about it */
  77.             {
  78.                 if (Cmdrow > Botrow)
  79.                 {
  80.                     Cmdrow--;
  81.                     dellines (Toprow, 1);
  82.                     inslines (Cmdrow, 1);
  83.                     Topln++;
  84.                 }
  85.                 else
  86.                 {
  87.                     dellines (Botrow, 1);
  88.                     inslines (Cmdrow, 1);
  89.                 }
  90.             }
  91.             prompt ("apd>");
  92.             do
  93.                 getcmd (lin, Firstcol, &len, &term);
  94.             while (term == CURSOR_UP || term == CURSOR_DOWN
  95.                 || term == CURSOR_SAME);
  96.  
  97.             dotseen = 0;
  98.             if (lin[0] == '.' && lin[1] == '\n' && lin[2] == EOS)
  99.                 dotseen = 1;
  100.             for (i = 0; i < dpos && lin[i] == ' '; i++)
  101.                 ;
  102.             if (i == dpos && lin[dpos] == '.' && lin[dpos + 1] == '\n'
  103.                 && lin[dpos+2] == EOS)
  104.                 dotseen = 1;
  105.  
  106.             if (dotseen)
  107.             {
  108.                 if (hwinsdel())
  109.                 {
  110.                     dellines (Cmdrow, 1);
  111.                     inslines (Botrow, 1);
  112.                 }
  113.                 ret = OK;
  114.             }
  115.             else if (inject (lin) == ERR)
  116.                 ret = ERR;
  117.             else            /* inject occured */
  118.                 prompt ("");    /* erase prompt */
  119.             Cmdrow++;
  120.             if (term != FUNNY)
  121.             {
  122.                 if (Indent > 0)
  123.                     len = Indent - 1;
  124.                 else /* do auto indent */
  125.                     for (len = 0; lin[len] == ' '; len++)
  126.                         ;
  127.                 dpos = len;
  128.                 lin[0] = EOS;
  129.             }
  130.         }
  131.         Cmdrow = Botrow + 1;
  132.         if (hwinsdel())            /* since we take control */
  133.         {                /* of the screen, we're sure */
  134.             Sctop = Topln;        /* it's still OK */
  135.  
  136.             for (i = 0; i < Sclen; i++)
  137.                 Scline[i] = Sctop + i <= Lastln ? i : -1;
  138.         }
  139.     }
  140.     if (Curln == 0 && Lastln > 0)   /* for 0a or 1i followed by "." */
  141.         Curln = 1;
  142.     if (First_affected > line)
  143.         First_affected = line;
  144.  
  145.     tflush ();
  146.     return (ret);
  147. }
  148.  
  149. /* copy --- copy line1 through line2 after line3 */
  150.  
  151. int copy (line3)
  152. int line3;
  153. {
  154.     register int i;
  155.     int ret;
  156.     register LINEDESC *ptr3, *after3, *k;
  157.     LINEDESC *getind ();
  158.  
  159.     ret = ERR;
  160.  
  161. #ifdef OLD_SCRATCH
  162.     ptr3 = getind (line3);
  163.     after3 = ptr3 -> Nextline;
  164. #endif
  165.  
  166.     if (Line1 <= 0)
  167.         Errcode = EORANGE;
  168.     else
  169.     {
  170.         ret = OK;
  171.         Curln = line3;
  172.         k = getind (Line1);
  173.         for (i = Line1; i <= Line2; i++)
  174.         {
  175.             gtxt (k);
  176.             if (inject (Txt) == ERR || intrpt ())
  177.             {
  178.                 ret = ERR;
  179.                 break;
  180.             }
  181. #ifdef OLD_SCRATCH
  182.             if (k == ptr3)        /* make sure we don't copy stuff */
  183.                 k = after3;    /* that's already been copied */
  184.             else
  185.                 k = k -> Nextline;
  186. #else
  187.             if (Line1 < line3)
  188.                 k++;
  189.             else
  190.                 k += 2;
  191.             /*
  192.              * inject calls blkmove, which will shift the
  193.              * lines down one in the array, so we add two
  194.              * instead of one to get to the next line.
  195.              */
  196. #endif
  197.         }
  198.         First_affected = min (First_affected, line3 + 1);
  199.     }
  200.     return (ret);
  201. }
  202.  
  203.  
  204. /* delete --- delete lines from through to */
  205.  
  206. int delete (from, to, status)
  207. int from, to, *status;
  208. {
  209.     int nextln (), prevln ();
  210.     LINEDESC *k1, *k2, *j1, *j2, *l1;
  211.     LINEDESC *getind ();
  212.  
  213.     if (from <= 0)          /* can't delete line 0 */
  214.     {
  215.         *status = ERR;
  216.         Errcode = EORANGE;
  217.     }
  218.     else
  219.     {
  220.         if (First_affected > from)
  221.             First_affected = from;
  222. #ifdef OLD_SCRATCH
  223.         k1 = getind (prevln (from));
  224.         j1 = k1 -> Nextline;
  225.         j2 = getind (to);
  226.         k2 = j2 -> Nextline;
  227.         relink (k1, k2, k1, k2);        /* close chain around deletion */
  228. #else
  229.         blkmove (from, to, MAXBUF - 1);    /* stick at end of buffer */
  230. #endif
  231.  
  232.         Lastln -= to - from + 1;        /* adjust number of last line */
  233.         Curln = prevln (from);
  234.  
  235. #ifdef OLD_SCRATCH
  236.         if (Limbo != NOMORE)            /* discard lines in limbo */
  237.         {
  238.             l1 = Limbo -> Prevline;
  239.             Limbo -> Prevline = Free;
  240.             Free = l1;
  241.         }
  242. #endif
  243.  
  244.         Lost_lines += Limcnt;
  245.         Limcnt = to - from + 1;        /* number of lines "deleted" */
  246.  
  247. #ifdef OLD_SCRATCH
  248.         Limbo = j1;     /* put what we just deleted in limbo */
  249.         relink (j2, j1, j2, j1);        /* close the ring */
  250. #else
  251.         /* point at first deleted */
  252.         Limbo = &Buf[MAXBUF - (to - from + 1)];
  253. #endif
  254.         *status = OK;
  255.         svdel (from, to - from + 1);
  256.         Buffer_changed = YES;
  257.     }
  258.  
  259.     return (*status);
  260. }
  261.  
  262.  
  263. /* join --- join a group of lines into a single line */
  264.  
  265. int join (sub)
  266. char sub[];
  267. {
  268.     char new[MAXLINE];
  269.     register int l, line, sublen;
  270.     int ret;
  271.     int inject (), delete (), prevln (), strlen ();
  272.     register LINEDESC *k;
  273.     LINEDESC *getind ();
  274.  
  275.     ret = OK;
  276.     if (Line1 <= 0)
  277.     {
  278.         Errcode = EORANGE;
  279.         return (ERR);
  280.     }
  281.  
  282.     sublen = strlen (sub) + 1;      /* length of separator & EOS */
  283.     line = Line1;
  284.     k = getind (line);
  285.     gtxt (k);
  286.     move_ (Txt, new, (int) k -> Lineleng);    /* move in first chunk */
  287.     l = k -> Lineleng;
  288.  
  289.     for (line++; line <= Line2; line++)
  290.     {
  291.         if (intrpt ())
  292.             return (ERR);
  293.         if (new[l - 2] == '\n') /* zap the NEWLINE */
  294.             l--;
  295.         k = NEXTLINE(k);    /* get the next line */
  296.         gtxt (k);
  297.         if (l + sublen - 1 + k -> Lineleng - 1 > MAXLINE)    /* won't fit */
  298.         {
  299.             Errcode = E2LONG;
  300.             return (ERR);
  301.         }
  302.         move_ (sub, &new[l - 1], sublen);    /* insert separator string */
  303.         l += sublen - 1;
  304.         move_ (Txt, &new[l - 1], (int) k -> Lineleng);    /* move next line */
  305.         l += k -> Lineleng - 1;
  306.     }
  307.     Curln = Line2;          /* all this will replace line1 through line2 */
  308.     ret = inject (new);    /* inject the new line */
  309.     if (ret == OK)
  310.         ret = delete (Line1, Line2, &ret);    /* delete old lines */
  311.     Curln++;
  312.  
  313.     if (First_affected > Curln)
  314.         First_affected = Curln;
  315.  
  316.     return (ret);
  317. }
  318.  
  319.  
  320. /* move --- move line1 through line2 after line3 */
  321.  
  322. int move (line3)
  323. int line3;
  324. {
  325.     int nextln (), prevln ();
  326.     LINEDESC *k0, *k1, *k2, *k3, *k4, *k5;
  327.     LINEDESC *getind ();
  328.  
  329.     if (Line1 <= 0)
  330.     {
  331.         Errcode = EORANGE;
  332.         return (ERR);
  333.     }
  334.  
  335.     if (Line1 <= line3 && line3 <= Line2)
  336.     {
  337.         Errcode = EINSIDEOUT;
  338.         return (ERR);
  339.     }
  340.  
  341. #ifdef OLD_SCRATCH
  342.     k0 = getind (prevln (Line1));
  343.     k1 = k0 -> Nextline;
  344.     k2 = getind (Line2);
  345.     k3 = k2 -> Nextline;
  346.     relink (k0, k3, k0, k3);
  347. #else
  348.     blkmove (Line1, Line2, line3);
  349. #endif
  350.  
  351.     if (line3 > Line1)
  352.     {
  353.         Curln = line3;
  354. #ifdef OLD_SCRATCH
  355.         line3 -= Line2 - Line1 + 1;
  356. #endif
  357.     }
  358.     else
  359.         Curln = line3 + (Line2 - Line1 + 1);
  360.  
  361. #ifdef OLD_SCRATCH
  362.     k4 = getind (line3);
  363.     k5 = k4 -> Nextline;
  364.     relink (k4, k1, k2, k5);
  365.     relink (k2, k5, k4, k1);
  366. #endif
  367.  
  368.     Buffer_changed = YES;
  369.     First_affected = min (First_affected, min (Line1, line3));
  370.  
  371.     return (OK);
  372. }
  373.  
  374. /* overlay --- let user edit lines directly */
  375.  
  376. overlay (status)
  377. int *status;
  378. {
  379.     char savtxt[MAXLINE], term, kname;
  380.     static char empty[] = "\n";
  381.     int lng, vcol, lcurln, scurln;
  382.     int inject (), nextln (), prevln (), strcmp ();
  383.     LINEDESC *indx;
  384.     LINEDESC *getind (), *gettxt ();
  385.  
  386.     *status = OK;
  387.     if (Line1 == 0)
  388.     {
  389.         Curln = 0;
  390.         *status = inject (empty);
  391.         if (*status == ERR)
  392.             return;
  393.         First_affected = 1;
  394.         Line1 = 1;
  395.         Line2++;
  396.     }
  397.  
  398.     for (lcurln = Line1; lcurln <= Line2; lcurln++)
  399.     {
  400.         Curln = lcurln;
  401.         vcol = Overlay_col - 1;
  402.         do {
  403.             adjust_window (Curln, Curln);
  404.             updscreen ();
  405.             Cmdrow = Curln - Topln + Toprow;
  406.             indx = gettxt (Curln);
  407.             lng = indx -> Lineleng;
  408.             if (Txt[lng - 2] == '\n')       /* clobber newline */
  409.                 lng--;
  410.             if (vcol < 0)
  411.                 vcol = lng - 1;
  412.             while (lng - 1 < vcol)
  413.             {
  414.                 Txt[lng - 1] = ' ';
  415.                 lng++;
  416.             }
  417.             Txt[lng - 1] = '\n';
  418.             Txt[lng] = EOS;
  419.             move_ (Txt, savtxt, lng + 1);    /* make a copy of the line */
  420.             getcmd (Txt, Firstcol, &vcol, &term);
  421.             if (term == FUNNY)
  422.             {
  423.                 if (First_affected > Curln)
  424.                     First_affected = Curln;
  425.                 Cmdrow = Botrow + 1;
  426.                 return;
  427.             }
  428.             if (strcmp (Txt, savtxt) != 0)  /* was line changed? */
  429.             {
  430.                 kname = indx -> Markname;
  431.                 delete (Curln, Curln, status);
  432.                 scurln = Curln;
  433.                 if (*status == OK)
  434.                     *status = inject (Txt);
  435.                 if (*status == ERR)
  436.                 {
  437.                     Cmdrow = Botrow + 1;
  438.                     return;
  439.                 }
  440.                 indx = getind (nextln (scurln));
  441.                 indx -> Markname = kname;
  442.             }
  443.             else
  444.             {           /* in case end-of-line is moved */
  445.                 if (First_affected > Curln)
  446.                     First_affected = Curln;
  447.             }
  448.             switch (term) {
  449.             case CURSOR_UP:
  450.                 if (Curln > 1)
  451.                     Curln--;
  452.                 else
  453.                     Curln = Lastln;
  454.                 break;
  455.             case CURSOR_DOWN:
  456.                 if (Curln < Lastln)
  457.                     Curln++;
  458.                 else
  459.                     Curln = min (1, Lastln);
  460.                 break;
  461.             case CURSOR_SAME:
  462.                 vcol = 0;
  463.                 break;
  464.             }
  465.         } while (term == CURSOR_UP || 
  466.             term == CURSOR_DOWN ||
  467.             term == CURSOR_SAME);
  468.     }
  469.     Cmdrow = Botrow + 1;
  470.     return;
  471. }
  472.  
  473.  
  474. /* subst --- substitute "sub" for occurrences of pattern */
  475.  
  476. int subst (sub, gflag, glob)
  477. char sub[];
  478. int gflag, glob;
  479. {
  480.     char new[MAXLINE], kname;
  481.     register int line, m, k, lastm;
  482.     int j, junk, status, subbed, ret;
  483.     int tagbeg[10], tagend[10];
  484.     int amatch (), addset (), inject ();
  485.     register LINEDESC *inx;
  486.     LINEDESC *gettxt (), *getind ();
  487.  
  488.     if (Globals && glob)
  489.         ret = OK;
  490.     else
  491.         ret = ERR;
  492.  
  493.     if (Line1 <= 0)
  494.     {
  495.         Errcode = EORANGE;
  496.         return (ERR);
  497.     }
  498.  
  499.     /* the following code has been removed for your protection
  500.        index() occasionally grabs newlines out of the character class
  501.        counter in a pattern.  for example [0-9] doesn't work due to this
  502.  
  503.         if (index (Pat, '\n') != -1)    # never delete NEWLINE
  504.         {
  505.             Errcode = EBADPAT;
  506.             return (ERR);
  507.         }
  508.     */
  509.  
  510.     for (line = Line1; line <= Line2; line++)
  511.     {
  512.         if (intrpt ())
  513.             break;
  514.         j = 0;
  515.         subbed = NO;
  516.         inx = gettxt (line);
  517.         lastm = -1;
  518.         for (k = 0; Txt[k] != EOS; )
  519.         {
  520.             for (m = 1; m <= 9; m++)
  521.             {
  522.                 tagbeg[m] = -1;
  523.                 tagend[m] = -1;
  524.             }
  525.             if (gflag == YES || subbed == NO)
  526.                 m = amatch (Txt, k, Pat, &tagbeg[1], &tagend[1]);
  527.             else
  528.                 m = -1;
  529.             if (m > -1 && lastm != m)       /* replace matched text */
  530.             {
  531.                 subbed = YES;
  532.                 tagbeg[0] = k;
  533.                 tagend[0] = m;
  534.                 catsub (Txt, tagbeg, tagend, sub, new, &j, MAXLINE);
  535.                 lastm = m;
  536.             }
  537.             if (m == -1 || m == k)  /* no match or null match */
  538.             {
  539.                 junk = addset (Txt[k], new, &j, MAXLINE);
  540.                 k++;
  541.             }
  542.             else
  543.                 k = m;    /* skip matched text */
  544.         }
  545.         if (subbed == YES)
  546.         {
  547.             if (addset (EOS, new, &j, MAXLINE) == NO)
  548.             {
  549.                 ret = ERR;
  550.                 Errcode = E2LONG;
  551.                 break;
  552.             }
  553.             kname = inx -> Markname;
  554.             delete (line, line, &status);    /* remembers dot */
  555.             ret = inject (new);
  556.             if (First_affected > Curln)
  557.                 First_affected = Curln;
  558.             if (ret == ERR)
  559.                 break;
  560.             inx = getind (Curln);
  561.             inx -> Markname = kname;
  562.             ret = OK;
  563.             Buffer_changed = YES;
  564.         }
  565.         else    /* subbed == NO */
  566.             Errcode = ENOMATCH;
  567.     }
  568.  
  569.     return (ret);
  570. }
  571.  
  572.  
  573. /* uniquely_name --- mark-name line; make sure no other line has same name */
  574.  
  575. uniquely_name (kname, status)
  576. char kname;
  577. int *status;
  578. {
  579.     register int line;
  580.     register LINEDESC *k;
  581.  
  582.     defalt (Curln, Curln);
  583.  
  584.     if (Line1 <= 0)
  585.     {
  586.         *status = ERR;
  587.         Errcode = EORANGE;
  588.         return;
  589.     }
  590.  
  591.     *status = OK;
  592.     line = 0;
  593.     k = Line0;
  594.  
  595.     do {
  596.         line++;
  597.         k = NEXTLINE(k);
  598.         if (line == Line2)
  599.             k -> Markname = kname;
  600.         else if (k -> Markname == kname)
  601.             k -> Markname = DEFAULTNAME;
  602.     } while (line < Lastln);
  603.  
  604.     return;
  605. }
  606.  
  607.  
  608. /* draw_box --- draw or erase a box at coordinates in command line */
  609.  
  610. int draw_box (lin, i)
  611. char lin[];
  612. int *i;
  613. {
  614.     register int left, right, col, len;
  615.     int junk;
  616.     int ctoi (), strcmp (), inject (), delete ();
  617.     register LINEDESC *k;
  618.     LINEDESC *getind (), *gettxt ();
  619.     char text[MAXLINE];
  620.     char kname, ch;
  621.  
  622.     left = ctoi (lin, i);
  623.     if (left <= 0 || left > MAXLINE)
  624.     {
  625.         Errcode = EBADCOL;
  626.         return (ERR);
  627.     }
  628.  
  629.     if (lin[*i] == ',')
  630.     {
  631.         (*i)++;
  632.         SKIPBL (lin, *i);
  633.         right = ctoi (lin, i);
  634.         if (right <= 0 || right >= MAXLINE || left > right)
  635.         {
  636.             Errcode = EBADCOL;
  637.             return (ERR);
  638.         }
  639.     }
  640.     else
  641.         right = left;
  642.  
  643.     SKIPBL (lin, *i);
  644.     if (lin[*i] == '\n')
  645.         ch = ' ';
  646.     else
  647.         ch = lin[(*i)++];
  648.  
  649.     if (lin[*i] != '\n')
  650.     {
  651.         Errcode = EEGARB;
  652.         return (ERR);
  653.     }
  654.  
  655.     if (Line1 <= 0)
  656.     {
  657.         Errcode = EORANGE;
  658.         return (ERR);
  659.     }
  660.  
  661.     for (Curln = Line1; Curln <= Line2; Curln++)
  662.     {
  663.         k = gettxt (Curln);
  664.         len = k -> Lineleng;
  665.         move_ (Txt, text, len);
  666.  
  667.         if (text[len - 2] == '\n')
  668.             col = len - 1;
  669.         else
  670.             col = len;
  671.         while (col <= right)
  672.         {
  673.             text[col - 1] = ' ';
  674.             col++;
  675.         }
  676.         text[col - 1] = '\n';
  677.         text[col] = EOS;
  678.  
  679.         if (Curln == Line1 || Curln == Line2)
  680.             for (col = left; col <= right; col++)
  681.                 text[col - 1] = ch;
  682.         else
  683.         {
  684.             text[left - 1] = ch;
  685.             text[right - 1] = ch;
  686.         }
  687.  
  688.         if (strcmp (text, Txt) != 0)
  689.         {
  690.             kname = k -> Markname;
  691.             if (delete (Curln, Curln, &junk) == ERR
  692.                 || inject (text) == ERR)
  693.                 return (ERR);
  694.             k = getind (Curln);
  695.             k -> Markname = kname;
  696.             Buffer_changed = YES;
  697.         }
  698.     }
  699.  
  700.     Curln = Line1;        /* move to top of box */
  701.     if (First_affected > Curln)
  702.         First_affected = Curln;
  703.     adjust_window (Curln, Curln);
  704.     updscreen ();
  705.  
  706.     return (OK);
  707. }
  708.  
  709.  
  710. /* dfltsopt --- set the 's' option to the extension on the file name */
  711.  
  712. dfltsopt (name)
  713. char name[];
  714. {
  715.     int i;
  716.     int strlen (), dosopt ();
  717.  
  718.     for (i = strlen (name) - 1; i >= 0; i--)
  719.         if (name[i] == '.')
  720.         {
  721.             dosopt (&name[i + 1]);
  722.             break;
  723.         }
  724.     if (i < 0)
  725.         dosopt ("");
  726. }
  727.  
  728.  
  729.  
  730. /* doshell --- escape to the Shell to run one or more Unix commands */
  731.  
  732. /*
  733. ** emulate vi: if running just a shell, redraw the screen as
  734. ** soon as the shell exits. if running a program, let the user
  735. ** redraw the screen when he/she is ready.
  736. **
  737. ** also emulate USG Unix 5.0 ed: a ! as the first character is
  738. ** replaced by the previous shell command; an unescaped % is replaced
  739. ** by the saved file name. The expanded command is echoed.
  740. */
  741.  
  742. #ifdef BSD
  743. #define DEFAULT_PATH    "/bin/csh"
  744. #define DEF_SHELL    "csh"
  745. #else
  746. #define DEFAULT_PATH    "/bin/sh"
  747. #define DEF_SHELL    "sh"
  748. #endif
  749.  
  750. int doshell (lin, pi)
  751. char lin[];
  752. int *pi;
  753. {
  754.     int forkstatus, childstatus;
  755.     int (*save_quit)(), (*save_int)();
  756.     int int_hdlr ();
  757.     int (*signal())();
  758.     int i, auto_redraw;
  759.     char *path, *name, *p, *getenv ();
  760.     char new_command[MAXLINE];
  761.     int j, k;
  762.     static char sav_com[MAXLINE] = "";
  763.     int expanded = NO;
  764.  
  765.     if (Nlines == 0)        /* use normal 'ed' behavior */
  766.     {
  767.         tflush ();    /* flush out the terminal output */
  768.         position_cursor (Nrows - 1, 0);    /* bottom left corner */
  769.  
  770.         if ((p = getenv ("SHELL")) == NULL || strcmp (p, DEFAULT_PATH) == 0)
  771.         {
  772.             path = DEFAULT_PATH;
  773.             name = DEF_SHELL;    /* default */
  774.         }
  775. #ifdef BSD
  776.         /* on Berkeley systems, check the other shell */
  777.         else if (strcmp (p, "/bin/sh") == 0)
  778.         {
  779.             path = "/bin/sh";
  780.             name = "sh";
  781.         }
  782. #endif
  783.         else
  784.         {
  785.             if (p[0] == '/')    /* full pathname there */
  786.             {
  787.                 /* work backwards to find just name */
  788.                 path = p;
  789.                 i = strlen (p);
  790.                 while (p[i] != '/')
  791.                     i--;
  792.                 i++;        /* skip '/' */
  793.                 name = &p[i];
  794.             }
  795.             else
  796.             {
  797.                 char buf[MAXLINE];
  798.  
  799.                 sprintf (buf, "unknown shell, using %s",
  800.                     DEF_SHELL);
  801.                 remark (buf);
  802.                 path = DEFAULT_PATH;
  803.                 name = DEF_SHELL;
  804.             }
  805.         }
  806.  
  807.         auto_redraw = (lin[*pi] == '\n') ? YES : NO;
  808.  
  809.         /* build command, checking for leading !, and % anywhere */
  810.         if (lin[*pi] == '!')
  811.         {
  812.             if (sav_com[0] != EOS)
  813.             {
  814.                 for (j = 0; sav_com[j] != EOS; j++)
  815.                     new_command[j] = sav_com[j];
  816.                 if (new_command[j-1] == '\n')
  817.                     j--;
  818.                 (*pi)++;
  819.                 expanded = YES;
  820.             }
  821.             else
  822.             {
  823.                 Errcode = ENOCMD;
  824.                 return (ERR);
  825.             }
  826.         }
  827.         else
  828.             j = 0;
  829.  
  830.         for (i = *pi; lin[i] != EOS; i++)
  831.         {
  832.             if (lin[i] == ESCAPE)
  833.             {
  834.                 if (lin[i+1] != '%')
  835.                 {
  836.                     new_command[j++] = ESCAPE;
  837.                     new_command[j++] = lin[++i];
  838.                 }
  839.                 else
  840.                     new_command[j++] = lin[++i];
  841.             }
  842.             else if (lin[i] == '%')
  843.             {
  844.                 for (k = 0; Savfil[k] != EOS; k++)
  845.                     new_command[j++] = Savfil[k];
  846.                 expanded = YES;
  847.             }
  848.             else
  849.                 new_command[j++] = lin[i];
  850.         }
  851.  
  852.         if (new_command[j-1] == '\n')
  853.             j--;
  854.         new_command[j] = EOS;
  855.  
  856.         strcpy (sav_com, new_command);    /* save it */
  857.  
  858.         ttynormal ();
  859. #ifndef HARD_TERMS
  860.         t_exit ();
  861. #endif
  862.         write (1, "\n\n", 2);            /* clear out a line */
  863.  
  864.         forkstatus = fork();
  865.         if (forkstatus == -1)   /* the fork failed */
  866.         {
  867.             ttyedit ();
  868. #ifndef HARD_TERMS
  869.             t_init ();
  870. #endif
  871.             Errcode = ECANTFORK;
  872.             return ERR;
  873.         }
  874.  
  875.         if (forkstatus == 0)    /* we're in the child process */
  876.         {
  877.             signal (SIGINT, SIG_DFL);
  878.             signal (SIGQUIT, SIG_DFL);
  879. #ifdef BSD
  880.             if (strcmp (name, "sh") != 0)    /* not /bin/sh */
  881.                 signal (SIGTSTP, SIG_DFL);
  882.             else
  883.                 signal (SIGTSTP, SIG_IGN);
  884. #endif
  885.             if (auto_redraw)    /* no params; run a shell */
  886.             {
  887.                 execl (path, name, 0);
  888.                 _exit (RETERR);   /* exec failed, notify parent */
  889.             }
  890.             else
  891.             {
  892.                 if (expanded)        /* echo it */
  893.                     printf ("%s\n", new_command);
  894.  
  895.                 execl (path, name, "-c", new_command, 0);
  896.                 _exit (RETERR);
  897.             }
  898.         }
  899.  
  900.         /* we're in the parent process here */
  901.         save_int = signal (SIGINT, SIG_IGN);        /* ignore interrupts */
  902.         save_quit = signal (SIGQUIT, SIG_IGN);
  903.         while (wait (&childstatus) != forkstatus)
  904.             ;
  905.         save_int = signal (SIGINT, save_int);       /* catch interupts */
  906.         save_quit = signal (SIGQUIT, save_quit);
  907.         write (1, "\n\n", 2);    /* clear out some message space */
  908.         Currow = Nrows - 1;
  909.         Curcol = 0;
  910.         if ((childstatus >> 8) != 0)
  911.         {
  912.             ttyedit ();
  913. #ifndef HARD_TERMS
  914.             t_init ();
  915. #endif
  916.             Errcode = ENOSHELL;
  917.             return ERR;
  918.         }
  919.  
  920.         /* a la vi: */
  921.         if (! auto_redraw)
  922.         {
  923.             int c;
  924.  
  925.             printf ("type return to continue: ");
  926.             while ((c = getchar()) != '\n' && c != EOF)
  927.                 ;
  928.         }
  929.  
  930.         ttyedit ();
  931. #ifndef HARD_TERMS
  932.         t_init ();
  933. #endif
  934.         restore_screen ();
  935.  
  936.         return OK;
  937.     }
  938.  
  939.     else
  940.         remark ("Not implemented yet");
  941.     
  942.     return OK;
  943. }
  944.