home *** CD-ROM | disk | FTP | other *** search
/ Computer Club Elmshorn Atari PD / CCE_PD.iso / pc / 0600 / CCE_0638.ZIP / CCE_0638 / UPDATE / UPDATE29.ZOO / editline / editline.c < prev    next >
C/C++ Source or Header  |  1993-03-28  |  23KB  |  1,413 lines

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