home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / D / TOOLS / _TOOLS.TAR / usr / doc / tools-2.16 / example / editline.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-05  |  22.1 KB  |  1,383 lines

  1. /*  $Revision: 1.4 $
  2. **
  3. **  Main editing routines for editline library.
  4. */
  5. #include "editline.h"
  6. #include <ctype.h>
  7.  
  8. extern const char version_string[];
  9.  
  10. const char * string = version_string+2;
  11. /*
  12. **  Manifest constants.
  13. */
  14. #define SCREEN_WIDTH    80
  15. #define SCREEN_ROWS    24
  16. #define NO_ARG        (-1)
  17. #define DEL        127
  18. #define CTL(x)        ((x) & 0x1F)
  19. #define ISCTL(x)    ((x) && (x) < ' ')
  20. #define UNCTL(x)    ((x) + 64)
  21. #define META(x)        ((x) | 0x80)
  22. #define ISMETA(x)    ((x) & 0x80)
  23. #define UNMETA(x)    ((x) & 0x7F)
  24. #if    !defined(HIST_SIZE)
  25. #define HIST_SIZE    20
  26. #endif    /* !defined(HIST_SIZE) */
  27.  
  28. /*
  29. **  Command status codes.
  30. */
  31. typedef enum _STATUS {
  32.     CSdone, CSeof, CSmove, CSdispatch, CSstay
  33. } STATUS;
  34.  
  35. /*
  36. **  The type of case-changing to perform.
  37. */
  38. typedef enum _CASE {
  39.     TOupper, TOlower
  40. } CASE;
  41.  
  42. /*
  43. **  Key to command mapping.
  44. */
  45. typedef struct _KEYMAP {
  46.     CHAR    Key;
  47.     STATUS    (*Function)();
  48. } KEYMAP;
  49.  
  50. /*
  51. **  Command history structure.
  52. */
  53. typedef struct _HISTORY {
  54.     int        Size;
  55.     int        Pos;
  56.     CHAR    *Lines[HIST_SIZE];
  57. } HISTORY;
  58.  
  59. /*
  60. **  Globals.
  61. */
  62. int        rl_eof;
  63. int        rl_erase;
  64. int        rl_intr;
  65. int        rl_kill;
  66.  
  67. STATIC CHAR        NIL[] = "";
  68. STATIC CONST CHAR    *Input = NIL;
  69. STATIC CHAR        *Line;
  70. STATIC CONST char    *Prompt;
  71. STATIC CHAR        *Yanked;
  72. STATIC char        *Screen;
  73. STATIC char        NEWLINE[]= CRLF;
  74. STATIC HISTORY        H;
  75. int        rl_quit;
  76. STATIC int        Repeat;
  77. STATIC int        End;
  78. STATIC int        Mark;
  79. STATIC int        OldPoint;
  80. STATIC int        Point;
  81. STATIC int        PushBack;
  82. STATIC int        Pushed;
  83. FORWARD KEYMAP        Map[33];
  84. FORWARD KEYMAP        MetaMap[16];
  85. STATIC SIZE_T        Length;
  86. STATIC SIZE_T        ScreenCount;
  87. STATIC SIZE_T        ScreenSize;
  88. STATIC char        *backspace;
  89. STATIC int        TTYwidth;
  90. STATIC int        TTYrows;
  91.  
  92. /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
  93. int        rl_meta_chars = 1;
  94.  
  95. /*
  96. **  Declarations.
  97. */
  98. STATIC CHAR    *editinput();
  99. extern int    read();
  100. extern int    write();
  101. #if    defined(USE_TERMCAP)
  102. extern char    *getenv();
  103. extern char    *tgetstr();
  104. extern int    tgetent();
  105. #endif    /* defined(USE_TERMCAP) */
  106.  
  107. /*
  108. **  TTY input/output functions.
  109. */
  110.  
  111. STATIC void
  112. TTYflush()
  113. {
  114.     if (ScreenCount) {
  115.     (void)write(1, Screen, ScreenCount);
  116.     ScreenCount = 0;
  117.     }
  118. }
  119.  
  120. STATIC void
  121. TTYput(c)
  122.     CHAR    c;
  123. {
  124.     Screen[ScreenCount] = c;
  125.     if (++ScreenCount >= ScreenSize - 1) {
  126.     ScreenSize += SCREEN_INC;
  127.     RENEW(Screen, char, ScreenSize);
  128.     }
  129. }
  130.  
  131. STATIC void
  132. TTYputs(p)
  133.     CHAR    *p;
  134. {
  135.     while (*p)
  136.     TTYput(*p++);
  137. }
  138.  
  139. STATIC void
  140. TTYshow(c)
  141.     CHAR    c;
  142. {
  143.     if (c == DEL) {
  144.     TTYput('^');
  145.     TTYput('?');
  146.     }
  147.     else if (ISCTL(c)) {
  148.     TTYput('^');
  149.     TTYput(UNCTL(c));
  150.     }
  151.     else if (rl_meta_chars && ISMETA(c)) {
  152.     TTYput('M');
  153.     TTYput('-');
  154.     TTYput(UNMETA(c));
  155.     }
  156.     else
  157.     TTYput(c);
  158. }
  159.  
  160. STATIC void
  161. TTYstring(p)
  162.     CHAR    *p;
  163. {
  164.     while (*p)
  165.     TTYshow(*p++);
  166. }
  167.  
  168. STATIC unsigned int
  169. TTYget()
  170. {
  171.     CHAR    c;
  172.  
  173.     TTYflush();
  174.     if (Pushed) {
  175.     Pushed = 0;
  176.     return PushBack;
  177.     }
  178.     if (*Input)
  179.     return *Input++;
  180.     return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
  181. }
  182.  
  183. #define TTYback()    (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
  184.  
  185. STATIC void
  186. TTYbackn(n)
  187.     int        n;
  188. {
  189.     while (--n >= 0)
  190.     TTYback();
  191. }
  192.  
  193. STATIC void
  194. TTYinfo()
  195. {
  196.     static int        init;
  197. #if    defined(USE_TERMCAP)
  198.     char        *term;
  199.     char        buff[2048];
  200.     char        *bp;
  201. #endif    /* defined(USE_TERMCAP) */
  202. #if    defined(TIOCGWINSZ)
  203.     struct winsize    W;
  204. #endif    /* defined(TIOCGWINSZ) */
  205.  
  206.     if (init) {
  207. #if    defined(TIOCGWINSZ)
  208.     /* Perhaps we got resized. */
  209.     if (ioctl(0, TIOCGWINSZ, &W) >= 0
  210.      && W.ws_col > 0 && W.ws_row > 0) {
  211.         TTYwidth = (int)W.ws_col;
  212.         TTYrows = (int)W.ws_row;
  213.     }
  214. #endif    /* defined(TIOCGWINSZ) */
  215.     return;
  216.     }
  217.     init++;
  218.  
  219.     TTYwidth = TTYrows = 0;
  220. #if    defined(USE_TERMCAP)
  221.     bp = &buff[0];
  222.     if ((term = getenv("TERM")) == NULL)
  223.     term = "dumb";
  224.     if (tgetent(buff, term) < 0) {
  225.        TTYwidth = SCREEN_WIDTH;
  226.        TTYrows = SCREEN_ROWS;
  227.        return;
  228.     }
  229.     backspace = tgetstr("le", &bp);
  230.     TTYwidth = tgetnum("co");
  231.     TTYrows = tgetnum("li");
  232. #endif    /* defined(USE_TERMCAP) */
  233.  
  234. #if    defined(TIOCGWINSZ)
  235.     if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
  236.     TTYwidth = (int)W.ws_col;
  237.     TTYrows = (int)W.ws_row;
  238.     }
  239. #endif    /* defined(TIOCGWINSZ) */
  240.  
  241.     if (TTYwidth <= 0 || TTYrows <= 0) {
  242.     TTYwidth = SCREEN_WIDTH;
  243.     TTYrows = SCREEN_ROWS;
  244.     }
  245. }
  246.  
  247.  
  248. /*
  249. **  Print an array of words in columns.
  250. */
  251. STATIC void
  252. columns(ac, av)
  253.     int        ac;
  254.     CHAR    **av;
  255. {
  256.     CHAR    *p;
  257.     int        i;
  258.     int        j;
  259.     int        k;
  260.     int        len;
  261.     int        skip;
  262.     int        longest;
  263.     int        cols;
  264.  
  265.     /* Find longest name, determine column count from that. */
  266.     for (longest = 0, i = 0; i < ac; i++)
  267.     if ((j = strlen((char *)av[i])) > longest)
  268.         longest = j;
  269.     cols = TTYwidth / (longest + 3);
  270.  
  271.     TTYputs((CHAR *)NEWLINE);
  272.     for (skip = ac / cols + 1, i = 0; i < skip; i++) {
  273.     for (j = i; j < ac; j += skip) {
  274.         for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
  275.         TTYput(*p);
  276.         if (j + skip < ac)
  277.         while (++len < longest + 3)
  278.             TTYput(' ');
  279.     }
  280.     TTYputs((CHAR *)NEWLINE);
  281.     }
  282. }
  283.  
  284. STATIC void
  285. reposition()
  286. {
  287.     int        i;
  288.     CHAR    *p;
  289.  
  290.     TTYput('\r');
  291.     TTYputs((CHAR *)Prompt);
  292.     for (i = Point, p = Line; --i >= 0; p++)
  293.     TTYshow(*p);
  294. }
  295.  
  296. STATIC void
  297. left(Change)
  298.     STATUS    Change;
  299. {
  300.     TTYback();
  301.     if (Point) {
  302.     if (ISCTL(Line[Point - 1]))
  303.         TTYback();
  304.         else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
  305.         TTYback();
  306.         TTYback();
  307.     }
  308.     }
  309.     if (Change == CSmove)
  310.     Point--;
  311. }
  312.  
  313. STATIC void
  314. right(Change)
  315.     STATUS    Change;
  316. {
  317.     TTYshow(Line[Point]);
  318.     if (Change == CSmove)
  319.     Point++;
  320. }
  321.  
  322. STATIC STATUS
  323. ring_bell()
  324. {
  325.     TTYput('\07');
  326.     TTYflush();
  327.     return CSstay;
  328. }
  329.  
  330. STATIC STATUS
  331. do_macro(c)
  332.     unsigned int    c;
  333. {
  334.     CHAR        name[4];
  335.  
  336.     name[0] = '_';
  337.     name[1] = c;
  338.     name[2] = '_';
  339.     name[3] = '\0';
  340.  
  341.     if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
  342.     Input = NIL;
  343.     return ring_bell();
  344.     }
  345.     return CSstay;
  346. }
  347.  
  348. STATIC STATUS
  349. do_forward(move)
  350.     STATUS    move;
  351. {
  352.     int        i;
  353.     CHAR    *p;
  354.  
  355.     i = 0;
  356.     do {
  357.     p = &Line[Point];
  358.     for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
  359.         if (move == CSmove)
  360.         right(CSstay);
  361.  
  362.     for (; Point < End && isalnum(*p); Point++, p++)
  363.         if (move == CSmove)
  364.         right(CSstay);
  365.  
  366.     if (Point == End)
  367.         break;
  368.     } while (++i < Repeat);
  369.  
  370.     return CSstay;
  371. }
  372.  
  373. STATIC STATUS
  374. do_case(type)
  375.     CASE    type;
  376. {
  377.     int        i;
  378.     int        end;
  379.     int        count;
  380.     CHAR    *p;
  381.  
  382.     (void)do_forward(CSstay);
  383.     if (OldPoint != Point) {
  384.     if ((count = Point - OldPoint) < 0)
  385.         count = -count;
  386.     Point = OldPoint;
  387.     if ((end = Point + count) > End)
  388.         end = End;
  389.     for (i = Point, p = &Line[i]; i < end; i++, p++) {
  390.         if (type == TOupper) {
  391.         if (islower(*p))
  392.             *p = toupper(*p);
  393.         }
  394.         else if (isupper(*p))
  395.         *p = tolower(*p);
  396.         right(CSmove);
  397.     }
  398.     }
  399.     return CSstay;
  400. }
  401.  
  402. STATIC STATUS
  403. case_down_word()
  404. {
  405.     return do_case(TOlower);
  406. }
  407.  
  408. STATIC STATUS
  409. case_up_word()
  410. {
  411.     return do_case(TOupper);
  412. }
  413.  
  414. STATIC void
  415. ceol()
  416. {
  417.     int        extras;
  418.     int        i;
  419.     CHAR    *p;
  420.  
  421.     for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
  422.     TTYput(' ');
  423.     if (ISCTL(*p)) {
  424.         TTYput(' ');
  425.         extras++;
  426.     }
  427.     else if (rl_meta_chars && ISMETA(*p)) {
  428.         TTYput(' ');
  429.         TTYput(' ');
  430.         extras += 2;
  431.     }
  432.     }
  433.  
  434.     for (i += extras; i > Point; i--)
  435.     TTYback();
  436. }
  437.  
  438. STATIC void
  439. clear_line()
  440. {
  441.     Point = -strlen(Prompt);
  442.     TTYput('\r');
  443.     ceol();
  444.     Point = 0;
  445.     End = 0;
  446.     Line[0] = '\0';
  447. }
  448.  
  449. STATIC STATUS
  450. insert_string(p)
  451.     CHAR    *p;
  452. {
  453.     SIZE_T    len;
  454.     int        i;
  455.     CHAR    *new;
  456.     CHAR    *q;
  457.  
  458.     len = strlen((char *)p);
  459.     if (End + len >= Length) {
  460.     if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
  461.         return CSstay;
  462.     if (Length) {
  463.         COPYFROMTO(new, Line, Length);
  464.         DISPOSE(Line);
  465.     }
  466.     Line = new;
  467.     Length += len + MEM_INC;
  468.     }
  469.  
  470.     for (q = &Line[Point], i = End - Point; --i >= 0; )
  471.     q[len + i] = q[i];
  472.     COPYFROMTO(&Line[Point], p, len);
  473.     End += len;
  474.     Line[End] = '\0';
  475.     TTYstring(&Line[Point]);
  476.     Point += len;
  477.  
  478.     return Point == End ? CSstay : CSmove;
  479. }
  480.  
  481.  
  482. STATIC CHAR *
  483. next_hist()
  484. {
  485.     return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
  486. }
  487.  
  488. STATIC CHAR *
  489. prev_hist()
  490. {
  491.     return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
  492. }
  493.  
  494. STATIC STATUS
  495. do_insert_hist(p)
  496.     CHAR    *p;
  497. {
  498.     if (p == NULL)
  499.     return ring_bell();
  500.     Point = 0;
  501.     reposition();
  502.     ceol();
  503.     End = 0;
  504.     return insert_string(p);
  505. }
  506.  
  507. STATIC STATUS
  508. do_hist(move)
  509.     CHAR    *(*move)();
  510. {
  511.     CHAR    *p;
  512.     int        i;
  513.  
  514.     i = 0;
  515.     do {
  516.     if ((p = (*move)()) == NULL)
  517.         return ring_bell();
  518.     } while (++i < Repeat);
  519.     return do_insert_hist(p);
  520. }
  521.  
  522. STATIC STATUS
  523. h_next()
  524. {
  525.     return do_hist(next_hist);
  526. }
  527.  
  528. STATIC STATUS
  529. h_prev()
  530. {
  531.     return do_hist(prev_hist);
  532. }
  533.  
  534. STATIC STATUS
  535. h_first()
  536. {
  537.     return do_insert_hist(H.Lines[H.Pos = 0]);
  538. }
  539.  
  540. STATIC STATUS
  541. h_last()
  542. {
  543.     return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
  544. }
  545.  
  546. /*
  547. **  Return zero if pat appears as a substring in text.
  548. */
  549. STATIC int
  550. substrcmp(text, pat, len)
  551.     char    *text;
  552.     char    *pat;
  553.     int        len;
  554. {
  555.     CHAR    c;
  556.  
  557.     if ((c = *pat) == '\0')
  558.         return *text == '\0';
  559.     for ( ; *text; text++)
  560.         if (*text == c && strncmp(text, pat, len) == 0)
  561.             return 0;
  562.     return 1;
  563. }
  564.  
  565. STATIC CHAR *
  566. search_hist(search, move)
  567.     CHAR    *search;
  568.     CHAR    *(*move)();
  569. {
  570.     static CHAR    *old_search;
  571.     int        len;
  572.     int        pos;
  573.     int        (*match)();
  574.     char    *pat;
  575.  
  576.     /* Save or get remembered search pattern. */
  577.     if (search && *search) {
  578.     if (old_search)
  579.         DISPOSE(old_search);
  580.     old_search = (CHAR *)strdup((char *)search);
  581.     }
  582.     else {
  583.     if (old_search == NULL || *old_search == '\0')
  584.             return NULL;
  585.     search = old_search;
  586.     }
  587.  
  588.     /* Set up pattern-finder. */
  589.     if (*search == '^') {
  590.     match = strncmp;
  591.     pat = (char *)(search + 1);
  592.     }
  593.     else {
  594.     match = substrcmp;
  595.     pat = (char *)search;
  596.     }
  597.     len = strlen(pat);
  598.  
  599.     for (pos = H.Pos; (*move)() != NULL; )
  600.     if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
  601.             return H.Lines[H.Pos];
  602.     H.Pos = pos;
  603.     return NULL;
  604. }
  605.  
  606. STATIC STATUS
  607. h_search()
  608. {
  609.     static int    Searching;
  610.     CONST char    *old_prompt;
  611.     CHAR    *(*move)();
  612.     CHAR    *p;
  613.  
  614.     if (Searching)
  615.     return ring_bell();
  616.     Searching = 1;
  617.  
  618.     clear_line();
  619.     old_prompt = Prompt;
  620.     Prompt = "Search: ";
  621.     TTYputs((CHAR *)Prompt);
  622.     move = Repeat == NO_ARG ? prev_hist : next_hist;
  623.     p = search_hist(editinput(), move);
  624.     clear_line();
  625.     Prompt = old_prompt;
  626.     TTYputs((CHAR *)Prompt);
  627.  
  628.     Searching = 0;
  629.     return do_insert_hist(p);
  630. }
  631.  
  632. STATIC STATUS
  633. fd_char()
  634. {
  635.     int        i;
  636.  
  637.     i = 0;
  638.     do {
  639.     if (Point >= End)
  640.         break;
  641.     right(CSmove);
  642.     } while (++i < Repeat);
  643.     return CSstay;
  644. }
  645.  
  646. STATIC void
  647. save_yank(begin, i)
  648.     int        begin;
  649.     int        i;
  650. {
  651.     if (Yanked) {
  652.     DISPOSE(Yanked);
  653.     Yanked = NULL;
  654.     }
  655.  
  656.     if (i < 1)
  657.     return;
  658.  
  659.     if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
  660.     COPYFROMTO(Yanked, &Line[begin], i);
  661.     Yanked[i] = '\0';
  662.     }
  663. }
  664.  
  665. STATIC STATUS
  666. delete_string(count)
  667.     int        count;
  668. {
  669.     int        i;
  670.     CHAR    *p;
  671.  
  672.     if (count <= 0 || End == Point)
  673.     return ring_bell();
  674.  
  675.     if (count == 1 && Point == End - 1) {
  676.     /* Optimize common case of delete at end of line. */
  677.     End--;
  678.     p = &Line[Point];
  679.     i = 1;
  680.     TTYput(' ');
  681.     if (ISCTL(*p)) {
  682.         i = 2;
  683.         TTYput(' ');
  684.     }
  685.     else if (rl_meta_chars && ISMETA(*p)) {
  686.         i = 3;
  687.         TTYput(' ');
  688.         TTYput(' ');
  689.     }
  690.     TTYbackn(i);
  691.     *p = '\0';
  692.     return CSmove;
  693.     }
  694.     if (Point + count > End && (count = End - Point) <= 0)
  695.     return CSstay;
  696.  
  697.     if (count > 1)
  698.     save_yank(Point, count);
  699.  
  700.     for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
  701.     p[0] = p[count];
  702.     ceol();
  703.     End -= count;
  704.     TTYstring(&Line[Point]);
  705.     return CSmove;
  706. }
  707.  
  708. STATIC STATUS
  709. bk_char()
  710. {
  711.     int        i;
  712.  
  713.     i = 0;
  714.     do {
  715.     if (Point == 0)
  716.         break;
  717.     left(CSmove);
  718.     } while (++i < Repeat);
  719.  
  720.     return CSstay;
  721. }
  722.  
  723. STATIC STATUS
  724. bk_del_char()
  725. {
  726.     int        i;
  727.  
  728.     i = 0;
  729.     do {
  730.     if (Point == 0)
  731.         break;
  732.     left(CSmove);
  733.     } while (++i < Repeat);
  734.  
  735.     return delete_string(i);
  736. }
  737.  
  738. STATIC STATUS
  739. redisplay()
  740. {
  741.     TTYputs((CHAR *)NEWLINE);
  742.     TTYputs((CHAR *)Prompt);
  743.     TTYstring(Line);
  744.     return CSmove;
  745. }
  746.  
  747. STATIC STATUS
  748. kill_line()
  749. {
  750.     int        i;
  751.  
  752.     if (Repeat != NO_ARG) {
  753.     if (Repeat < Point) {
  754.         i = Point;
  755.         Point = Repeat;
  756.         reposition();
  757.         (void)delete_string(i - Point);
  758.     }
  759.     else if (Repeat > Point) {
  760.         right(CSmove);
  761.         (void)delete_string(Repeat - Point - 1);
  762.     }
  763.     return CSmove;
  764.     }
  765.  
  766.     save_yank(Point, End - Point);
  767.     Line[Point] = '\0';
  768.     ceol();
  769.     End = Point;
  770.     return CSstay;
  771. }
  772.  
  773. STATIC STATUS
  774. insert_char(c)
  775.     int        c;
  776. {
  777.     STATUS    s;
  778.     CHAR    buff[2];
  779.     CHAR    *p;
  780.     CHAR    *q;
  781.     int        i;
  782.  
  783.     if (Repeat == NO_ARG || Repeat < 2) {
  784.     buff[0] = c;
  785.     buff[1] = '\0';
  786.     return insert_string(buff);
  787.     }
  788.  
  789.     if ((p = NEW(CHAR, Repeat + 1)) == NULL)
  790.     return CSstay;
  791.     for (i = Repeat, q = p; --i >= 0; )
  792.     *q++ = c;
  793.     *q = '\0';
  794.     Repeat = 0;
  795.     s = insert_string(p);
  796.     DISPOSE(p);
  797.     return s;
  798. }
  799.  
  800. STATIC STATUS
  801. meta()
  802. {
  803.     unsigned int    c;
  804.     KEYMAP        *kp;
  805.  
  806.     if ((c = TTYget()) == EOF)
  807.     return CSeof;
  808. #if    defined(ANSI_ARROWS)
  809.     /* Also include VT-100 arrows. */
  810.     if (c == '[' || c == 'O')
  811.     switch (c = TTYget()) {
  812.     default:    return ring_bell();
  813.     case EOF:    return CSeof;
  814.     case 'A':    return h_prev();
  815.     case 'B':    return h_next();
  816.     case 'C':    return fd_char();
  817.     case 'D':    return bk_char();
  818.     }
  819. #endif    /* defined(ANSI_ARROWS) */
  820.  
  821.     if (isdigit(c)) {
  822.     for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
  823.         Repeat = Repeat * 10 + c - '0';
  824.     Pushed = 1;
  825.     PushBack = c;
  826.     return CSstay;
  827.     }
  828.  
  829.     if (isupper(c))
  830.     return do_macro(c);
  831.     for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
  832.     if (kp->Key == c)
  833.         return (*kp->Function)();
  834.  
  835.     return ring_bell();
  836. }
  837.  
  838. STATIC STATUS
  839. emacs(c)
  840.     unsigned int    c;
  841. {
  842.     STATUS        s;
  843.     KEYMAP        *kp;
  844.  
  845.     if (ISMETA(c)) {
  846.     Pushed = 1;
  847.     PushBack = UNMETA(c);
  848.     return meta();
  849.     }
  850.     for (kp = Map; kp->Function; kp++)
  851.     if (kp->Key == c)
  852.         break;
  853.     s = kp->Function ? (*kp->Function)() : insert_char((int)c);
  854.     if (!Pushed)
  855.     /* No pushback means no repeat count; hacky, but true. */
  856.     Repeat = NO_ARG;
  857.     return s;
  858. }
  859.  
  860. STATIC STATUS
  861. TTYspecial(c)
  862.     unsigned int    c;
  863. {
  864.     if (ISMETA(c))
  865.     return CSdispatch;
  866.  
  867.     if (c == rl_erase || c == DEL)
  868.     return bk_del_char();
  869.     if (c == rl_kill) {
  870.     if (Point != 0) {
  871.         Point = 0;
  872.         reposition();
  873.     }
  874.     Repeat = NO_ARG;
  875.     return kill_line();
  876.     }
  877.     if (c == rl_intr || c == rl_quit) {
  878.     Point = End = 0;
  879.     Line[0] = '\0';
  880.     return redisplay();
  881.     }
  882.     if (c == rl_eof && Point == 0 && End == 0)
  883.     return CSeof;
  884.  
  885.     return CSdispatch;
  886. }
  887.  
  888. STATIC CHAR *
  889. editinput()
  890. {
  891.     unsigned int    c;
  892.  
  893.     Repeat = NO_ARG;
  894.     OldPoint = Point = Mark = End = 0;
  895.     Line[0] = '\0';
  896.  
  897.     while ((c = TTYget()) != EOF)
  898.     switch (TTYspecial(c)) {
  899.     case CSdone:
  900.         return Line;
  901.     case CSeof:
  902.         return NULL;
  903.     case CSmove:
  904.         reposition();
  905.         break;
  906.     case CSdispatch:
  907.         switch (emacs(c)) {
  908.         case CSdone:
  909.         return Line;
  910.         case CSeof:
  911.         return NULL;
  912.         case CSmove:
  913.         reposition();
  914.         break;
  915.         case CSdispatch:
  916.         case CSstay:
  917.         break;
  918.         }
  919.         break;
  920.     case CSstay:
  921.         break;
  922.     }
  923.     return NULL;
  924. }
  925.  
  926. STATIC void
  927. hist_add(p)
  928.     CHAR    *p;
  929. {
  930.     int        i;
  931.  
  932.     if ((p = (CHAR *)strdup((char *)p)) == NULL)
  933.     return;
  934.     if (H.Size < HIST_SIZE)
  935.     H.Lines[H.Size++] = p;
  936.     else {
  937.     DISPOSE(H.Lines[0]);
  938.     for (i = 0; i < HIST_SIZE - 1; i++)
  939.         H.Lines[i] = H.Lines[i + 1];
  940.     H.Lines[i] = p;
  941.     }
  942.     H.Pos = H.Size - 1;
  943. }
  944.  
  945. /*
  946. **  For compatibility with FSF readline.
  947. */
  948. /* ARGSUSED0 */
  949. void
  950. rl_reset_terminal(p)
  951.     char    *p;
  952. {
  953. }
  954.  
  955. void
  956. rl_initialize()
  957. {
  958. }
  959.  
  960. char *
  961. readline(prompt)
  962.     CONST char    *prompt;
  963. {
  964.     CHAR    *line;
  965.  
  966.     printf("Version: %s\n",string);
  967.     if (Line == NULL) {
  968.     Length = MEM_INC;
  969.     if ((Line = NEW(CHAR, Length)) == NULL)
  970.         return NULL;
  971.     }
  972.  
  973.     TTYinfo();
  974.     rl_ttyset(0);
  975.     hist_add(NIL);
  976.     ScreenSize = SCREEN_INC;
  977.     Screen = NEW(char, ScreenSize);
  978.     Prompt = prompt ? prompt : (char *)NIL;
  979.     TTYputs((CHAR *)Prompt);
  980.     if ((line = editinput()) != NULL) {
  981.     line = (CHAR *)strdup((char *)line);
  982.     TTYputs((CHAR *)NEWLINE);
  983.     TTYflush();
  984.     }
  985.     rl_ttyset(1);
  986.     DISPOSE(Screen);
  987.     DISPOSE(H.Lines[--H.Size]);
  988.     return (char *)line;
  989. }
  990.  
  991. void
  992. add_history(p)
  993.     char    *p;
  994. {
  995.     if (p == NULL || *p == '\0')
  996.     return;
  997.  
  998. #if    defined(UNIQUE_HISTORY)
  999.     if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
  1000.         return;
  1001. #endif    /* defined(UNIQUE_HISTORY) */
  1002.     hist_add((CHAR *)p);
  1003. }
  1004.  
  1005.  
  1006. STATIC STATUS
  1007. beg_line()
  1008. {
  1009.     if (Point) {
  1010.     Point = 0;
  1011.     return CSmove;
  1012.     }
  1013.     return CSstay;
  1014. }
  1015.  
  1016. STATIC STATUS
  1017. del_char()
  1018. {
  1019.     return delete_string(Repeat == NO_ARG ? 1 : Repeat);
  1020. }
  1021.  
  1022. STATIC STATUS
  1023. end_line()
  1024. {
  1025.     if (Point != End) {
  1026.     Point = End;
  1027.     return CSmove;
  1028.     }
  1029.     return CSstay;
  1030. }
  1031.  
  1032. /*
  1033. **  Move back to the beginning of the current word and return an
  1034. **  allocated copy of it.
  1035. */
  1036. STATIC CHAR *
  1037. find_word()
  1038. {
  1039.     static char    SEPS[] = "#;&|^$=`'{}()<>\n\t ";
  1040.     CHAR    *p;
  1041.     CHAR    *new;
  1042.     SIZE_T    len;
  1043.  
  1044.     for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
  1045.     continue;
  1046.     len = Point - (p - Line) + 1;
  1047.     if ((new = NEW(CHAR, len)) == NULL)
  1048.     return NULL;
  1049.     COPYFROMTO(new, p, len);
  1050.     new[len - 1] = '\0';
  1051.     return new;
  1052. }
  1053.  
  1054. STATIC STATUS
  1055. c_complete()
  1056. {
  1057.     CHAR    *p;
  1058.     CHAR    *word;
  1059.     int        unique;
  1060.     STATUS    s;
  1061.  
  1062.     word = find_word();
  1063.     p = (CHAR *)rl_complete((char *)word, &unique);
  1064.     if (word)
  1065.     DISPOSE(word);
  1066.     if (p && *p) {
  1067.     s = insert_string(p);
  1068.     if (!unique)
  1069.         (void)ring_bell();
  1070.     DISPOSE(p);
  1071.     return s;
  1072.     }
  1073.     return ring_bell();
  1074. }
  1075.  
  1076. STATIC STATUS
  1077. c_possible()
  1078. {
  1079.     CHAR    **av;
  1080.     CHAR    *word;
  1081.     int        ac;
  1082.  
  1083.     word = find_word();
  1084.     ac = rl_list_possib((char *)word, (char ***)&av);
  1085.     if (word)
  1086.     DISPOSE(word);
  1087.     if (ac) {
  1088.     columns(ac, av);
  1089.     while (--ac >= 0)
  1090.         DISPOSE(av[ac]);
  1091.     DISPOSE(av);
  1092.     return CSmove;
  1093.     }
  1094.     return ring_bell();
  1095. }
  1096.  
  1097. STATIC STATUS
  1098. accept_line()
  1099. {
  1100.     Line[End] = '\0';
  1101.     return CSdone;
  1102. }
  1103.  
  1104. STATIC STATUS
  1105. transpose()
  1106. {
  1107.     CHAR    c;
  1108.  
  1109.     if (Point) {
  1110.     if (Point == End)
  1111.         left(CSmove);
  1112.     c = Line[Point - 1];
  1113.     left(CSstay);
  1114.     Line[Point - 1] = Line[Point];
  1115.     TTYshow(Line[Point - 1]);
  1116.     Line[Point++] = c;
  1117.     TTYshow(c);
  1118.     }
  1119.     return CSstay;
  1120. }
  1121.  
  1122. STATIC STATUS
  1123. quote()
  1124. {
  1125.     unsigned int    c;
  1126.  
  1127.     return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
  1128. }
  1129.  
  1130. STATIC STATUS
  1131. wipe()
  1132. {
  1133.     int        i;
  1134.  
  1135.     if (Mark > End)
  1136.     return ring_bell();
  1137.  
  1138.     if (Point > Mark) {
  1139.     i = Point;
  1140.     Point = Mark;
  1141.     Mark = i;
  1142.     reposition();
  1143.     }
  1144.  
  1145.     return delete_string(Mark - Point);
  1146. }
  1147.  
  1148. STATIC STATUS
  1149. mk_set()
  1150. {
  1151.     Mark = Point;
  1152.     return CSstay;
  1153. }
  1154.  
  1155. STATIC STATUS
  1156. exchange()
  1157. {
  1158.     unsigned int    c;
  1159.  
  1160.     if ((c = TTYget()) != CTL('X'))
  1161.     return c == EOF ? CSeof : ring_bell();
  1162.  
  1163.     if ((c = Mark) <= End) {
  1164.     Mark = Point;
  1165.     Point = c;
  1166.     return CSmove;
  1167.     }
  1168.     return CSstay;
  1169. }
  1170.  
  1171. STATIC STATUS
  1172. yank()
  1173. {
  1174.     if (Yanked && *Yanked)
  1175.     return insert_string(Yanked);
  1176.     return CSstay;
  1177. }
  1178.  
  1179. STATIC STATUS
  1180. copy_region()
  1181. {
  1182.     if (Mark > End)
  1183.     return ring_bell();
  1184.  
  1185.     if (Point > Mark)
  1186.     save_yank(Mark, Point - Mark);
  1187.     else
  1188.     save_yank(Point, Mark - Point);
  1189.  
  1190.     return CSstay;
  1191. }
  1192.  
  1193. STATIC STATUS
  1194. move_to_char()
  1195. {
  1196.     unsigned int    c;
  1197.     int            i;
  1198.     CHAR        *p;
  1199.  
  1200.     if ((c = TTYget()) == EOF)
  1201.     return CSeof;
  1202.     for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
  1203.     if (*p == c) {
  1204.         Point = i;
  1205.         return CSmove;
  1206.     }
  1207.     return CSstay;
  1208. }
  1209.  
  1210. STATIC STATUS
  1211. fd_word()
  1212. {
  1213.     return do_forward(CSmove);
  1214. }
  1215.  
  1216. STATIC STATUS
  1217. fd_kill_word()
  1218. {
  1219.     int        i;
  1220.  
  1221.     (void)do_forward(CSstay);
  1222.     if (OldPoint != Point) {
  1223.     i = Point - OldPoint;
  1224.     Point = OldPoint;
  1225.     return delete_string(i);
  1226.     }
  1227.     return CSstay;
  1228. }
  1229.  
  1230. STATIC STATUS
  1231. bk_word()
  1232. {
  1233.     int        i;
  1234.     CHAR    *p;
  1235.  
  1236.     i = 0;
  1237.     do {
  1238.     for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
  1239.         left(CSmove);
  1240.  
  1241.     for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
  1242.         left(CSmove);
  1243.  
  1244.     if (Point == 0)
  1245.         break;
  1246.     } while (++i < Repeat);
  1247.  
  1248.     return CSstay;
  1249. }
  1250.  
  1251. STATIC STATUS
  1252. bk_kill_word()
  1253. {
  1254.     (void)bk_word();
  1255.     if (OldPoint != Point)
  1256.     return delete_string(OldPoint - Point);
  1257.     return CSstay;
  1258. }
  1259.  
  1260. STATIC int
  1261. argify(line, avp)
  1262.     CHAR    *line;
  1263.     CHAR    ***avp;
  1264. {
  1265.     CHAR    *c;
  1266.     CHAR    **p;
  1267.     CHAR    **new;
  1268.     int        ac;
  1269.     int        i;
  1270.  
  1271.     i = MEM_INC;
  1272.     if ((*avp = p = NEW(CHAR*, i))== NULL)
  1273.      return 0;
  1274.  
  1275.     for (c = line; isspace(*c); c++)
  1276.     continue;
  1277.     if (*c == '\n' || *c == '\0')
  1278.     return 0;
  1279.  
  1280.     for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
  1281.     if (isspace(*c)) {
  1282.         *c++ = '\0';
  1283.         if (*c && *c != '\n') {
  1284.         if (ac + 1 == i) {
  1285.             new = NEW(CHAR*, i + MEM_INC);
  1286.             if (new == NULL) {
  1287.             p[ac] = NULL;
  1288.             return ac;
  1289.             }
  1290.             COPYFROMTO(new, p, i * sizeof (char **));
  1291.             i += MEM_INC;
  1292.             DISPOSE(p);
  1293.             *avp = p = new;
  1294.         }
  1295.         p[ac++] = c;
  1296.         }
  1297.     }
  1298.     else
  1299.         c++;
  1300.     }
  1301.     *c = '\0';
  1302.     p[ac] = NULL;
  1303.     return ac;
  1304. }
  1305.  
  1306. STATIC STATUS
  1307. last_argument()
  1308. {
  1309.     CHAR    **av;
  1310.     CHAR    *p;
  1311.     STATUS    s;
  1312.     int        ac;
  1313.  
  1314.     if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
  1315.     return ring_bell();
  1316.  
  1317.     if ((p = (CHAR *)strdup((char *)p)) == NULL)
  1318.     return CSstay;
  1319.     ac = argify(p, &av);
  1320.  
  1321.     if (Repeat != NO_ARG)
  1322.     s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
  1323.     else
  1324.     s = ac ? insert_string(av[ac - 1]) : CSstay;
  1325.  
  1326.     if (ac)
  1327.     DISPOSE(av);
  1328.     DISPOSE(p);
  1329.     return s;
  1330. }
  1331.  
  1332. STATIC KEYMAP    Map[33] = {
  1333.     {    CTL('@'),    ring_bell    },
  1334.     {    CTL('A'),    beg_line    },
  1335.     {    CTL('B'),    bk_char        },
  1336.     {    CTL('D'),    del_char    },
  1337.     {    CTL('E'),    end_line    },
  1338.     {    CTL('F'),    fd_char        },
  1339.     {    CTL('G'),    ring_bell    },
  1340.     {    CTL('H'),    bk_del_char    },
  1341.     {    CTL('I'),    c_complete    },
  1342.     {    CTL('J'),    accept_line    },
  1343.     {    CTL('K'),    kill_line    },
  1344.     {    CTL('L'),    redisplay    },
  1345.     {    CTL('M'),    accept_line    },
  1346.     {    CTL('N'),    h_next        },
  1347.     {    CTL('O'),    ring_bell    },
  1348.     {    CTL('P'),    h_prev        },
  1349.     {    CTL('Q'),    ring_bell    },
  1350.     {    CTL('R'),    h_search    },
  1351.     {    CTL('S'),    ring_bell    },
  1352.     {    CTL('T'),    transpose    },
  1353.     {    CTL('U'),    ring_bell    },
  1354.     {    CTL('V'),    quote        },
  1355.     {    CTL('W'),    wipe        },
  1356.     {    CTL('X'),    exchange    },
  1357.     {    CTL('Y'),    yank        },
  1358.     {    CTL('Z'),    ring_bell    },
  1359.     {    CTL('['),    meta        },
  1360.     {    CTL(']'),    move_to_char    },
  1361.     {    CTL('^'),    ring_bell    },
  1362.     {    CTL('_'),    ring_bell    },
  1363.     {    0,        NULL        }
  1364. };
  1365.  
  1366. STATIC KEYMAP    MetaMap[16]= {
  1367.     {    CTL('H'),    bk_kill_word    },
  1368.     {    DEL,        bk_kill_word    },
  1369.     {    ' ',        mk_set    },
  1370.     {    '.',        last_argument    },
  1371.     {    '<',        h_first        },
  1372.     {    '>',        h_last        },
  1373.     {    '?',        c_possible    },
  1374.     {    'b',        bk_word        },
  1375.     {    'd',        fd_kill_word    },
  1376.     {    'f',        fd_word        },
  1377.     {    'l',        case_down_word    },
  1378.     {    'u',        case_up_word    },
  1379.     {    'y',        yank        },
  1380.     {    'w',        copy_region    },
  1381.     {    0,        NULL        }
  1382. };
  1383.