home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / ksh48.zip / sh / vi.c < prev   
C/C++ Source or Header  |  1992-09-08  |  33KB  |  1,724 lines

  1. /*
  2.  *    vi command editing
  3.  *    written by John Rochester (initially for nsh)
  4.  *    bludgeoned to fit PD ksh by Larry Bouzane and Eric Gisin
  5.  *    Further hacked (bugfixes and tweaks) by Mike Jetzer
  6.  */
  7.  
  8. #include "config.h"
  9. #ifdef VI
  10.  
  11. #ifndef lint
  12. static char *RCSid = "$Id: vi.c,v 1.3 1992/08/10 12:03:31 sjg Exp $";
  13. #endif
  14.  
  15. #include "stdh.h"
  16. #include <unistd.h>
  17. #include <signal.h>
  18. #include <fcntl.h>
  19. #include <ctype.h>
  20. #include <errno.h>
  21. #include <setjmp.h>
  22. #include "sh.h"
  23. #include "expand.h"
  24. #include "edit.h"
  25.  
  26. #define CMDLEN        256
  27. #define Ctrl(c)        (c&0x1f)
  28. extern    int    histN();
  29.  
  30. static int      nextstate   ARGS((int ch));
  31. static int      vi_insert   ARGS((int ch));
  32. static int      vi_cmd      ARGS((int argcnt, char *cmd));
  33. static int      domove      ARGS((int argcnt, char *cmd, int sub));
  34. static int      redo_insert ARGS((int count));
  35. static          yank_range  ARGS((int a, int b));
  36. static int      bracktype   ARGS((int ch));
  37. static          edit_reset  ARGS((char *buf, int len));
  38. static int      putbuf      ARGS((char *buf, int len, int repl));
  39. static          stripblanks ARGS((void));
  40. static          del_range   ARGS((int a, int b));
  41. static int      findch      ARGS((int ch, int cnt, int forw, int incl));
  42. static int      forwword    ARGS((int argcnt));
  43. static int      backword    ARGS((int argcnt));
  44. static int      endword     ARGS((int argcnt));
  45. static int      Forwword    ARGS((int argcnt));
  46. static int      Backword    ARGS((int argcnt));
  47. static int      Endword     ARGS((int argcnt));
  48. static int      grabhist    ARGS((int save, int n));
  49. static int      grabsearch  ARGS((int save, int start, int fwd, char *pat));
  50. static          redraw_line ARGS((void));
  51. static          refresh     ARGS((int leftside));
  52. static int      outofwin    ARGS((void));
  53. static          rewindow    ARGS((void));
  54. static int      newcol      ARGS((int ch, int col));
  55. static          display     ARGS((char *wb1, char *wb2, int leftside));
  56. static          ed_mov_opt  ARGS((int col, char *wb));
  57.  
  58. #define C_    0x1
  59. #define M_    0x2
  60. #define E_    0x4
  61. #define X_    0x8
  62. #define U_    0x10
  63. #define B_    0x20
  64. #define O_    0x40
  65. #define S_    0x80
  66.  
  67. #define isbad(c)    (classify[c]&B_)
  68. #define iscmd(c)    (classify[c]&(M_|E_|C_|U_))
  69. #define ismove(c)    (classify[c]&M_)
  70. #define isextend(c)    (classify[c]&E_)
  71. #define islong(c)    (classify[c]&X_)
  72. #define ismeta(c)    (classify[c]&O_)
  73. #define isundoable(c)    (!(classify[c]&U_))
  74. #define issrch(c)    (classify[c]&S_)
  75.  
  76. char    classify[256] = {
  77.     B_,    0,    0,    0,    0,    0,    O_,    0,
  78. #if 1    /* Mike B. changes */
  79.     C_|M_,    0,    O_,    0,    O_,    O_,    O_,    0,
  80. #else
  81.     C_,    0,    O_,    0,    O_,    O_,    O_,    0,
  82. #endif
  83.     O_,    0,    C_|U_,    0,    0,    0,    0,    0,
  84.     0,    0,    O_,    0,    0,    0,    0,    0,
  85. #if 1    /* Mike B. changes */
  86.     C_|M_,    0,    0,    C_,    M_,    C_,    0,    0,
  87. #else
  88.     C_,    0,    0,    C_,    M_,    C_,    0,    0,
  89. #endif
  90.     0,    0,    C_,    C_,    M_,    C_,    0,    C_|S_,
  91.     M_,    0,    0,    0,    0,    0,    0,    0,
  92.     0,    0,    0,    M_,    0,    C_,    0,    C_|S_,
  93.     0,    C_,    M_,    C_,    C_,    M_,    M_|X_,    C_,
  94.     0,    C_,    0,    0,    0,    0,    C_,    0,
  95.     C_,    0,    C_,    C_,    M_|X_,    0,    0,    M_,
  96.     C_,    C_,    0,    0,    0,    0,    M_,    C_,
  97.     0,    C_,    M_,    E_,    E_,    M_,    M_|X_,    0,
  98.     M_,    C_,    C_,    C_,    M_,    0,    C_,    0,
  99.     C_,    0,    C_,    C_,    M_|X_,    C_|U_,    0,    M_,
  100.     C_,    E_,    0,    0,    0,    0,    C_,    0
  101. };
  102.  
  103. #define MAXVICMD    3
  104. #define SRCHLEN        40
  105.  
  106. #define INSERT        1
  107. #define REPLACE        2
  108.  
  109. #define VNORMAL        0
  110. #define VARG1        1
  111. #define VEXTCMD        2
  112. #define VARG2        3
  113. #define VXCH        4
  114. #define VFAIL        5
  115. #define VCMD        6
  116. #define VREDO        7
  117. #define VLIT        8
  118. #define VSEARCH        9
  119. #define VREPLACE1CHAR    10
  120.  
  121. struct edstate {
  122.     int    winleft;
  123.     char    *cbuf;
  124.     int    cbufsize;
  125.     int    linelen;
  126.     int    cursor;
  127. };
  128.  
  129. static char        undocbuf[CMDLEN];
  130.  
  131. static struct edstate    ebuf;
  132. static struct edstate    undobuf = { 0, undocbuf, CMDLEN, 0, 0 };
  133.  
  134. static struct edstate    *es;            /* current editor state */
  135. static struct edstate    *undo;
  136.  
  137. static char    ibuf[CMDLEN];        /* input buffer */
  138. static int    inslen;            /* length of input buffer */
  139. static int    srchlen;        /* length of current search pattern */
  140. static char    ybuf[CMDLEN];        /* yank buffer */
  141. static int    yanklen;        /* length of yank buffer */
  142. static int    fsavecmd = ' ';        /* last find command */
  143. static int    fsavech;        /* character to find */
  144. static char    lastcmd[MAXVICMD];    /* last non-move command */
  145. static int    lastac;            /* argcnt for lastcmd */
  146. static int    lastsearch = ' ';    /* last search command */
  147. static char    srchpat[SRCHLEN];    /* last search pattern */
  148. static int    insert;            /* non-zero in insert mode */
  149. static int    hnum;            /* position in history */
  150. static int    hlast;            /* 1 past last position in history */
  151. static int    modified;        /* buffer has been "modified" */
  152. static int    state;
  153.  
  154. #if 0
  155. vi_init()
  156. {
  157.     es = (struct edstate *) malloc((unsigned) sizeof(struct edstate));
  158.     fsavecmd = ' ';
  159.     lastsearch = ' ';
  160. }
  161.  
  162. edit_init()
  163. {
  164.     wbuf[0] = malloc((unsigned) (x_cols - 3));
  165.     wbuf[1] = malloc((unsigned) (x_cols - 3));
  166. }
  167. #endif
  168.  
  169. void
  170. vi_reset(buf, len)
  171.     char    *buf;
  172.     int    len;
  173. {
  174.     state = VNORMAL;
  175.     hnum = hlast = histnum(-1) + 1;
  176.     insert = INSERT;
  177.     yanklen = 0;
  178.     inslen = 0;
  179.     lastcmd[0] = 'a';
  180.     lastac = 1;
  181.     modified = 1;
  182.     edit_reset(buf, len);
  183. }
  184.  
  185. int
  186. vi_hook(ch)
  187.     int        ch;
  188. {
  189.     static char    curcmd[MAXVICMD];
  190.     static char    locpat[SRCHLEN];
  191.     static int    cmdlen;
  192.     static int    argc1, argc2;
  193.  
  194.     if (state != VSEARCH && (ch == '\r' || ch == '\n')) {
  195.         x_putc('\r');
  196.         x_putc('\n');
  197.         x_flush();
  198.         return 1;
  199.     }
  200.  
  201.     switch (state) {
  202.  
  203.     case VREPLACE1CHAR:
  204.         curcmd[cmdlen++] = ch;
  205.         state = VCMD;
  206.         break;
  207.  
  208.     case VNORMAL:
  209.         if (insert != 0) {
  210.             if (ch == Ctrl('v')) {
  211.                 state = VLIT;
  212.                 ch = '^';
  213.             }
  214.             if (vi_insert(ch) != 0) {
  215.                 x_putc(Ctrl('g'));
  216.                 state = VNORMAL;
  217.             } else {
  218.                 if (state == VLIT) {
  219.                     es->cursor--;
  220.                     refresh(0);
  221.                 } else
  222.                     refresh(insert != 0);
  223.             }
  224.         } else {
  225.             cmdlen = 0;
  226.             argc1 = 0;
  227.             if (ch >= '1' && ch <= '9') {
  228.                 argc1 = ch - '0';
  229.                 state = VARG1;
  230.             } else {
  231.                 curcmd[cmdlen++] = ch;
  232.                 state = nextstate(ch);
  233.                 if (state == VSEARCH) {
  234.                     save_cbuf();
  235.                     es->cursor = 0;
  236.                     es->linelen = 0;
  237.                     if (ch == '/') {
  238.                         if (putbuf("/", 1, 0) != 0) {
  239.                             return -1;
  240.                         }
  241.                     } else if (putbuf("?", 1, 0) != 0)
  242.                             return -1;
  243.                     refresh(0);
  244.                 }
  245.             }
  246.         }
  247.         break;
  248.  
  249.     case VLIT:
  250.         if (isbad(ch)) {
  251.             del_range(es->cursor, es->cursor + 1);
  252.             x_putc(Ctrl('g'));
  253.         } else
  254.             es->cbuf[es->cursor++] = ch;
  255.         refresh(1);
  256.         state = VNORMAL;
  257.         break;
  258.  
  259.     case VARG1:
  260.         if (isdigit(ch))
  261.             argc1 = argc1 * 10 + ch - '0';
  262.         else {
  263.             curcmd[cmdlen++] = ch;
  264.             state = nextstate(ch);
  265.         }
  266.         break;
  267.  
  268.     case VEXTCMD:
  269.         argc2 = 0;
  270.         if (ch >= '1' && ch <= '9') {
  271.             argc2 = ch - '0';
  272.             state = VARG2;
  273.             return 0;
  274.         } else {
  275.             curcmd[cmdlen++] = ch;
  276.             if (ch == curcmd[0])
  277.                 state = VCMD;
  278.             else if (ismove(ch))
  279.                 state = nextstate(ch);
  280.             else
  281.                 state = VFAIL;
  282.         }
  283.         break;
  284.  
  285.     case VARG2:
  286.         if (isdigit(ch))
  287.             argc2 = argc2 * 10 + ch - '0';
  288.         else {
  289.             if (argc1 == 0)
  290.                 argc1 = argc2;
  291.             else
  292.                 argc1 *= argc2;
  293.             curcmd[cmdlen++] = ch;
  294.             if (ch == curcmd[0])
  295.                 state = VCMD;
  296.             else if (ismove(ch))
  297.                 state = nextstate(ch);
  298.             else
  299.                 state = VFAIL;
  300.         }
  301.         break;
  302.  
  303.     case VXCH:
  304.         if (ch == Ctrl('['))
  305.             state = VNORMAL;
  306.         else {
  307.             curcmd[cmdlen++] = ch;
  308.             state = VCMD;
  309.         }
  310.         break;
  311.  
  312.     case VSEARCH:
  313.         switch (ch) {
  314.  
  315.         /* case Ctrl('['): */
  316.         case '\r':
  317.         case '\n':
  318.             locpat[srchlen] = '\0';
  319.             (void) strcpy(srchpat, locpat);
  320.             /* redraw_line(); */
  321.             state = VCMD;
  322.             break;
  323.  
  324.         case 0x7f:
  325.             if (srchlen == 0) {
  326.                 restore_cbuf();
  327.                 state = VNORMAL;
  328.             } else {
  329.                 srchlen--;
  330.                 if (locpat[srchlen] < ' ' ||
  331.                         locpat[srchlen] == 0x7f) {
  332.                     es->linelen--;
  333.                 }
  334.                 es->linelen--;
  335.                 es->cursor = es->linelen;
  336.                 refresh(0);
  337.                 return 0;
  338.             }
  339.             refresh(0);
  340.             break;
  341.  
  342.         case Ctrl('u'):
  343.             srchlen = 0;
  344.             es->linelen = 1;
  345.             es->cursor = 1;
  346.             refresh(0);
  347.             return 0;
  348.  
  349.         default:
  350.             if (srchlen == SRCHLEN - 1)
  351.                 x_putc(Ctrl('g'));
  352.             else {
  353.                 locpat[srchlen++] = ch;
  354.                 if (ch < ' ' || ch == 0x7f) {
  355.                     es->cbuf[es->linelen++] = '^';
  356.                     es->cbuf[es->linelen++] = ch ^ '@';
  357.                 } else
  358.                     es->cbuf[es->linelen++] = ch;
  359.                 es->cursor = es->linelen;
  360.                 refresh(0);
  361.             }
  362.             return 0;
  363.             break;
  364.         }
  365.         break;
  366.     }
  367.     switch (state) {
  368.  
  369.     case VCMD:
  370.         state = VNORMAL;
  371.         switch (vi_cmd(argc1, curcmd)) {
  372.         case -1:
  373.             x_putc(Ctrl('g'));
  374.             break;
  375.         case 0:
  376.             if (insert != 0)
  377.                 inslen = 0;
  378.             refresh(insert != 0);
  379.             break;
  380.         case 1:
  381.             refresh(0);
  382.             x_putc('\r');
  383.             x_putc('\n');
  384.             x_flush();
  385.             return 1;
  386.         }
  387.         break;
  388.  
  389.     case VREDO:
  390.         state = VNORMAL;
  391.         if (argc1 != 0)
  392.             lastac = argc1;
  393.         switch (vi_cmd(lastac, lastcmd) != 0) {
  394.         case -1:
  395.             x_putc(Ctrl('g'));
  396.             refresh(0);
  397.             break;
  398.         case 0:
  399.             if (insert != 0) {
  400.                 if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
  401.                         lastcmd[0] == 'C') {
  402.                     if (redo_insert(1) != 0)
  403.                         x_putc(Ctrl('g'));
  404.                 } else {
  405.                     if (redo_insert(lastac) != 0)
  406.                         x_putc(Ctrl('g'));
  407.                 }
  408.             }
  409.             refresh(0);
  410.             break;
  411.         case 1:
  412.             refresh(0);
  413.             x_putc('\r');
  414.             x_putc('\n');
  415.             x_flush();
  416.             return 1;
  417.         }
  418.         break;
  419.  
  420.     case VFAIL:
  421.         state = VNORMAL;
  422.         x_putc(Ctrl('g'));
  423.         break;
  424.     }
  425.     return 0;
  426. }
  427.  
  428. static int
  429. nextstate(ch)
  430.     int    ch;
  431. {
  432.     /*
  433.      * probably could have been done more elegantly than
  434.      * by creating a new state, but it works
  435.      */
  436.     if (ch == 'r')
  437.         return VREPLACE1CHAR;
  438.     else if (isextend(ch))
  439.         return VEXTCMD;
  440.     else if (issrch(ch))
  441.         return VSEARCH;
  442.     else if (islong(ch))
  443.         return VXCH;
  444.     else if (ch == '.')
  445.         return VREDO;
  446.     else if (iscmd(ch))
  447.         return VCMD;
  448.     else
  449.         return VFAIL;
  450. }
  451.  
  452. static int
  453. vi_insert(ch)
  454.     int    ch;
  455. {
  456.     int    tcursor;
  457.  
  458.     switch (ch) {
  459.  
  460.     case '\0':
  461.         return -1;
  462.  
  463.     case Ctrl('['):
  464.         if (lastcmd[0] == 's' || lastcmd[0] == 'c' ||
  465.                 lastcmd[0] == 'C')
  466.             return redo_insert(0);
  467.         else
  468.             return redo_insert(lastac - 1);
  469.  
  470.     case 0x7f:        /* delete */
  471.         /* tmp fix */
  472.         /* general fix is to get stty erase char and use that
  473.         */
  474.     case Ctrl('H'):        /* delete */
  475.         if (es->cursor != 0) {
  476.             if (inslen > 0)
  477.                 inslen--;
  478.             es->cursor--;
  479.             if (insert != REPLACE) {
  480.                 memmove(&es->cbuf[es->cursor],
  481.                         &es->cbuf[es->cursor+1],
  482.                         es->linelen - es->cursor);
  483.                 es->linelen--;
  484.             }
  485.         }
  486.         break;
  487.  
  488.     case Ctrl('U'):
  489.         if (es->cursor != 0) {
  490.             inslen = 0;
  491.             memmove(es->cbuf, &es->cbuf[es->cursor],
  492.                         es->linelen - es->cursor);
  493.             es->linelen -= es->cursor;
  494.             es->cursor = 0;
  495.         }
  496.         break;
  497.  
  498.     case Ctrl('W'):
  499.         if (es->cursor != 0) {
  500.             tcursor = backword(1);
  501.             memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
  502.                         es->linelen - es->cursor);
  503.             es->linelen -= es->cursor - tcursor;
  504.             if (inslen < es->cursor - tcursor)
  505.                 inslen = 0;
  506.             else
  507.                 inslen -= es->cursor - tcursor;
  508.             es->cursor = tcursor;
  509.         }
  510.         break;
  511.  
  512.     default:
  513.         if (es->linelen == es->cbufsize - 1)
  514.             return -1;
  515.         ibuf[inslen++] = ch;
  516.         if (insert == INSERT) {
  517.             memmove(&es->cbuf[es->cursor+1], &es->cbuf[es->cursor],
  518.                     es->linelen - es->cursor);
  519.             es->linelen++;
  520.         }
  521.         es->cbuf[es->cursor++] = ch;
  522.         if (insert == REPLACE && es->cursor > es->linelen)
  523.             es->linelen++;
  524.     }
  525.     return 0;
  526. }
  527.  
  528. static int
  529. vi_cmd(argcnt, cmd)
  530.     int        argcnt;
  531.     char        *cmd;
  532. {
  533.     int        ncursor;
  534.     int        cur, c1, c2, c3 = 0;
  535.     struct edstate    *t;
  536.  
  537.  
  538.     if (argcnt == 0) {
  539.         if (*cmd == 'G')
  540.             argcnt = hlast + 1;
  541.         else if (*cmd != '_')
  542.             argcnt = 1;
  543.     }
  544.  
  545.     if (ismove(*cmd)) {
  546.         if ((cur = domove(argcnt, cmd, 0)) >= 0) {
  547.             if (cur == es->linelen && cur != 0)
  548.                 cur--;
  549.             es->cursor = cur;
  550.         } else
  551.             return -1;
  552.     } else {
  553.         if (isundoable(*cmd)) {
  554.             undo->winleft = es->winleft;
  555.             memmove(undo->cbuf, es->cbuf, es->linelen);
  556.             undo->linelen = es->linelen;
  557.             undo->cursor = es->cursor;
  558.             lastac = argcnt;
  559.             memmove(lastcmd, cmd, MAXVICMD);
  560.         }
  561.         switch (*cmd) {
  562.  
  563.         case Ctrl('r'):
  564.             redraw_line();
  565.             break;
  566.  
  567.         case 'a':
  568.             modified = 1;
  569.             if (es->linelen != 0)
  570.                 es->cursor++;
  571.             insert = INSERT;
  572.             break;
  573.  
  574.         case 'A':
  575.             modified = 1;
  576.             del_range(0, 0);
  577.             es->cursor = es->linelen;
  578.             insert = INSERT;
  579.             break;
  580.  
  581.         case 'c':
  582.         case 'd':
  583.         case 'y':
  584.             if (*cmd == cmd[1]) {
  585.                 c1 = 0;
  586.                 c2 = es->linelen;
  587.             } else if (!ismove(cmd[1]))
  588.                 return -1;
  589.             else {
  590.                 if ((ncursor = domove(argcnt, &cmd[1], 1)) < 0)
  591.                     return -1;
  592.                 if (*cmd == 'c' &&
  593.                         (cmd[1]=='w' || cmd[1]=='W') &&
  594.                         !isspace(es->cbuf[es->cursor])) {
  595.                     while (isspace(es->cbuf[--ncursor]))
  596.                         ;
  597.                     ncursor++;
  598.                 }
  599.                 if (ncursor > es->cursor) {
  600.                     c1 = es->cursor;
  601.                     c2 = ncursor;
  602.                 } else {
  603.                     c1 = ncursor;
  604.                     c2 = es->cursor;
  605.                 }
  606.             }
  607.             if (*cmd != 'c' && c1 != c2)
  608.                 yank_range(c1, c2);
  609.             if (*cmd != 'y') {
  610.                 del_range(c1, c2);
  611.                 es->cursor = c1;
  612.             }
  613.             if (*cmd == 'c') {
  614.                 modified = 1;
  615.                 insert = INSERT;
  616.             }
  617.             break;
  618.  
  619.         case 'p':
  620.             modified = 1;
  621.             if (es->linelen != 0)
  622.                 es->cursor++;
  623.             while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
  624.                 ;
  625.             if (es->cursor != 0)
  626.                 es->cursor--;
  627.             if (argcnt != 0)
  628.                 return -1;
  629.             break;
  630.  
  631.         case 'P':
  632.             modified = 1;
  633.             while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
  634.                 ;
  635.             if (es->cursor != 0)
  636.                 es->cursor--;
  637.             if (argcnt != 0)
  638.                 return -1;
  639.             break;
  640.  
  641.         case 'C':
  642.             modified = 1;
  643.             del_range(es->cursor, es->linelen);
  644.             insert = INSERT;
  645.             break;
  646.  
  647.         case 'D':
  648.             yank_range(es->cursor, es->linelen);
  649.             del_range(es->cursor, es->linelen);
  650.             if (es->cursor != 0)
  651.                 es->cursor--;
  652.             break;
  653.  
  654.         case 'G':
  655.             if (grabhist(modified, argcnt - 1) < 0)
  656.                 return -1;
  657.             else {
  658.                 modified = 0;
  659.                 hnum = argcnt - 1;
  660.             }
  661.             break;
  662.  
  663.         case 'i':
  664.             modified = 1;
  665.             insert = INSERT;
  666.             break;
  667.  
  668.         case 'I':
  669.             modified = 1;
  670.             es->cursor = 0;
  671.             insert = INSERT;
  672.             break;
  673.  
  674.         case '+':
  675.         case 'j':
  676.             if (grabhist(modified, hnum + argcnt) < 0)
  677.                 return -1;
  678.             else {
  679.                 modified = 0;
  680.                 hnum += argcnt;
  681.             }
  682.             break;
  683.  
  684.         case '-':
  685.         case 'k':
  686.             if (grabhist(modified, hnum - argcnt) < 0)
  687.                 return -1;
  688.             else {
  689.                 modified = 0;
  690.                 hnum -= argcnt;
  691.             }
  692.             break;
  693.  
  694.         case 'r':
  695.             if (es->linelen == 0)
  696.                 return -1;
  697.             modified = 1;
  698.             es->cbuf[es->cursor] = cmd[1];
  699.             break;
  700.  
  701.         case 'R':
  702.             modified = 1;
  703.             insert = REPLACE;
  704.             break;
  705.  
  706.         case 's':
  707.             if (es->linelen == 0)
  708.                 return -1;
  709.             modified = 1;
  710.             if (es->cursor + argcnt > es->linelen)
  711.                 argcnt = es->linelen - es->cursor;
  712.             del_range(es->cursor, es->cursor + argcnt);
  713.             insert = INSERT;
  714.             break;
  715.  
  716.         case 'x':
  717.             if (es->linelen == 0)
  718.                 return -1;
  719.             modified = 1;
  720.             if (es->cursor + argcnt > es->linelen)
  721.                 argcnt = es->linelen - es->cursor;
  722.             yank_range(es->cursor, es->cursor + argcnt);
  723.             del_range(es->cursor, es->cursor + argcnt);
  724.             break;
  725.  
  726.         case 'X':
  727.             if (es->cursor > 0) {
  728.                 modified = 1;
  729.                 if (es->cursor < argcnt)
  730.                     argcnt = es->cursor;
  731.                 yank_range(es->cursor - argcnt, es->cursor);
  732.                 del_range(es->cursor - argcnt, es->cursor);
  733.                 es->cursor -= argcnt;
  734.             } else
  735.                 return -1;
  736.             break;
  737.  
  738.         case 'u':
  739.             t = es;
  740.             es = undo;
  741.             undo = t;
  742.             break;
  743.  
  744.         case '?':
  745.             hnum = -1;
  746.             /* ahhhhhh... */
  747.         case '/':
  748.             c3 = 1;
  749.             srchlen = 0;
  750.             lastsearch = *cmd;
  751.             /* fall through */
  752.         case 'n':
  753.         case 'N':
  754.             if (lastsearch == ' ')
  755.                 return -1;
  756.             if (lastsearch == '?')
  757.                 c1 = 1;
  758.             else
  759.                 c1 = 0;
  760.             if (*cmd == 'N')
  761.                 c1 = !c1;
  762.             if ((c2 = grabsearch(modified, hnum,
  763.                             c1, srchpat)) < 0) {
  764.                 if (c3) {
  765.                     restore_cbuf();
  766.                     refresh(0);
  767.                 }
  768.                 return -1;
  769.             } else {
  770.                 modified = 0;
  771.                 hnum = c2;
  772.             }
  773.             break;
  774.         case '_': {
  775.             int    space;
  776.             char    *p, *sp;
  777.  
  778.             (void) histnum(-1);
  779.             p = *histpos();
  780. #define issp(c)        (isspace((c)) || (c) == '\n')
  781.             if (argcnt) {
  782.                 while (*p && issp(*p))
  783.                     p++;
  784.                 while (*p && --argcnt) {
  785.                     while (*p && !issp(*p))
  786.                         p++;
  787.                     while (*p && issp(*p))
  788.                         p++;
  789.                 }
  790.                 if (!*p)
  791.                     return -1;
  792.                 sp = p;
  793.             } else {
  794.                 sp = p;
  795.                 space = 0;
  796.                 while (*p) {
  797.                     if (issp(*p))
  798.                         space = 1;
  799.                     else if (space) {
  800.                         space = 0;
  801.                         sp = p;
  802.                     }
  803.                     p++;
  804.                 }
  805.                 p = sp;
  806.             }
  807.             modified = 1;
  808.             if (es->linelen != 0)
  809.                 es->cursor++;
  810.             while (*p && !issp(*p)) {
  811.                 argcnt++;
  812.                 p++;
  813.             }
  814.             if (putbuf(" ", 1, 0) != 0)
  815.                 argcnt = -1;
  816.             else if (putbuf(sp, argcnt, 0) != 0)
  817.                 argcnt = -1;
  818.             if (argcnt < 0) {
  819.                 if (es->cursor != 0)
  820.                     es->cursor--;
  821.                 return -1;
  822.             }
  823.             insert = INSERT;
  824.             }
  825.             break;
  826.  
  827.         case '~': {
  828.             char    *p;
  829.  
  830.             if (es->linelen == 0)
  831.                 return -1;
  832.             p = &es->cbuf[es->cursor];
  833.             if (islower(*p)) {
  834.                 modified = 1;
  835.                 *p = toupper(*p);
  836.             } else if (isupper(*p)) {
  837.                 modified = 1;
  838.                 *p = tolower(*p);
  839.             }
  840.             if (es->cursor < es->linelen - 1)
  841.                 es->cursor++;
  842.             }
  843.             break;
  844.  
  845.         case '#':
  846.             es->cursor = 0;
  847.             if (putbuf("#", 1, 0) != 0)
  848.                 return -1;
  849.             return 1;
  850.  
  851.         case '*':
  852.         case '=': {
  853.             int    rval = 0;
  854.             int    start, end;
  855.             char    *toglob = undo->cbuf;
  856.             char    **ap;
  857.             char    **ap2;
  858.             char    **globstr();
  859.  
  860.             if (isspace(es->cbuf[es->cursor]))
  861.                 return -1;
  862.             start = es->cursor;
  863.             while (start > -1 && !isspace(es->cbuf[start]))
  864.                 start--;
  865.             start++;
  866.             end = es->cursor;
  867.             while (end < es->linelen && !isspace(es->cbuf[end]))
  868.                 end++;
  869.             /* use undo buffer to build word up in */
  870.             memmove(toglob, &es->cbuf[start], end-start);
  871.             if (toglob[end-start-1] != '*') {
  872.                 toglob[end-start] = '*';
  873.                 toglob[end-start+1] = '\0';
  874.             } else
  875.                 toglob[end-start] = '\0';
  876.             ap = globstr(toglob);
  877.             ap2 = ap;
  878.             if (strcmp(ap[0], toglob) == 0 && ap[1] == (char *) 0)
  879.                 rval = -1;
  880.             /* restore undo buffer that we used temporarily */
  881.             memmove(toglob, es->cbuf, es->linelen);
  882.             if (rval < 0)
  883.                 return rval;
  884.             if (*cmd == '=') {
  885.                 fputc('\n', shlout);
  886.                 pr_menu(ap2, 0);
  887.                 fflush(shlout);
  888.                 if (es->linelen != 0)
  889.                     es->cursor++;
  890.                 redraw_line();
  891.                 insert = INSERT;
  892.                 state = VNORMAL;
  893.                 return 0;
  894.             } else {
  895.                 del_range(start, end);
  896.                 es->cursor = start;
  897.                 while (1) {
  898.                     if (putbuf(*ap, strlen(*ap), 0) != 0) {
  899.                         rval = -1;
  900.                         break;
  901.                     }
  902.                     if (*++ap == (char *) 0)
  903.                         break;
  904.                     if (putbuf(" ", 1, 0) != 0) {
  905.                         rval = -1;
  906.                         break;
  907.                     }
  908.  
  909.                 }
  910. #if 0
  911.                 /*
  912.                  * this is definitely wrong
  913.                  */
  914.                 for (ap = ap2; *ap; ap++)
  915.                     free(*ap);
  916.  
  917.                 free(ap2);
  918. #endif
  919.  
  920.                 modified = 1;
  921.                 insert = INSERT;
  922.                 refresh(0);
  923.             }
  924.             if (rval != 0)
  925.                 return rval;
  926.             }
  927.             break;
  928.         }
  929.         if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
  930.             es->cursor--;
  931.     }
  932.     return 0;
  933. }
  934.  
  935. static int
  936. domove(argcnt, cmd, sub)
  937.     int    argcnt;
  938.     char    *cmd;
  939.     int    sub;
  940. {
  941.     int    bcount, i = 0, t;    /* = 0 kludge for gcc -W */
  942.     int    ncursor = 0;        /* = 0 kludge for gcc -W */
  943.  
  944.     switch (*cmd) {
  945.  
  946.     case 'b':
  947.         if (!sub && es->cursor == 0)
  948.             return -1;
  949.         ncursor = backword(argcnt);
  950.         break;
  951.  
  952.     case 'B':
  953.         if (!sub && es->cursor == 0)
  954.             return -1;
  955.         ncursor = Backword(argcnt);
  956.         break;
  957.  
  958.     case 'e':
  959.         if (!sub && es->cursor + 1 >= es->linelen)
  960.             return -1;
  961.         ncursor = endword(argcnt);
  962.         if (sub)
  963.             ncursor++;
  964.         break;
  965.  
  966.     case 'E':
  967.         if (!sub && es->cursor + 1 >= es->linelen)
  968.             return -1;
  969.         ncursor = Endword(argcnt);
  970.         if (sub)
  971.             ncursor++;
  972.         break;
  973.  
  974.     case 'f':
  975.     case 'F':
  976.     case 't':
  977.     case 'T':
  978.         fsavecmd = *cmd;
  979.         fsavech = cmd[1];
  980.         /* drop through */
  981.  
  982.     case ',':
  983.     case ';':
  984.         if (fsavecmd == ' ')
  985.             return -1;
  986.         i = fsavecmd == 'f' || fsavecmd == 'F';
  987.         t = fsavecmd > 'a';
  988.         if (*cmd == ',')
  989.             t = !t;
  990.         if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
  991.             return -1;
  992.         if (sub && t)
  993.             ncursor++;
  994.         break;
  995.  
  996.     case 'h':
  997.         /* tmp fix */
  998.     case Ctrl('H'):
  999.         if (!sub && es->cursor == 0)
  1000.             return -1;
  1001.         ncursor = es->cursor - argcnt;
  1002.         if (ncursor < 0)
  1003.             ncursor = 0;
  1004.         break;
  1005.  
  1006.     case ' ':
  1007.     case 'l':
  1008.         if (!sub && es->cursor + 1 >= es->linelen)
  1009.             return -1;
  1010.         if (es->linelen != 0) {
  1011.             ncursor = es->cursor + argcnt;
  1012.             if (ncursor >= es->linelen)
  1013.                 ncursor = es->linelen - 1;
  1014.         }
  1015.         break;
  1016.  
  1017.     case 'w':
  1018.         if (!sub && es->cursor + 1 >= es->linelen)
  1019.             return -1;
  1020.         ncursor = forwword(argcnt);
  1021.         break;
  1022.  
  1023.     case 'W':
  1024.         if (!sub && es->cursor + 1 >= es->linelen)
  1025.             return -1;
  1026.         ncursor = Forwword(argcnt);
  1027.         break;
  1028.  
  1029.     case '0':
  1030.         ncursor = 0;
  1031.         break;
  1032.  
  1033.     case '^':
  1034.         ncursor = 0;
  1035.         while (ncursor < es->linelen - 1 && isspace(es->cbuf[ncursor]))
  1036.             ncursor++;
  1037.         break;
  1038.  
  1039.     case '$':
  1040.         if (es->linelen != 0)
  1041.             ncursor = es->linelen;
  1042.         else
  1043.             ncursor = 0;
  1044.         break;
  1045.  
  1046.     case '%':
  1047.         ncursor = es->cursor;
  1048.         while (ncursor < es->linelen &&
  1049.                 (i = bracktype(es->cbuf[ncursor])) == 0)
  1050.             ncursor++;
  1051.         if (ncursor == es->linelen)
  1052.             return -1;
  1053.         bcount = 1;
  1054.         do {
  1055.             if (i > 0) {
  1056.                 if (++ncursor >= es->linelen)
  1057.                     return -1;
  1058.             } else {
  1059.                 if (--ncursor < 0)
  1060.                     return -1;
  1061.             }
  1062.             t = bracktype(es->cbuf[ncursor]);
  1063.             if (t == i)
  1064.                 bcount++;
  1065.             else if (t == -i)
  1066.                 bcount--;
  1067.         } while (bcount != 0);
  1068.         if (sub)
  1069.             ncursor++;
  1070.         break;
  1071.  
  1072.     default:
  1073.         return -1;
  1074.     }
  1075.     return ncursor;
  1076. }
  1077.  
  1078. static int
  1079. redo_insert(count)
  1080.     int    count;
  1081. {
  1082.     while (count-- > 0)
  1083.         if (putbuf(ibuf, inslen, insert==REPLACE) != 0)
  1084.             return -1;
  1085.     if (es->cursor > 0)
  1086.         es->cursor--;
  1087.     insert = 0;
  1088.     return 0;
  1089. }
  1090.  
  1091. static
  1092. yank_range(a, b)
  1093.     int    a, b;
  1094. {
  1095.     yanklen = b - a;
  1096.     if (yanklen != 0)
  1097.         memmove(ybuf, &es->cbuf[a], yanklen);
  1098. }
  1099.  
  1100. static int
  1101. bracktype(ch)
  1102.     int    ch;
  1103. {
  1104.     switch (ch) {
  1105.  
  1106.     case '(':
  1107.         return 1;
  1108.  
  1109.     case '[':
  1110.         return 2;
  1111.  
  1112.     case '{':
  1113.         return 3;
  1114.  
  1115.     case ')':
  1116.         return -1;
  1117.  
  1118.     case ']':
  1119.         return -2;
  1120.  
  1121.     case '}':
  1122.         return -3;
  1123.  
  1124.     default:
  1125.         return 0;
  1126.     }
  1127. }
  1128.  
  1129. /*
  1130.  *    Non user interface editor routines below here
  1131.  */
  1132.  
  1133. static int    cur_col;        /* current column on line */
  1134. static int    pwidth;            /* width of prompt */
  1135. static int    winwidth;        /* width of window */
  1136. /*static char    *wbuf[2];        /* window buffers */
  1137. static char    wbuf[2][128-3];    /* window buffers */ /* TODO */
  1138. static int    win;            /* window buffer in use */
  1139. static char    morec;            /* more character at right of window */
  1140. static int    lastref;        /* argument to last refresh() */
  1141. static char    holdbuf[CMDLEN];    /* place to hold last edit buffer */
  1142. static int    holdlen;        /* length of holdbuf */
  1143.  
  1144. save_cbuf()
  1145. {
  1146.     memmove(holdbuf, es->cbuf, es->linelen);
  1147.     holdlen = es->linelen;
  1148.     holdbuf[holdlen] = '\0';
  1149. }
  1150.  
  1151. restore_cbuf()
  1152. {
  1153.     es->cursor = 0;
  1154.     es->linelen = holdlen;
  1155.     memmove(es->cbuf, holdbuf, holdlen);
  1156. }
  1157.  
  1158. static
  1159. edit_reset(buf, len)
  1160.     char    *buf;
  1161.     int    len;
  1162. {
  1163.     es = &ebuf;
  1164.     es->cbuf = buf;
  1165.     es->cbufsize = len;
  1166.     undo = &undobuf;
  1167.     undo->cbufsize = len;
  1168.  
  1169.     es->linelen = undo->linelen = 0;
  1170.     es->cursor = undo->cursor = 0;
  1171.     es->winleft = undo->winleft = 0;
  1172.  
  1173.     cur_col = pwidth = promptlen(prompt);
  1174.     winwidth = x_cols - pwidth - 3;
  1175.     x_putc('\r');
  1176.     x_flush();
  1177.     pprompt(prompt);
  1178.     /* docap(CLR_EOL, 0); */
  1179.     win = 0;
  1180.     morec = ' ';
  1181.     lastref = 1;
  1182. }
  1183.  
  1184. static int
  1185. putbuf(buf, len, repl)
  1186.     char    *buf;
  1187.     int    len;
  1188.     int    repl;
  1189. {
  1190.     if (len == 0)
  1191.         return 0;
  1192.     if (repl) {
  1193.         if (es->cursor + len >= es->cbufsize - 1)
  1194.             return -1;
  1195.         if (es->cursor + len > es->linelen)
  1196.             es->linelen = es->cursor + len;
  1197.     } else {
  1198.         if (es->linelen + len >= es->cbufsize - 1)
  1199.             return -1;
  1200.         memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor],
  1201.             es->linelen - es->cursor);
  1202.         es->linelen += len;
  1203.     }
  1204.     memmove(&es->cbuf[es->cursor], buf, len);
  1205.     es->cursor += len;
  1206.     return 0;
  1207. }
  1208.  
  1209. static
  1210. stripblanks()
  1211. {
  1212.     int    ncursor;
  1213.  
  1214.     ncursor = 0;
  1215.     while (ncursor < es->linelen && isspace(es->cbuf[ncursor]))
  1216.         ncursor++;
  1217.     del_range(0, ncursor);
  1218. }
  1219.  
  1220. static
  1221. del_range(a, b)
  1222.     int    a, b;
  1223. {
  1224.     if (es->linelen != b)
  1225.         memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
  1226.     es->linelen -= b - a;
  1227. }
  1228.  
  1229. static int
  1230. findch(ch, cnt, forw, incl)
  1231.     int    ch;
  1232.     int    forw;
  1233.     int    incl;
  1234. {
  1235.     int    ncursor;
  1236.  
  1237.     if (es->linelen == 0)
  1238.         return -1;
  1239.     ncursor = es->cursor;
  1240.     while (cnt--) {
  1241.         do {
  1242.             if (forw) {
  1243.                 if (++ncursor == es->linelen)
  1244.                     return -1;
  1245.             } else {
  1246.                 if (--ncursor < 0)
  1247.                     return -1;
  1248.             }
  1249.         } while (es->cbuf[ncursor] != ch);
  1250.     }
  1251.     if (!incl) {
  1252.         if (forw)
  1253.             ncursor--;
  1254.         else
  1255.             ncursor++;
  1256.     }
  1257.     return ncursor;
  1258. }
  1259.  
  1260. #define Isalnum(x) (isalnum(x) || (x == '_'))
  1261. static int
  1262. forwword(argcnt)
  1263.     int    argcnt;
  1264. {
  1265.     int    ncursor;
  1266.  
  1267.     ncursor = es->cursor;
  1268.     while (ncursor < es->linelen && argcnt--) {
  1269.         if (Isalnum(es->cbuf[ncursor]))
  1270.             while (Isalnum(es->cbuf[ncursor]) &&
  1271.                     ++ncursor < es->linelen)
  1272.                 ;
  1273.         else if (!isspace(es->cbuf[ncursor]))
  1274.             while (!Isalnum(es->cbuf[ncursor]) &&
  1275.                     !isspace(es->cbuf[ncursor]) &&
  1276.                     ++ncursor < es->linelen)
  1277.                 ;
  1278.         while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
  1279.             ;
  1280.     }
  1281.     return ncursor;
  1282. }
  1283.  
  1284. static int
  1285. backword(argcnt)
  1286.     int    argcnt;
  1287. {
  1288.     int    ncursor;
  1289.  
  1290.     ncursor = es->cursor;
  1291.     while (ncursor > 0 && argcnt--) {
  1292.         while (--ncursor > 0 && isspace(es->cbuf[ncursor]))
  1293.             ;
  1294.         if (ncursor > 0) {
  1295.             if (Isalnum(es->cbuf[ncursor]))
  1296.                 while (--ncursor >= 0 &&
  1297.                    Isalnum(es->cbuf[ncursor]))
  1298.                     ;
  1299.             else
  1300.                 while (--ncursor >= 0 &&
  1301.                    !Isalnum(es->cbuf[ncursor]) &&
  1302.                    !isspace(es->cbuf[ncursor]))
  1303.                     ;
  1304.             ncursor++;
  1305.         }
  1306.     }
  1307.     return ncursor;
  1308. }
  1309.  
  1310. static int
  1311. endword(argcnt)
  1312.     int    argcnt;
  1313. {
  1314.     int    ncursor;
  1315.  
  1316.     ncursor = es->cursor;
  1317.     while (ncursor < es->linelen && argcnt--) {
  1318.         while (++ncursor < es->linelen - 1 &&
  1319.                 isspace(es->cbuf[ncursor]))
  1320.             ;
  1321.         if (ncursor < es->linelen - 1) {
  1322.             if (Isalnum(es->cbuf[ncursor]))
  1323.                 while (++ncursor < es->linelen &&
  1324.                       Isalnum(es->cbuf[ncursor]))
  1325.                     ;
  1326.             else
  1327.                 while (++ncursor < es->linelen &&
  1328.                    !Isalnum(es->cbuf[ncursor]) &&
  1329.                    !isspace(es->cbuf[ncursor]))
  1330.                     ;
  1331.             ncursor--;
  1332.         }
  1333.     }
  1334.     return ncursor;
  1335. }
  1336.  
  1337. static int
  1338. Forwword(argcnt)
  1339.     int    argcnt;
  1340. {
  1341.     int    ncursor;
  1342.  
  1343.     ncursor = es->cursor;
  1344.     while (ncursor < es->linelen && argcnt--) {
  1345.         while (!isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
  1346.             ;
  1347.         while (isspace(es->cbuf[ncursor]) && ++ncursor < es->linelen)
  1348.             ;
  1349.     }
  1350.     return ncursor;
  1351. }
  1352.  
  1353. static int
  1354. Backword(argcnt)
  1355.     int    argcnt;
  1356. {
  1357.     int    ncursor;
  1358.  
  1359.     ncursor = es->cursor;
  1360.     while (ncursor > 0 && argcnt--) {
  1361.         while (--ncursor >= 0 && isspace(es->cbuf[ncursor]))
  1362.             ;
  1363.         while (ncursor >= 0 && !isspace(es->cbuf[ncursor]))
  1364.             ncursor--;
  1365.         ncursor++;
  1366.     }
  1367.     return ncursor;
  1368. }
  1369.  
  1370. static int
  1371. Endword(argcnt)
  1372.     int    argcnt;
  1373. {
  1374.     int    ncursor;
  1375.  
  1376.     ncursor = es->cursor;
  1377.     while (ncursor < es->linelen - 1 && argcnt--) {
  1378.         while (++ncursor < es->linelen - 1 &&
  1379.                 isspace(es->cbuf[ncursor]))
  1380.             ;
  1381.         if (ncursor < es->linelen - 1) {
  1382.             while (++ncursor < es->linelen &&
  1383.                     !isspace(es->cbuf[ncursor]))
  1384.                 ;
  1385.             ncursor--;
  1386.         }
  1387.     }
  1388.     return ncursor;
  1389. }
  1390.  
  1391. static int
  1392. grabhist(save, n)
  1393.     int    save;
  1394.     int    n;
  1395. {
  1396.     char    *hptr;
  1397.  
  1398.     if (n < 0 || n > hlast)
  1399.         return -1;
  1400.     if (n == hlast) {
  1401.         restore_cbuf();
  1402.         return 0;
  1403.     }
  1404.     (void) histnum(n);
  1405.     if ((hptr = *histpos()) == NULL) {
  1406.         shellf("grabhist: bad history array\n");
  1407.         return -1;
  1408.     }
  1409.     if (save)
  1410.         save_cbuf();
  1411.     es->linelen = strlen(hptr);
  1412.     memmove(es->cbuf, hptr, es->linelen);
  1413.     es->cursor = 0;
  1414.     return 0;
  1415. }
  1416.  
  1417. static int
  1418. grabsearch(save, start, fwd, pat)
  1419.     int    save, start, fwd;
  1420.     char    *pat;
  1421. {
  1422.     char    *hptr;
  1423.  
  1424.     if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1))
  1425.         return -1;
  1426.     if ((hptr = findhist(start, fwd, pat)) == NULL) {
  1427.         /* if (start != 0 && fwd && match(holdbuf, pat) >= 0) { */
  1428.         if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
  1429.             restore_cbuf();
  1430.             return 0;
  1431.         } else
  1432.             return -1;
  1433.     } else if (hptr == (char *)-1) {
  1434.         return -1;
  1435.     }
  1436.     if (save)
  1437.         save_cbuf();
  1438.     es->linelen = strlen(hptr);
  1439.     memmove(es->cbuf, hptr, es->linelen);
  1440.     es->cursor = 0;
  1441.     return histN();
  1442. }
  1443.  
  1444. static
  1445. redraw_line()
  1446. {
  1447.     x_putc('\r');
  1448.     x_putc('\n');
  1449.     x_flush();
  1450.     pprompt(prompt);
  1451.     cur_col = pwidth;
  1452.     morec = ' ';
  1453. }
  1454.  
  1455. static
  1456. refresh(leftside)
  1457.     int        leftside;
  1458. {
  1459.     if (leftside < 0)
  1460.         leftside = lastref;
  1461.     else
  1462.         lastref = leftside;
  1463.     if (outofwin())
  1464.         rewindow();
  1465.     display(wbuf[1 - win], wbuf[win], leftside);
  1466.     win = 1 - win;
  1467. }
  1468.  
  1469. static int
  1470. outofwin()
  1471. {
  1472.     int    cur, col;
  1473.  
  1474.     if (es->cursor < es->winleft)
  1475.         return 1;
  1476.     col = 0;
  1477.     cur = es->winleft;
  1478.     while (cur < es->cursor)
  1479.         col = newcol(es->cbuf[cur++], col);
  1480.     if (col > winwidth)
  1481.         return 1;
  1482.     return 0;
  1483. }
  1484.  
  1485. static
  1486. rewindow()
  1487. {
  1488.     register int    tcur, tcol;
  1489.     int        holdcur1, holdcol1;
  1490.     int        holdcur2, holdcol2;
  1491.  
  1492.     holdcur1 = holdcur2 = tcur = 0;
  1493.     holdcol1 = holdcol2 = tcol = 0;
  1494.     while (tcur < es->cursor) {
  1495.         if (tcol - holdcol2 > winwidth / 2) {
  1496.             holdcur1 = holdcur2;
  1497.             holdcol1 = holdcol2;
  1498.             holdcur2 = tcur;
  1499.             holdcol2 = tcol;
  1500.         }
  1501.         tcol = newcol(es->cbuf[tcur++], tcol);
  1502.     }
  1503.     while (tcol - holdcol1 > winwidth / 2)
  1504.         holdcol1 = newcol(es->cbuf[holdcur1++], holdcol1);
  1505.     es->winleft = holdcur1;
  1506. }
  1507.  
  1508. static int
  1509. newcol(ch, col)
  1510.     int    ch, col;
  1511. {
  1512.     if (ch < ' ' || ch == 0x7f) {
  1513.         if (ch == '\t')
  1514.             return (col | 7) + 1;
  1515.         else
  1516.             return col + 2;
  1517.     } else
  1518.         return col + 1;
  1519. }
  1520.  
  1521. static
  1522. display(wb1, wb2, leftside)
  1523.     char    *wb1, *wb2;
  1524.     int    leftside;
  1525. {
  1526.     char    *twb1, *twb2, mc;
  1527.     int    cur, col, cnt;
  1528.     int    ncol = 0; /* set to 0 kludge for gcc -W */
  1529.     int    moreright;
  1530.  
  1531.     col = 0;
  1532.     cur = es->winleft;
  1533.     moreright = 0;
  1534.     twb1 = wb1;
  1535.     while (col < winwidth && cur < es->linelen) {
  1536.         if (cur == es->cursor && leftside)
  1537.             ncol = col + pwidth;
  1538.         if (es->cbuf[cur] < ' ' || es->cbuf[cur] == 0x7f) {
  1539.             if (es->cbuf[cur] == '\t') {
  1540.                 do {
  1541.                     *twb1++ = ' ';
  1542.                 } while (++col < winwidth && (col & 7) != 0);
  1543.             } else {
  1544.                 *twb1++ = '^';
  1545.                 if (++col < winwidth) {
  1546.                     *twb1++ = es->cbuf[cur] ^ '@';
  1547.                     col++;
  1548.                 }
  1549.             }
  1550.         } else {
  1551.             *twb1++ = es->cbuf[cur];
  1552.             col++;
  1553.         }
  1554.         if (cur == es->cursor && !leftside)
  1555.             ncol = col + pwidth - 1;
  1556.         cur++;
  1557.     }
  1558.     if (cur == es->cursor)
  1559.         ncol = col + pwidth;
  1560.     if (col < winwidth) {
  1561.         while (col < winwidth) {
  1562.             *twb1++ = ' ';
  1563.             col++;
  1564.         }
  1565.     } else
  1566.         moreright++;
  1567.     *twb1 = ' ';
  1568.  
  1569.     col = pwidth;
  1570.     cnt = winwidth;
  1571.     twb1 = wb1;
  1572.     twb2 = wb2;
  1573.     while (cnt--) {
  1574.         if (*twb1 != *twb2) {
  1575.             if (cur_col != col)
  1576.                 ed_mov_opt(col, wb1);
  1577.             x_putc(*twb1);
  1578.             cur_col++;
  1579.         }
  1580.         twb1++;
  1581.         twb2++;
  1582.         col++;
  1583.     }
  1584.     if (es->winleft > 0 && moreright)
  1585.         mc = '+';
  1586.     else if (es->winleft > 0)
  1587.         mc = '<';
  1588.     else if (moreright)
  1589.         mc = '>';
  1590.     else
  1591.         mc = ' ';
  1592.     if (mc != morec) {
  1593.         ed_mov_opt(x_cols - 2, wb1);
  1594.         x_putc(mc);
  1595.         cur_col++;
  1596.         morec = mc;
  1597.     }
  1598. #if 0
  1599.     /*
  1600.      * Hack to fix the ^r redraw problem, but it redraws way too much.
  1601.      * Probably unacceptable at low baudrates.  Someone please fix this
  1602.      */
  1603.     else
  1604.         {
  1605.         ed_mov_opt(x_cols - 2, wb1);
  1606.         }
  1607. #endif
  1608.     if (cur_col != ncol)
  1609.         ed_mov_opt(ncol, wb1);
  1610. }
  1611.  
  1612. static
  1613. ed_mov_opt(col, wb)
  1614.     int    col;
  1615.     char    *wb;
  1616. {
  1617.     if (col < cur_col) {
  1618.         if (col + 1 < cur_col - col) {
  1619.             x_putc('\r');
  1620.             x_flush();
  1621.             pprompt(prompt);
  1622.             cur_col = pwidth;
  1623.             while (cur_col++ < col)
  1624.                 x_putc(*wb++);
  1625.         } else {
  1626.             while (cur_col-- > col)
  1627.                 x_putc('\b');
  1628.         }
  1629.     } else {
  1630.         wb = &wb[cur_col - pwidth];
  1631.         while (cur_col++ < col)
  1632.             x_putc(*wb++);
  1633.     }
  1634.     cur_col = col;
  1635. }
  1636.  
  1637. int
  1638. x_vi(buf, len)
  1639.     char *buf;
  1640.     size_t len;
  1641. {
  1642.     int    c;
  1643.  
  1644.     vi_reset(buf, len > CMDLEN ? CMDLEN : len);
  1645.     x_flush();
  1646.     while ((c = getch()) != -1) {
  1647.         if (vi_hook(c))
  1648.             break;
  1649.         x_flush();
  1650.     }
  1651.  
  1652.     if (c == -1)
  1653.         return -1;
  1654.  
  1655.     if (es->cbuf != buf) {
  1656.         memmove(buf, es->cbuf, es->linelen);
  1657.         buf[es->linelen] = '\n';
  1658.     } else
  1659.         es->cbuf[es->linelen] = '\n';
  1660.  
  1661.     es->linelen++;
  1662.     return es->linelen;
  1663. }
  1664.  
  1665. getch()
  1666. {
  1667.     unsigned char    buf;
  1668.  
  1669. #ifdef OS2
  1670.         do
  1671.         {
  1672.           buf = _read_kbd(0, 1, 0);
  1673.           if ( buf == 0 || buf == 0xE0 )
  1674.             _read_kbd(0, 1, 0);
  1675.         }
  1676.         while ( buf == 0 || buf == 0xE0 );
  1677.     if (buf == Ctrl('c')) {
  1678. #else
  1679.     if (read(ttyfd, &buf, 1) != 1)
  1680.         return -1;
  1681.     if ((buf & 0x7f) == Ctrl('c')) {
  1682. #endif
  1683.         /*
  1684.          * If you hit ctrl-c, the buffer was left in a
  1685.          * strange state; the next command typed was
  1686.          * mucked up.  Doing all of this is probably
  1687.          * overkill, but it works most of the time.
  1688.          */
  1689.         memset(es->cbuf, 0, CMDLEN);
  1690.         es->winleft = 0;
  1691.         es->cbufsize = 0;
  1692.         es->linelen = 0;
  1693.         es->cursor = 0;
  1694.  
  1695.         memset(undo->cbuf, 0, CMDLEN);
  1696.         undo->winleft = 0;
  1697.         undo->cbufsize = 0;
  1698.         undo->linelen = 0;
  1699.         undo->cursor = 0;
  1700.         x_mode(FALSE);
  1701.         trapsig(SIGINT);
  1702. #ifdef OS2
  1703.     } else if (buf == Ctrl('d'))
  1704.         return -1;
  1705.     return buf;
  1706. #else
  1707.     } else if ((buf & 0x7f) == Ctrl('d'))
  1708.         return -1;
  1709.     return buf & 0x7f;
  1710. #endif
  1711. }
  1712.  
  1713.  
  1714. char **globstr(stuff)
  1715. char *stuff;
  1716.     {
  1717.     char *vecp[2];
  1718.  
  1719.     vecp[0] = stuff;
  1720.     vecp[1] = NULL;
  1721.     return(eval(vecp, DOBLANK|DOGLOB|DOTILDE));
  1722.     }
  1723. #endif /* VI */
  1724.