home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / GNU_ATP_1_40.lzh / EDITLINE / editline.c < prev    next >
Text File  |  1993-08-04  |  27KB  |  1,534 lines

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