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