openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

editline.c (37116B)


      1 /*  $Revision: 1.21 $
      2 **
      3 **  Main editing routines for editline library.
      4 **
      5 ** There are two editline implementations: synchronous and asynchronsou.
      6 ** Synchronous is a blocking read call readline(CONST char *prompt).
      7 ** This call returns after a whole line has been read, returning that
      8 ** line to the user. The returned line could have been pulled from history
      9 ** or directly from stdin.
     10 **
     11 ** Asynchronous is a character process non-blocking call, which make 
     12 ** a callout to an end-of-line handler. The entry points for these calls
     13 ** are:
     14 ** rl_callback_handler_install(CONST char *prompt, rl_vcpfunc_t eol_handler, 
     15 ** rl_callback_read_char(void)
     16 ** rl_callback_handler_remove(void)
     17 **
     18 ** Algorithm 
     19 ** 
     20 ** The major steps taken for synchronous API are:
     21 ** READ LINE
     22 **   TTYInfo
     23 **   rl_ttyset(0)
     24 **   hist_add(nil)
     25 **   TTYputs(Prompt)
     26 **   read line
     27 **   TTYputs(NEWLINE)
     28 **   rl_ttyset(1)
     29 **   DISPOSE(H.Lines[-H.Size]);
     30 **   return line
     31 **   add to history
     32 ** All operations are done during the readline call.
     33 **
     34 ** The Major steps for asynchronous are broken into three stages.
     35 **
     36 ** START <- rl_callback_handler_install
     37 **   TTYInfo
     38 **   rl_ttyset(0)
     39 **   hist_add(nil)
     40 **                                    
     41 ** READ CHAR <- rl_callback_read_char
     42 **   TTYInfo
     43 **   hist_add(nil)
     44 **   read character
     45 **   DISPOSE(H.Lines[-H.Size]);
     46 **   if end-of-line then call eol_callback with line
     47 **   hist_add(nil)
     48 **   TTYputs(Prompt)
     49 **
     50 ** CLEAN <- rl_callback_handler_remove
     51 **  rl_ttyset(1)
     52 **
     53 ** START is done initially once. CLEAN is done at termination. READ
     54 */
     55 
     56 #ifdef INCLUDE_EDITLINE
     57 
     58 #include "sal/appl/editline/editline.h"
     59 #include "editline.h"
     60 #if defined(INCLUDE_AUTOCOMPLETE)
     61 #include <sal/appl/editline/autocomplete.h>
     62 #endif
     63 
     64 #include <appl/diag/shell.h>
     65 
     66 #if     defined(USE_POSIX_SIGNALS)
     67 #include <signal.h>
     68 #include <errno.h>
     69 #else
     70 /* Dummy defines to avoid too many ifdefs */
     71 #define	SIGINT	        2
     72 #define	SIGQUIT	        3
     73 #define	SIGTSTP	        20
     74 #endif
     75 
     76 /*
     77 **  Manifest constants.
     78 */
     79 #define SCREEN_WIDTH	80
     80 #define SCREEN_ROWS	24
     81 #define NO_ARG		(-1)
     82 #define DEL		127
     83 #define TAB		'\t'
     84 #define CTL(x)		((x) & 0x1F)
     85 #define ISCTL(x)	((x) && (x) < ' ')
     86 #define UNCTL(x)	((x) + 64)
     87 #define META(x)		((x) | 0x80)
     88 #define ISMETA(x)	((x) & 0x80)
     89 #define UNMETA(x)	((x) & 0x7F)
     90 #define MAPSIZE		32
     91 #define METAMAPSIZE	20
     92 #if	!defined(HIST_SIZE)
     93 #define HIST_SIZE	20
     94 #endif	/* !defined(HIST_SIZE) */
     95 
     96 
     97 typedef CONST CHAR	*STRING;
     98 
     99 /*
    100 **  Command status codes.
    101 */
    102 typedef enum _STATE {
    103     CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
    104 } STATE;
    105 
    106 /*
    107 **  The type of case-changing to perform.
    108 */
    109 typedef enum _CASE {
    110     TOupper, TOlower
    111 } CASE;
    112 
    113 /*
    114 **  Key to command mapping.
    115 */
    116 typedef struct _KEYMAP {
    117     CHAR	Key;
    118     char	Active;
    119     STATE	(*Function)();
    120 } KEYMAP;
    121 
    122 /*
    123 **  Command history structure.
    124 */
    125 typedef struct _HISTORY {
    126     int		Size;
    127     int		Pos;
    128     CHAR	*Lines[HIST_SIZE];
    129 } HISTORY;
    130 
    131 /*
    132 **  Globals.
    133 */
    134 int		rl_eof;
    135 int		rl_erase;
    136 int		rl_intr;
    137 int		rl_kill;
    138 int		rl_quit;
    139 #if	defined(DO_SIGTSTP)
    140 int		rl_susp;
    141 #endif	/* defined(DO_SIGTSTP) */
    142 char		*(*rl_complete)() = rl_complete_file;
    143 int		(*rl_list_possib)() = rl_list_possib_file;
    144 
    145 STATIC CHAR		NIL[] = "";
    146 STATIC STRING		Input = NIL;
    147 STATIC CHAR		*Line;
    148 STATIC CONST char	*Prompt;
    149 STATIC CHAR		*Yanked;
    150 STATIC char		*Screen;
    151 STATIC char		NEWLINE[]= CRLF;
    152 STATIC HISTORY		H;
    153 STATIC int		Repeat;
    154 STATIC int		End;
    155 STATIC int		Mark;
    156 STATIC int		CursorPos;	/* Relative to beginning of prompt */
    157 STATIC int		OldPoint;
    158 STATIC int		Point;
    159 STATIC int		PushBack;
    160 STATIC int		Pushed;
    161 STATIC int		Signal;
    162 FORWARD KEYMAP		Map[MAPSIZE];
    163 FORWARD KEYMAP		MetaMap[METAMAPSIZE];
    164 STATIC SIZE_T		Length;
    165 STATIC SIZE_T		ScreenCount;
    166 STATIC SIZE_T		ScreenSize;
    167 STATIC char		*backspace;
    168 STATIC int		TTYwidth;
    169 STATIC int		TTYrows;
    170 
    171 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
    172 int		rl_meta_chars = 1;
    173 
    174 STATIC rl_vcpfunc_t gCALLBACK_EOL_HANDLER     = NULL;
    175 STATIC void        *gCALLBACK_EOL_HANDLER_CTX = NULL;
    176 STATIC rf_vcpfunc_t gCALLBACK_EOF_HANDLER     = NULL;
    177 STATIC void        *gCALLBACK_EOF_HANDLER_CTX = NULL;
    178 
    179 /*
    180 **  Declarations.
    181 */
    182 STATIC CHAR	*editinput();
    183 #if	defined(USE_TERMCAP)
    184 extern char	*getenv();
    185 extern char	*tgetstr();
    186 extern int	tgetent();
    187 extern int	tgetnum();
    188 #endif	/* defined(USE_TERMCAP) */
    189 
    190 /*
    191 **  TTY input/output functions.
    192 */
    193 
    194 STATIC void
    195 TTYflush()
    196 {
    197   if (ScreenCount) {
    198 	(void)sal_console_write(Screen, ScreenCount);
    199 	ScreenCount = 0;
    200   }
    201 }
    202 
    203 STATIC void
    204 TTYput(CONST CHAR c)
    205 {
    206     Screen[ScreenCount] = c;
    207     switch (c) {
    208     case '\b':
    209 	CursorPos--;
    210 	break;
    211     case '\r':
    212 	/* Actually, never use CR any more; use TTYbol() instead */
    213 	CursorPos = 0;
    214 	break;
    215     default:
    216 	if (c >= ' ')
    217 	    CursorPos++;
    218     }
    219     if (++ScreenCount >= ScreenSize - 1) {
    220 	char *p;
    221 	ScreenSize += SCREEN_INC;
    222 	p = NEW(char, ScreenSize);
    223 	memcpy(p, Screen, (ScreenSize - SCREEN_INC));
    224 	DISPOSE(Screen);
    225 	Screen = p;
    226     }
    227 }
    228 
    229 STATIC void
    230 TTYputs(STRING p)
    231 {
    232     while (*p)
    233 	TTYput(*p++);
    234 }
    235 
    236 STATIC void
    237 TTYshow(CHAR c)
    238 {
    239   if (c == DEL) {
    240 	TTYput('^');
    241 	TTYput('?');
    242   } else if (c == TAB) {
    243 	/* XXX */
    244   } else if (ISCTL(c)) {
    245 	TTYput('^');
    246 	TTYput(UNCTL(c));
    247   } else if (rl_meta_chars && ISMETA(c)) {
    248     TTYput('M');
    249 	TTYput('-');
    250 	TTYput(UNMETA(c));
    251   } else {
    252 	TTYput(c);
    253   }
    254 }
    255 
    256 STATIC void
    257 TTYstring(CHAR *p)
    258 {
    259     while (*p)
    260 	TTYshow(*p++);
    261 }
    262 
    263 STATIC unsigned int
    264 TTYget()
    265 {
    266     CHAR	c;
    267     int		n;
    268 
    269     TTYflush();
    270     if (Pushed) {
    271       Pushed = 0;
    272       return PushBack;
    273     }
    274 
    275     if (*Input) {
    276       return *Input++;
    277     }
    278 
    279     n = sal_console_read(&c, 1) == 1 ? c : EOF;
    280 
    281     return n;
    282 }
    283 
    284 #define TTYback()	(backspace ? TTYputs((STRING)backspace) : TTYput('\b'))
    285 
    286 STATIC void
    287 TTYbackn(int n)
    288 {
    289     while (--n >= 0)
    290 	TTYback();
    291 }
    292 
    293 STATIC void
    294 TTYbol()
    295 {
    296     while (CursorPos > 0)
    297 	TTYback();
    298 }
    299 
    300 STATIC void
    301 TTYinfo()
    302 {
    303     static int		init;
    304     sal_console_info_t  info;
    305 #if	defined(USE_TERMCAP)
    306     char		*term;
    307     char		buff[2048];
    308     char		*bp;
    309     char		*p;
    310 #endif	/* defined(USE_TERMCAP) */
    311 
    312     if (init) {
    313 	/* Perhaps we got resized. */
    314 	if (sal_console_info_get(&info) >= 0
    315 	 && info.cols > 0 && info.rows > 0) {
    316 	    TTYwidth = info.cols;
    317 	    TTYrows = info.rows;
    318 	}
    319 	return;
    320     }
    321     init++;
    322 
    323     TTYwidth = TTYrows = 0;
    324 #if	defined(USE_TERMCAP)
    325     bp = &buff[0];
    326     if ((term = getenv("TERM")) == NULL)
    327 	term = "dumb";
    328     if (tgetent(buff, term) < 0) {
    329 	TTYwidth = SCREEN_WIDTH;
    330 	TTYrows = SCREEN_ROWS;
    331 	return;
    332     }
    333     p = tgetstr("le", &bp);
    334     backspace = p ? sal_strdup(p) : NULL;
    335     TTYwidth = tgetnum("co");
    336     TTYrows = tgetnum("li");
    337 #endif	/* defined(USE_TERMCAP) */
    338 
    339     if (sal_console_info_get(&info) >= 0) {
    340         TTYwidth = info.cols;
    341         TTYrows = info.rows;
    342     }
    343 
    344     if (TTYwidth <= 0 || TTYrows <= 0) {
    345 	TTYwidth = SCREEN_WIDTH;
    346 	TTYrows = SCREEN_ROWS;
    347     }
    348 }
    349 
    350 
    351 /*
    352 **  Print an array of words in columns.
    353 */
    354 STATIC void
    355 columns(int ac, CHAR **av)
    356 {
    357     CHAR	*p;
    358     int		i;
    359     int		j;
    360     int		k;
    361     int		len;
    362     int		skip;
    363     int		longest;
    364     int		cols;
    365 
    366     /* Find longest name, determine column count from that. */
    367     for (longest = 0, i = 0; i < ac; i++)
    368 	if ((j = strlen((char *)av[i])) > longest)
    369 	    longest = j;
    370     cols = TTYwidth / (longest + 3);
    371 
    372     TTYputs((STRING)NEWLINE);
    373     for (skip = ac / cols + 1, i = 0; i < skip; i++) {
    374 	for (j = i; j < ac; j += skip) {
    375 	    for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
    376 		TTYput(*p);
    377 	    if (j + skip < ac)
    378 		while (++len < longest + 3)
    379 		    TTYput(' ');
    380 	}
    381 	TTYputs((STRING)NEWLINE);
    382     }
    383 }
    384 
    385 STATIC void
    386 reposition()
    387 {
    388     int		i;
    389     CHAR	*p;
    390 
    391     TTYbol();
    392     TTYputs((STRING)Prompt);
    393     for (i = Point, p = Line; --i >= 0; p++) {
    394       TTYshow(*p);
    395     }
    396 }
    397 
    398 STATIC void
    399 left(STATE Change)
    400 {
    401     CHAR	c;
    402 
    403     TTYback();
    404     if (Point) {
    405 	c = Line[Point - 1];
    406 	if (c == TAB) {
    407 	    /* XXX */
    408 	}
    409 	else if (ISCTL(c))
    410 	    TTYback();
    411 	else if (rl_meta_chars && ISMETA(c)) {
    412 	    TTYback();
    413 	    TTYback();
    414 	}
    415     }
    416     if (Change == CSmove)
    417 	Point--;
    418 }
    419 
    420 STATIC void
    421 right(STATE Change)
    422 {
    423     TTYshow(Line[Point]);
    424     if (Change == CSmove)
    425 	Point++;
    426 }
    427 
    428 STATIC STATE
    429 ring_bell()
    430 {
    431     TTYput('\07');
    432     TTYflush();
    433     return CSstay;
    434 }
    435 
    436 STATIC STATE
    437 do_macro(unsigned int c)
    438 {
    439 #if	defined(USE_TERMCAP)
    440     CHAR		name[4];
    441 
    442     name[0] = '_';
    443     name[1] = c;
    444     name[2] = '_';
    445     name[3] = '\0';
    446 
    447     if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
    448 	Input = NIL;
    449 	return ring_bell();
    450     }
    451 #endif
    452     return CSstay;
    453 }
    454 
    455 STATIC STATE
    456 do_forward(STATE move)
    457 {
    458     int		i;
    459     CHAR	*p;
    460 
    461     i = 0;
    462     do {
    463 	p = &Line[Point];
    464 	for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
    465 	    if (move == CSmove)
    466 		right(CSstay);
    467 
    468 	for (; Point < End && isalnum(*p); Point++, p++)
    469 	    if (move == CSmove)
    470 		right(CSstay);
    471 
    472 	if (Point == End)
    473 	    break;
    474     } while (++i < Repeat);
    475 
    476     return CSstay;
    477 }
    478 
    479 STATIC STATE
    480 do_case(CASE type)
    481 {
    482     int		i;
    483     int		end;
    484     int		count;
    485     CHAR	*p;
    486 
    487     (void)do_forward(CSstay);
    488     if (OldPoint != Point) {
    489 	if ((count = Point - OldPoint) < 0)
    490 	    count = -count;
    491 	Point = OldPoint;
    492 	if ((end = Point + count) > End)
    493 	    end = End;
    494 	for (i = Point, p = &Line[i]; i < end; i++, p++) {
    495 	    if (type == TOupper) {
    496 		if (islower(*p))
    497 		    *p = toupper(*p);
    498 	    }
    499 	    else if (isupper(*p))
    500 		*p = tolower(*p);
    501 	    right(CSmove);
    502 	}
    503     }
    504     return CSstay;
    505 }
    506 
    507 STATIC STATE
    508 case_down_word()
    509 {
    510     return do_case(TOlower);
    511 }
    512 
    513 STATIC STATE
    514 case_up_word()
    515 {
    516     return do_case(TOupper);
    517 }
    518 
    519 STATIC void
    520 ceol()
    521 {
    522     int		extras;
    523     int		i;
    524     CHAR	*p;
    525 
    526     for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
    527 	TTYput(' ');
    528 	if (*p == TAB) {
    529 	    /* XXX */
    530 	}
    531 	else if (ISCTL(*p)) {
    532 	    TTYput(' ');
    533 	    extras++;
    534 	}
    535 	else if (rl_meta_chars && ISMETA(*p)) {
    536 	    TTYput(' ');
    537 	    TTYput(' ');
    538 	    extras += 2;
    539 	}
    540     }
    541 
    542     for (i += extras; i > Point; i--)
    543 	TTYback();
    544 }
    545 
    546 #if	defined(SEARCH_HISTORY)
    547 STATIC void
    548 clear_line()
    549 {
    550     Point = -strlen(Prompt);
    551     TTYbol();
    552     ceol();
    553     Point = 0;
    554     End = 0;
    555     Line[0] = '\0';
    556 }
    557 #endif
    558 
    559 STATIC STATE
    560 insert_string(CHAR *p)
    561 {
    562     SIZE_T	len;
    563     int		i;
    564     CHAR	*new;
    565     CHAR	*q;
    566 
    567     len = strlen((char *)p);
    568     if (End + len >= Length) {
    569 	if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
    570 	    return CSstay;
    571 	if (Length) {
    572 	    COPYFROMTO(new, Line, Length);
    573 	    DISPOSE(Line);
    574 	}
    575 	Line = new;
    576 	Length += len + MEM_INC;
    577     }
    578 
    579     for (q = &Line[Point], i = End - Point; --i >= 0; )
    580 	q[len + i] = q[i];
    581     COPYFROMTO(&Line[Point], p, len);
    582     End += len;
    583     Line[End] = '\0';
    584     TTYstring(&Line[Point]);
    585     Point += len;
    586 
    587     return Point == End ? CSstay : CSmove;
    588 }
    589 
    590 STATIC STATE
    591 redisplay()
    592 {
    593     TTYputs((STRING)NEWLINE);
    594     TTYputs((STRING)Prompt);
    595     TTYstring(Line);
    596     return CSmove;
    597 }
    598 
    599 STATIC STATE
    600 redisplay_no_nl()
    601 {
    602     TTYbol();
    603     TTYputs((STRING)Prompt);
    604     TTYstring(Line);
    605     return CSmove;
    606 }
    607 
    608 STATIC STATE
    609 toggle_meta_mode()
    610 {
    611     rl_meta_chars = !rl_meta_chars;
    612     return redisplay();
    613 }
    614 
    615 
    616 STATIC CHAR *
    617 next_hist()
    618 {
    619     return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
    620 }
    621 
    622 STATIC CHAR *
    623 prev_hist()
    624 {
    625     return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
    626 }
    627 
    628 STATIC STATE
    629 do_insert_hist(CHAR *p)
    630 {
    631     if (p == NULL)
    632 	return ring_bell();
    633     Point = 0;
    634     reposition();
    635     ceol();
    636     End = 0;
    637     return insert_string(p);
    638 }
    639 
    640 STATIC STATE
    641 do_hist(CHAR *(*move)() )
    642 {
    643     CHAR	*p;
    644     int		i;
    645 
    646     i = 0;
    647     do {
    648 	if ((p = (*move)()) == NULL)
    649 	    return ring_bell();
    650     } while (++i < Repeat);
    651     return do_insert_hist(p);
    652 }
    653 
    654 STATIC STATE
    655 h_next()
    656 {
    657     return do_hist(next_hist);
    658 }
    659 
    660 STATIC STATE
    661 h_prev()
    662 {
    663     return do_hist(prev_hist);
    664 }
    665 
    666 STATIC STATE
    667 h_first()
    668 {
    669     return do_insert_hist(H.Lines[H.Pos = 0]);
    670 }
    671 
    672 STATIC STATE
    673 h_last()
    674 {
    675     return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
    676 }
    677 
    678 #if	defined(SEARCH_HISTORY)
    679 /*
    680 **  Return zero if pat appears as a substring in text.
    681 */
    682 STATIC int
    683 _substrcmp(char *text, char *pat, int len)
    684 {
    685     CHAR	c;
    686 
    687     if ((c = *pat) == '\0')
    688 	return *text == '\0';
    689     for ( ; *text; text++)
    690 	if (*text == c && strncmp(text, pat, len) == 0)
    691 	    return 0;
    692     return 1;
    693 }
    694 #endif
    695 
    696 STATIC STATE
    697 do_prefix_search(CHAR *(*move)() )
    698 {
    699     int		old_point;
    700 
    701     old_point = Point;
    702 
    703     for ( ; (*move)() != NULL; )
    704 	if (strncmp((char *)H.Lines[H.Pos], (char *)Line, Point) == 0) {
    705 	    (void) do_insert_hist(H.Lines[H.Pos]);
    706 	    Point = old_point;
    707 	    return CSmove;
    708 	}
    709 
    710     return ring_bell();
    711 }
    712 
    713 STATIC STATE
    714 h_search_prev()
    715 {
    716     return do_prefix_search(prev_hist);
    717 }
    718 
    719 STATIC STATE
    720 h_search_next()
    721 {
    722     return do_prefix_search(next_hist);
    723 }
    724 
    725 #if	defined(SEARCH_HISTORY)
    726 STATIC CHAR *
    727 search_hist(CHAR *search, CHAR *(*move)() )
    728 {
    729     static CHAR	*old_search;
    730     int		len;
    731     int		pos;
    732     int		(*match)();
    733     char	*pat;
    734 
    735     /* Save or get remembered search pattern. */
    736     if (search && *search) {
    737 	if (old_search)
    738 	    DISPOSE(old_search);
    739 	old_search = (CHAR *)sal_strdup((char *)search);
    740     }
    741     else {
    742 	if (old_search == NULL || *old_search == '\0')
    743 	    return NULL;
    744 	search = old_search;
    745     }
    746 
    747     /* Set up pattern-finder. */
    748     if (*search == '^') {
    749 	match = strncmp;
    750 	pat = (char *)(search + 1);
    751     }
    752     else {
    753 	match = _substrcmp;
    754 	pat = (char *)search;
    755     }
    756     len = strlen(pat);
    757 
    758     for (pos = H.Pos; (*move)() != NULL; )
    759 	if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
    760 	    return H.Lines[H.Pos];
    761     H.Pos = pos;
    762     return NULL;
    763 }
    764 #endif
    765 
    766 #if	defined(SEARCH_HISTORY)
    767 STATIC STATE
    768 h_search()
    769 {
    770     static int	Searching;
    771     CONST char	*old_prompt;
    772     CHAR	*(*move)();
    773     CHAR	*p;
    774 
    775     if (Searching)
    776 	return ring_bell();
    777     Searching = 1;
    778 
    779     clear_line();
    780     old_prompt = Prompt;
    781     Prompt = "Search: ";
    782     TTYputs((STRING)Prompt);
    783     move = Repeat == NO_ARG ? prev_hist : next_hist;
    784     CursorPos = strlen(Prompt);
    785     p = editinput();
    786     Searching = 0;
    787     if (p == NULL && Signal > 0) {
    788 	Signal = 0;
    789 	clear_line();
    790 	Prompt = old_prompt;
    791 	return redisplay_no_nl();
    792     }
    793     p = search_hist(p, move);
    794     clear_line();
    795     Prompt = old_prompt;
    796     if (p == NULL) {
    797 	(void)ring_bell();
    798 	return redisplay_no_nl();
    799     }
    800     return do_insert_hist(p);
    801 }
    802 #endif
    803 
    804 STATIC STATE
    805 fd_char()
    806 {
    807     int		i;
    808 
    809     i = 0;
    810     do {
    811 	if (Point >= End)
    812 	    break;
    813 	right(CSmove);
    814     } while (++i < Repeat);
    815     return CSstay;
    816 }
    817 
    818 STATIC void
    819 save_yank(int begin,int i)
    820 {
    821     if (Yanked) {
    822 	DISPOSE(Yanked);
    823 	Yanked = NULL;
    824     }
    825 
    826     if (i < 1)
    827 	return;
    828 
    829     if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
    830 	COPYFROMTO(Yanked, &Line[begin], i);
    831 	Yanked[i] = '\0';
    832     }
    833 }
    834 
    835 STATIC STATE
    836 delete_string(int count)
    837 {
    838     int		i;
    839     CHAR	*p;
    840 
    841     if (count <= 0 || End == Point)
    842 	return ring_bell();
    843 
    844     if (count == 1 && Point == End - 1) {
    845 	/* Optimize common case of delete at end of line. */
    846 	End--;
    847 	p = &Line[Point];
    848 	i = 1;
    849 	TTYput(' ');
    850 	if (*p == TAB) {
    851 	    /* XXX */
    852 	}
    853 	else if (ISCTL(*p)) {
    854 	    i = 2;
    855 	    TTYput(' ');
    856 	}
    857 	else if (rl_meta_chars && ISMETA(*p)) {
    858 	    i = 3;
    859 	    TTYput(' ');
    860 	    TTYput(' ');
    861 	}
    862 	TTYbackn(i);
    863 	*p = '\0';
    864 	return CSmove;
    865     }
    866     if (Point + count > End && (count = End - Point) <= 0)
    867 	return CSstay;
    868 
    869     if (count > 1)
    870 	save_yank(Point, count);
    871 
    872     ceol();
    873     for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
    874 	p[0] = p[count];
    875     End -= count;
    876     TTYstring(&Line[Point]);
    877     return CSmove;
    878 }
    879 
    880 STATIC STATE
    881 bk_char()
    882 {
    883     int		i;
    884 
    885     i = 0;
    886     do {
    887 	if (Point == 0)
    888 	    break;
    889 	left(CSmove);
    890     } while (++i < Repeat);
    891 
    892     return CSstay;
    893 }
    894 
    895 STATIC STATE
    896 bk_del_char()
    897 {
    898     int		i;
    899 
    900     i = 0;
    901     do {
    902 	if (Point == 0)
    903 	    break;
    904 	left(CSmove);
    905     } while (++i < Repeat);
    906 
    907     return delete_string(i);
    908 }
    909 
    910 STATIC STATE
    911 kill_line()
    912 {
    913     int		i;
    914 
    915     if (Repeat != NO_ARG) {
    916 	if (Repeat < Point) {
    917 	    i = Point;
    918 	    Point = Repeat;
    919 	    reposition();
    920 	    (void)delete_string(i - Point);
    921 	}
    922 	else if (Repeat > Point) {
    923 	    right(CSmove);
    924 	    (void)delete_string(Repeat - Point - 1);
    925 	}
    926 	return CSmove;
    927     }
    928 
    929     save_yank(Point, End - Point);
    930     ceol();
    931     Line[Point] = '\0';
    932     End = Point;
    933     return CSstay;
    934 }
    935 
    936 STATIC STATE
    937 insert_char(int c)
    938 {
    939     STATE	s;
    940     CHAR	buff[2];
    941     CHAR	*p;
    942     CHAR	*q;
    943     int		i;
    944 
    945     if (Repeat == NO_ARG || Repeat < 2) {
    946 	buff[0] = c;
    947 	buff[1] = '\0';
    948 	return insert_string(buff);
    949     }
    950 
    951     if ((p = NEW(CHAR, Repeat + 1)) == NULL)
    952 	return CSstay;
    953     for (i = Repeat, q = p; --i >= 0; )
    954 	*q++ = c;
    955     *q = '\0';
    956     Repeat = 0;
    957     s = insert_string(p);
    958     DISPOSE(p);
    959     return s;
    960 }
    961 
    962 static STATE
    963 meta()
    964 {
    965     int	c;
    966     KEYMAP		*kp;
    967 
    968     if ((c = TTYget()) == EOF)
    969 	return CSeof;
    970 #if	defined(ANSI_ARROWS)
    971     /* Also include VT-100 arrows. */
    972     if (c == '[' || c == 'O')
    973 	switch ((int)(c = TTYget())) {
    974 	default:	return ring_bell();
    975 	case EOF:	return CSeof;
    976 	case 'A':	return h_prev();
    977 	case 'B':	return h_next();
    978 	case 'C':	return fd_char();
    979 	case 'D':	return bk_char();
    980 	}
    981 #endif	/* defined(ANSI_ARROWS) */
    982 
    983     if (isdigit(c)) {
    984 	for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
    985 	    Repeat = Repeat * 10 + c - '0';
    986 	Pushed = 1;
    987 	PushBack = c;
    988 	return CSstay;
    989     }
    990 
    991     if (isupper(c))
    992 	return do_macro((unsigned int)c);
    993     for (OldPoint = Point, kp = MetaMap; kp < &MetaMap[METAMAPSIZE]; kp++)
    994 	if (kp->Key == c && kp->Active)
    995 	    return (*kp->Function)();
    996 
    997     return ring_bell();
    998 }
    999 
   1000 STATIC STATE
   1001 emacs(unsigned int c)
   1002 {
   1003     STATE		s;
   1004     KEYMAP		*kp;
   1005 
   1006 #if	0
   1007     /* This test makes it impossible to enter eight-bit characters when
   1008      * meta-char mode is enabled. */
   1009     if (rl_meta_chars && ISMETA(c)) {
   1010 	Pushed = 1;
   1011 	PushBack = UNMETA(c);
   1012 	return meta();
   1013     }
   1014 #endif	/* 0 */
   1015     for (kp = Map; kp < &Map[MAPSIZE]; kp++)
   1016 	if (kp->Key == c && kp->Active)
   1017 	    break;
   1018     s = kp < &Map[MAPSIZE] ? (*kp->Function)() : insert_char((int)c);
   1019     if (!Pushed)
   1020 	
   1021 	Repeat = NO_ARG;
   1022     return s;
   1023 }
   1024 
   1025 STATIC STATE
   1026 TTYspecial(int c)
   1027 {
   1028   if (rl_meta_chars && ISMETA(c)) {
   1029       return CSdispatch;
   1030   }
   1031 
   1032   if (c == rl_erase || c == DEL) {
   1033 	return bk_del_char();
   1034   }
   1035   if (c == rl_kill) {
   1036 	if (Point != 0) {
   1037       Point = 0;
   1038 	  reposition();
   1039 	}
   1040 	Repeat = NO_ARG;
   1041 	return kill_line();
   1042   }
   1043   if (c == rl_eof && Point == 0 && End == 0) {
   1044 	return CSeof;
   1045   }
   1046 
   1047   if (c == rl_intr) {
   1048 	Signal = SIGINT;
   1049 	return CSsignal;
   1050   }
   1051   if (c == rl_quit) {
   1052 	Signal = SIGQUIT;
   1053 	return CSsignal;
   1054   }
   1055 #if	defined(DO_SIGTSTP)
   1056   if (c == rl_susp) {
   1057 	Signal = SIGTSTP;
   1058 	return CSsignal;
   1059   }
   1060 #endif	/* defined(DO_SIGTSTP) */
   1061 
   1062   return CSdispatch;
   1063 }
   1064 
   1065 STATIC CHAR *
   1066 editinput()
   1067 {
   1068     int	c;
   1069 #if defined(INCLUDE_AUTOCOMPLETE)
   1070     extern int diag_user_var_unit;
   1071 #endif
   1072 
   1073     Repeat = NO_ARG;
   1074     OldPoint = Point = Mark = End = 0;
   1075     Line[0] = '\0';
   1076     /* This is a formality to keep consistent with the asynchronous char
   1077        process. 
   1078        Need to track if the previous character was EOL so that asynchronous
   1079        support knows when to apply the three lines above.
   1080     */
   1081 
   1082     Signal = -1;
   1083     while ((c = TTYget()) != EOF) {
   1084 #if defined(INCLUDE_AUTOCOMPLETE)
   1085       if (c == TAB) {
   1086           Input = (STRING)autocomplete_print(diag_user_var_unit, (char*)Line, (char*)Prompt);
   1087           TTYflush();
   1088           continue;
   1089       }
   1090 #endif
   1091       switch (TTYspecial(c)) {
   1092 	  case CSdone:
   1093         return Line;
   1094 	  case CSeof:
   1095 	    return NULL;
   1096 	  case CSsignal:
   1097 	    return (CHAR *)"";
   1098 	  case CSmove:
   1099 	    reposition();
   1100 	    break;
   1101 	  case CSdispatch:
   1102 	    switch (emacs(c)) {
   1103 	    case CSdone:
   1104           return Line;
   1105 	    case CSeof:
   1106           return NULL;
   1107 	    case CSsignal:
   1108           return (CHAR *)"";
   1109 	    case CSmove:
   1110           reposition();
   1111           break;
   1112 	    case CSdispatch:
   1113         case CSstay:
   1114           break;
   1115 	    }
   1116 	    break;
   1117       case CSstay:
   1118 	    break;
   1119       }
   1120     }
   1121     return NULL;
   1122 }
   1123 
   1124 STATIC void
   1125 hist_add(CHAR *p)
   1126 {
   1127     int		i;
   1128 
   1129     if ((p = (CHAR *)sal_strdup((char *)p)) == NULL) {
   1130       return;
   1131     }
   1132     if (H.Size < HIST_SIZE)
   1133       H.Lines[H.Size++] = p;
   1134     else {
   1135       DISPOSE(H.Lines[0]);
   1136       for (i = 0; i < HIST_SIZE - 1; i++)
   1137 	    H.Lines[i] = H.Lines[i + 1];
   1138       H.Lines[i] = p;
   1139     }
   1140     H.Pos = H.Size - 1;
   1141 }
   1142 
   1143 STATIC char *
   1144 read_redirected()
   1145 {
   1146     int		size;
   1147     char	*p;
   1148     char	*line;
   1149     char	*end;
   1150 
   1151     size = MEM_INC;
   1152     line = NEW(char, size);
   1153     end = line + size;
   1154 
   1155     for (p = line; ; p++) {
   1156 	if (p == end) {
   1157 	    p = NEW(char, size + MEM_INC);
   1158 	    memcpy(p, line, size);
   1159 	    DISPOSE(line);
   1160 	    line = p;
   1161 	    p = line + size;
   1162 	    size += MEM_INC;
   1163 	    end = line + size;
   1164 	}
   1165 	if (sal_console_read(p, 1) <= 0) {
   1166 	    /* Ignore "incomplete" lines at EOF, just like we do for a tty. */
   1167 	    DISPOSE(line);
   1168 	    return NULL;
   1169 	}
   1170 	
   1171 	if (*p == '\n')
   1172 	    break;
   1173     }
   1174     *p = '\0';
   1175     return line;
   1176 }
   1177 
   1178 /*
   1179 **  For compatibility with FSF readline.
   1180 */
   1181 /* ARGSUSED0 */
   1182 void
   1183 rl_reset_terminal(char *p)
   1184 {
   1185 }
   1186 
   1187 int
   1188 rl_insert(int count,int c)
   1189 {
   1190     if (count > 0) {
   1191 	Repeat = count;
   1192 	(void)insert_char(c);
   1193 	(void)redisplay_no_nl();
   1194     }
   1195     return 0;
   1196 }
   1197 
   1198 int (*rl_event_hook)();
   1199 
   1200 int
   1201 rl_key_action(int c, char flag)
   1202 {
   1203     KEYMAP	*kp;
   1204     int		size;
   1205 
   1206     if (ISMETA(c)) {
   1207 	kp = MetaMap;
   1208 	size = METAMAPSIZE;
   1209     }
   1210     else {
   1211 	kp = Map;
   1212 	size = MAPSIZE;
   1213     }
   1214     for ( ; --size >= 0; kp++)
   1215 	if (kp->Key == c) {
   1216 	    kp->Active = c ? 1 : 0;
   1217 	    return 1;
   1218 	}
   1219     return -1;
   1220 }
   1221 
   1222 int
   1223 readchar(CONST char *prompt)
   1224 {
   1225     char c;
   1226 #ifdef UNIX
   1227     int gdb = 0;
   1228 
   1229     if (getenv("GDB") != NULL && getenv("DCON") == NULL) {
   1230 	gdb = 1;
   1231     }
   1232 #endif
   1233 
   1234     if (Screen == NULL) {
   1235 	ScreenSize = SCREEN_INC;
   1236 	Screen = NEW(char, ScreenSize);
   1237     }
   1238 
   1239     if (sal_console_info_get(NULL) < 0) {
   1240 	TTYflush();
   1241 	return EOF;
   1242     }
   1243 
   1244 #ifdef UNIX
   1245     if (gdb) {
   1246 	char *t;
   1247         char p;
   1248 	printf("%s", prompt);
   1249 	fflush(stdout);
   1250 	t = read_redirected();
   1251         if(t == NULL) {
   1252            return EOF;
   1253         } else {
   1254            p = *(t+0);
   1255            sal_free(t);
   1256            return p;
   1257         }  
   1258     }
   1259 #endif
   1260 
   1261     TTYinfo();
   1262     rl_ttyset(0);
   1263     Prompt = prompt ? prompt : (char *)NIL;
   1264     TTYputs((STRING)Prompt);
   1265     c = TTYget();
   1266     if (c == rl_intr)
   1267 	Signal = SIGINT;
   1268     else if (c == rl_quit)
   1269 	Signal = SIGQUIT;
   1270 #if	defined(DO_SIGTSTP)
   1271     else if (c == rl_susp)
   1272 	Signal = SIGTSTP;
   1273 #endif	/* defined(DO_SIGTSTP) */
   1274     rl_ttyset(1);
   1275 
   1276 #if     defined(USE_POSIX_SIGNALS)
   1277     if (Signal > 0) {
   1278         int s = Signal;
   1279 	Signal = 0;
   1280 	(void)kill(getpid(), s);
   1281     }
   1282 #endif
   1283     return c;
   1284 }    
   1285 
   1286 char *
   1287 readline(CONST char *prompt)
   1288 {
   1289     CHAR	*line;
   1290 #ifdef UNIX
   1291     int		gdb = 0;
   1292 
   1293     if (getenv("GDB") != NULL && getenv("DCON") == NULL) {
   1294 	gdb = 1;
   1295     }
   1296 #endif
   1297 
   1298     if (Screen == NULL) {
   1299 	ScreenSize = SCREEN_INC;
   1300 	Screen = NEW(char, ScreenSize);
   1301     }
   1302 
   1303     /*
   1304      * If input is not a TTY, just do a read.
   1305      * Also just do a read if TTY data is pending.
   1306      */
   1307     if (sal_console_info_get(NULL) < 0) {
   1308       TTYflush();
   1309       return read_redirected();
   1310     }
   1311 
   1312 #ifdef UNIX
   1313     if (gdb) {
   1314 	printf("%s", prompt);
   1315 	fflush(stdout);
   1316 	return read_redirected();
   1317     }
   1318 #endif
   1319 
   1320     if (Line == NULL) {
   1321       Length = MEM_INC;
   1322       if ((Line = NEW(CHAR, Length)) == NULL) {
   1323 	    return NULL;
   1324       }
   1325     }
   1326 
   1327     TTYinfo();
   1328     rl_ttyset(0);
   1329     hist_add(NIL);
   1330     Prompt = prompt ? prompt : (char *)NIL;
   1331     TTYputs((STRING)Prompt);
   1332     CursorPos = strlen(Prompt);
   1333     if ((line = editinput()) != NULL) {
   1334       line = (CHAR *)sal_strdup((char *)line);
   1335       TTYputs((STRING)NEWLINE);
   1336       TTYflush();
   1337     }
   1338     rl_ttyset(1);
   1339 
   1340     DISPOSE(H.Lines[--H.Size]);
   1341 #if     defined(USE_POSIX_SIGNALS)
   1342     if (Signal > 0) {
   1343       int s = Signal;
   1344       errno = EINTR;
   1345       Signal = 0;
   1346       (void)kill(getpid(), s);
   1347       if (line) {
   1348 	    DISPOSE(line);
   1349 	    line = NULL;
   1350       }
   1351     } else {
   1352         errno = 0;
   1353     }
   1354 #endif
   1355     return (char *)line;
   1356 }
   1357 
   1358 void
   1359 add_history(char *p)
   1360 {
   1361   if (p == NULL || *p == '\0') {
   1362       return;
   1363   }
   1364 
   1365 #if	defined(UNIQUE_HISTORY)
   1366   if (H.Size && strcmp(p, (char *)H.Lines[H.Size - 1]) == 0) {
   1367 	return;
   1368   }
   1369 #endif	/* defined(UNIQUE_HISTORY) */
   1370   hist_add((CHAR *)p);
   1371 }
   1372 
   1373 void
   1374 list_history(int count)
   1375 {
   1376     int h;
   1377     if ((h = H.Size - count) < 0)
   1378 	h = 0;
   1379     while (h < H.Size) {
   1380 	TTYputs((STRING)"   ");
   1381 	TTYputs((STRING)H.Lines[h++]);
   1382 	TTYputs((STRING)NEWLINE);
   1383 	TTYflush();
   1384     }
   1385 }
   1386 
   1387 
   1388 
   1389 STATIC STATE
   1390 beg_line()
   1391 {
   1392     if (Point) {
   1393 	Point = 0;
   1394 	return CSmove;
   1395     }
   1396     return CSstay;
   1397 }
   1398 
   1399 STATIC STATE
   1400 del_char()
   1401 {
   1402     return delete_string(Repeat == NO_ARG ? 1 : Repeat);
   1403 }
   1404 
   1405 STATIC STATE
   1406 end_line()
   1407 {
   1408     if (Point != End) {
   1409 	Point = End;
   1410 	return CSmove;
   1411     }
   1412     return CSstay;
   1413 }
   1414 
   1415 /*
   1416 **  Return allocated copy of word under cursor, moving cursor after the
   1417 **  word.
   1418 */
   1419 STATIC CHAR *
   1420 find_word()
   1421 {
   1422     static char	SEPS[] = "\"#;&|^$=`'{}()<>\n\t ";
   1423     CHAR	*p;
   1424     CHAR	*new;
   1425     SIZE_T	len;
   1426 
   1427     /* Move forward to end of word. */
   1428     p = &Line[Point];
   1429     for ( ; Point < End && strchr(SEPS, (char)*p) == NULL; Point++, p++)
   1430 	right(CSstay);
   1431 
   1432     /* Back up to beginning of word. */
   1433     for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
   1434 	continue;
   1435     len = Point - (p - Line) + 1;
   1436     if ((new = NEW(CHAR, len)) == NULL)
   1437 	return NULL;
   1438     COPYFROMTO(new, p, len);
   1439     new[len - 1] = '\0';
   1440     return new;
   1441 }
   1442 
   1443 STATIC STATE
   1444 c_complete()
   1445 {
   1446     CHAR	*p;
   1447     CHAR	*word;
   1448     int		unique;
   1449 
   1450     word = find_word();
   1451     p = (CHAR *)(*rl_complete)((char *)word, &unique);
   1452     if (word)
   1453 	DISPOSE(word);
   1454     if (p) {
   1455 	if (*p)
   1456 	    (void)insert_string(p);
   1457 	if (!unique)
   1458 	    (void)ring_bell();
   1459 	DISPOSE(p);
   1460 	return redisplay_no_nl();
   1461     }
   1462     return ring_bell();
   1463 }
   1464 
   1465 void rl_input_state(rl_input_state_t *state)
   1466 {
   1467     state->line = Line;
   1468     state->point = Point;
   1469 }
   1470 
   1471 STATIC STATE
   1472 c_possible()
   1473 {
   1474     CHAR	**av, ***pav = &av;
   1475     CHAR	*word;
   1476     int		ac;
   1477 
   1478     word = find_word();
   1479     ac = (*rl_list_possib)((char *)word, (char ***)pav);
   1480     if (word)
   1481 	DISPOSE(word);
   1482     if (ac) {
   1483 	columns(ac, av);
   1484 	while (--ac >= 0)
   1485 	    DISPOSE(av[ac]);
   1486 	DISPOSE(av);
   1487 	return redisplay_no_nl();
   1488     }
   1489     return ring_bell();
   1490 }
   1491 
   1492 STATIC STATE
   1493 accept_line()
   1494 {
   1495     Line[End] = '\0';
   1496     return CSdone;
   1497 }
   1498 
   1499 STATIC STATE
   1500 transpose()
   1501 {
   1502     CHAR	c;
   1503 
   1504     if (Point) {
   1505 	if (Point == End)
   1506 	    left(CSmove);
   1507 	c = Line[Point - 1];
   1508 	left(CSstay);
   1509 	Line[Point - 1] = Line[Point];
   1510 	TTYshow(Line[Point - 1]);
   1511 	Line[Point++] = c;
   1512 	TTYshow(c);
   1513     }
   1514     return CSstay;
   1515 }
   1516 
   1517 STATIC STATE
   1518 quote()
   1519 {
   1520     int	c;
   1521 
   1522     return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
   1523 }
   1524 
   1525 STATIC STATE
   1526 wipe()
   1527 {
   1528     int		i;
   1529 
   1530     if (Mark > End)
   1531 	return ring_bell();
   1532 
   1533     if (Point > Mark) {
   1534 	i = Point;
   1535 	Point = Mark;
   1536 	Mark = i;
   1537 	reposition();
   1538     }
   1539 
   1540     return delete_string(Mark - Point);
   1541 }
   1542 
   1543 STATIC STATE
   1544 mk_set()
   1545 {
   1546     Mark = Point;
   1547     return CSstay;
   1548 }
   1549 
   1550 STATIC STATE
   1551 exchange()
   1552 {
   1553     int	c;
   1554 
   1555     if ((c = TTYget()) != CTL('X'))
   1556 	return c == EOF ? CSeof : ring_bell();
   1557 
   1558     if ((c = Mark) <= End) {
   1559 	Mark = Point;
   1560 	Point = c;
   1561 	return CSmove;
   1562     }
   1563     return CSstay;
   1564 }
   1565 
   1566 STATIC STATE
   1567 yank()
   1568 {
   1569     if (Yanked && *Yanked)
   1570 	return insert_string(Yanked);
   1571     return CSstay;
   1572 }
   1573 
   1574 STATIC STATE
   1575 copy_region()
   1576 {
   1577     if (Mark > End)
   1578 	return ring_bell();
   1579 
   1580     if (Point > Mark)
   1581 	save_yank(Mark, Point - Mark);
   1582     else
   1583 	save_yank(Point, Mark - Point);
   1584 
   1585     return CSstay;
   1586 }
   1587 
   1588 STATIC STATE
   1589 move_to_char()
   1590 {
   1591     int	c;
   1592     int			i;
   1593     CHAR		*p;
   1594 
   1595     if ((c = TTYget()) == EOF)
   1596 	return CSeof;
   1597     for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
   1598 	if (*p == c) {
   1599 	    Point = i;
   1600 	    return CSmove;
   1601 	}
   1602     return CSstay;
   1603 }
   1604 
   1605 STATIC STATE
   1606 fd_word()
   1607 {
   1608     return do_forward(CSmove);
   1609 }
   1610 
   1611 STATIC STATE
   1612 fd_kill_word()
   1613 {
   1614     int		i;
   1615 
   1616     (void)do_forward(CSstay);
   1617     if (OldPoint != Point) {
   1618 	i = Point - OldPoint;
   1619 	Point = OldPoint;
   1620 	return delete_string(i);
   1621     }
   1622     return CSstay;
   1623 }
   1624 
   1625 STATIC STATE
   1626 bk_word()
   1627 {
   1628     int		i;
   1629     CHAR	*p;
   1630 
   1631     i = 0;
   1632     do {
   1633 	for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
   1634 	    left(CSmove);
   1635 
   1636 	for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
   1637 	    left(CSmove);
   1638 
   1639 	if (Point == 0)
   1640 	    break;
   1641     } while (++i < Repeat);
   1642 
   1643     return CSstay;
   1644 }
   1645 
   1646 STATIC STATE
   1647 bk_kill_word()
   1648 {
   1649     (void)bk_word();
   1650     if (OldPoint != Point)
   1651 	return delete_string(OldPoint - Point);
   1652     return CSstay;
   1653 }
   1654 
   1655 STATIC int
   1656 argify(CHAR *line, CHAR ***avp)
   1657 {
   1658     CHAR	*c;
   1659     CHAR	**p;
   1660     CHAR	**new;
   1661     int		ac;
   1662     int		i;
   1663 
   1664     i = MEM_INC;
   1665     if ((*avp = p = NEW(CHAR*, i))== NULL)
   1666 	 return 0;
   1667 
   1668     for (c = line; isspace(*c); c++)
   1669 	continue;
   1670     if (*c == '\n' || *c == '\0')
   1671 	return 0;
   1672 
   1673     for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
   1674 	if (isspace(*c)) {
   1675 	    *c++ = '\0';
   1676 	    if (*c && *c != '\n') {
   1677 		if (ac + 1 == i) {
   1678 		    new = NEW(CHAR*, i + MEM_INC);
   1679 		    if (new == NULL) {
   1680 			p[ac] = NULL;
   1681 			return ac;
   1682 		    }
   1683 		    COPYFROMTO(new, p, i * sizeof(CHAR*));
   1684 		    i += MEM_INC;
   1685 		    DISPOSE(p);
   1686 		    *avp = p = new;
   1687 		}
   1688 		p[ac++] = c;
   1689 	    }
   1690 	}
   1691 	else
   1692 	    c++;
   1693     }
   1694     *c = '\0';
   1695     p[ac] = NULL;
   1696     return ac;
   1697 }
   1698 
   1699 STATIC STATE
   1700 last_argument()
   1701 {
   1702     CHAR	**av;
   1703     CHAR	*p;
   1704     STATE	s;
   1705     int		ac;
   1706 
   1707     if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
   1708 	return ring_bell();
   1709 
   1710     if ((p = (CHAR *)sal_strdup((char *)p)) == NULL)
   1711 	return CSstay;
   1712     ac = argify(p, &av);
   1713 
   1714     if (Repeat != NO_ARG)
   1715 	s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
   1716     else
   1717 	s = ac ? insert_string(av[ac - 1]) : CSstay;
   1718 
   1719     if (av)
   1720 	DISPOSE(av);
   1721     DISPOSE(p);
   1722     return s;
   1723 }
   1724 
   1725 STATIC KEYMAP	Map[MAPSIZE] = {
   1726     {	CTL('@'),	1,	mk_set		},
   1727     {	CTL('A'),	1,	beg_line	},
   1728     {	CTL('B'),	1,	bk_char		},
   1729     {	CTL('D'),	1,	del_char	},
   1730     {	CTL('E'),	1,	end_line	},
   1731     {	CTL('F'),	1,	fd_char		},
   1732     {	CTL('G'),	1,	ring_bell	},
   1733     {	CTL('H'),	1,	bk_del_char	},
   1734     {	CTL('I'),	1,	c_complete	},
   1735     {	CTL('J'),	1,	accept_line	},
   1736     {	CTL('K'),	1,	kill_line	},
   1737     {	CTL('L'),	1,	redisplay	},
   1738     {	CTL('M'),	1,	accept_line	},
   1739     {	CTL('N'),	1,	h_next		},
   1740     {	CTL('O'),	1,	ring_bell	},
   1741     {	CTL('P'),	1,	h_prev		},
   1742     {	CTL('Q'),	1,	ring_bell	},
   1743 #if	defined(SEARCH_HISTORY)
   1744     {	CTL('R'),	1,	h_search	},
   1745 #endif
   1746     {	CTL('S'),	1,	ring_bell	},
   1747     {	CTL('T'),	1,	transpose	},
   1748     {	CTL('U'),	1,	ring_bell	},
   1749     {	CTL('V'),	1,	quote		},
   1750     {	CTL('W'),	1,	wipe		},
   1751     {	CTL('X'),	1,	exchange	},
   1752     {	CTL('Y'),	1,	yank		},
   1753     {	CTL('Z'),	1,	ring_bell	},
   1754     {	CTL('['),	1,	meta		},
   1755     {	CTL(']'),	1,	move_to_char	},
   1756     {	CTL('^'),	1,	ring_bell	},
   1757     {	CTL('_'),	1,	ring_bell	},
   1758 };
   1759 
   1760 STATIC KEYMAP	MetaMap[METAMAPSIZE]= {
   1761     {	CTL('H'),	1,	bk_kill_word	},
   1762     {	CTL('['),	1,	c_possible	},
   1763     {	DEL,		1,	bk_kill_word	},
   1764     {	' ',		1,	mk_set		},
   1765     {	'.',		1,	last_argument	},
   1766     {	'<',		1,	h_first		},
   1767     {	'>',		1,	h_last		},
   1768     {	'?',		1,	c_possible	},
   1769     {	'b',		1,	bk_word		},
   1770     {	'd',		1,	fd_kill_word	},
   1771     {	'f',		1,	fd_word		},
   1772     {	'l',		1,	case_down_word	},
   1773     {	'm',		1,	toggle_meta_mode},
   1774     {	'n',		1,	h_search_next	},
   1775     {	'p',		1,	h_search_prev	},
   1776     {	'u',		1,	case_up_word	},
   1777     {	'y',		1,	yank		},
   1778     {	'w',		1,	copy_region	},
   1779 };
   1780 
   1781 /* Asynchronous event support */
   1782 void
   1783 _rl_editline_input_start(void)
   1784 {
   1785 
   1786     Repeat = NO_ARG;
   1787     OldPoint = Point = Mark = End = 0;
   1788     Line[0] = '\0';
   1789 
   1790     Signal = -1;
   1791 }
   1792 
   1793 /*
   1794  * Description:
   1795  *  process individual characters and determines if history should be
   1796  *  be presented to the user.
   1797  */
   1798 int
   1799 _rl_editline_input_process(int c, CHAR **linep)
   1800 {
   1801     int eol = FALSE;
   1802 
   1803     switch (TTYspecial(c)) {
   1804     case CSdone:
   1805         *linep = Line;
   1806         eol = TRUE;
   1807         break;
   1808     case CSeof:
   1809         if (gCALLBACK_EOF_HANDLER) {
   1810           gCALLBACK_EOF_HANDLER(gCALLBACK_EOF_HANDLER_CTX);
   1811         }
   1812         break;
   1813     case CSsignal:
   1814         *linep = (CHAR *)"";
   1815         eol = TRUE;
   1816         break;
   1817     case CSmove:
   1818         reposition();
   1819         break;
   1820     case CSdispatch:
   1821         switch (emacs(c)) {
   1822         case CSdone:
   1823           *linep = Line;
   1824           eol = TRUE;
   1825           break;
   1826         case CSeof:
   1827           if (gCALLBACK_EOF_HANDLER) {
   1828             gCALLBACK_EOF_HANDLER(gCALLBACK_EOF_HANDLER_CTX);
   1829           }
   1830           *linep = NULL;
   1831           eol = TRUE;
   1832           break;
   1833         case CSsignal:
   1834             *linep =  (CHAR *)"";
   1835             eol = TRUE;
   1836             break;
   1837         case CSmove:
   1838             reposition();
   1839             break;
   1840         case CSdispatch:
   1841         case CSstay:
   1842             break;
   1843         }
   1844         break;
   1845     case CSstay:
   1846         break;
   1847     }
   1848 
   1849     return eol;
   1850 }
   1851 
   1852 /*
   1853  Set new prompt.
   1854  */
   1855 void rl_prompt_set(CONST char *prompt)
   1856 {
   1857   int changed = 0;
   1858   if (!Prompt || !prompt) {
   1859     changed = 1;
   1860   } else if (Prompt && prompt && sal_strcmp(Prompt, prompt)) {
   1861     changed = 1;
   1862   }
   1863 
   1864   Prompt = prompt ? prompt : (char *)NIL;
   1865   if (changed || (CursorPos == 0)) {
   1866     /* CursorPos == 0 means that nothing has been displayed as a prompt.*/
   1867     if (CursorPos != 0) {
   1868       /* We're changing prompts in the middle of a line. 
   1869          put a new line to continue. */
   1870       TTYputs((STRING)NEWLINE);
   1871     }
   1872     TTYputs((STRING)Prompt);
   1873     TTYflush();
   1874     CursorPos = strlen((char *)Prompt);
   1875   }
   1876 }
   1877 
   1878 /*
   1879  * Initialize asynchronous editline support.
   1880  *
   1881  * Must call _rl_done when finished.
   1882  */
   1883 int
   1884 _rl_initialize(CONST char *prompt)
   1885 {
   1886     if (Screen == NULL) {
   1887       ScreenSize = SCREEN_INC;
   1888       if(!(Screen = NEW(char, ScreenSize))) {
   1889         return 0;
   1890       }
   1891     }
   1892 
   1893     if (Line == NULL) {
   1894       Length = MEM_INC;
   1895       if ((Line = NEW(CHAR, Length)) == NULL) {
   1896 	    return 0;
   1897       }
   1898     }
   1899 
   1900     TTYinfo();
   1901     rl_ttyset(0);
   1902     hist_add(NIL);
   1903     rl_prompt_set(prompt);
   1904 
   1905     return 1;
   1906 }
   1907 
   1908 void
   1909 _rl_done(void)
   1910 {
   1911     rl_ttyset(1);
   1912 
   1913 #if     defined(USE_POSIX_SIGNALS)
   1914     if (Signal > 0) {
   1915       int s = Signal;
   1916       errno = EINTR;
   1917       Signal = 0;
   1918       (void)kill(getpid(), s);
   1919     } else {
   1920       errno = 0;
   1921     }
   1922 #endif
   1923 }
   1924 
   1925 /**
   1926  Read a single character and post end-of-line handler.
   1927 
   1928  Notes:
   1929  see rl_callback_handler_install to register the end-of-line handler.
   1930  */
   1931 void rl_callback_read_char(CONST char *prompt)
   1932 {
   1933     /* Start with yes previous character processed was eol so that 
   1934        initialization will work. */
   1935     static int PrevEol = TRUE;
   1936 
   1937     /* read a char from input */
   1938     CHAR *line = NULL;
   1939     int   c    = 0;
   1940 
   1941     /* 
   1942        When we transition from synchronous to asynchronous H.Size == H.Pos
   1943        that is how we tell we are at a new line. We may need to change 
   1944        the prompt and cleanout output. 
   1945 
   1946        The PrevEol state is strictly internal because PrevEol is only
   1947        set to TRUE when eol handler is called a new line has been read.
   1948     */
   1949     if ((H.Size == H.Pos) || (PrevEol == TRUE)) {
   1950       _rl_initialize(prompt);
   1951       _rl_editline_input_start();
   1952       PrevEol = FALSE; /* Start of a process a new line. */
   1953     }
   1954     c = TTYget();
   1955     
   1956     /* if the line is complete, execute eol handler */
   1957     if (_rl_editline_input_process(c, &line)) {
   1958       PrevEol = TRUE;
   1959       /* Once a new line has been found pos to eol handler. 
   1960          We can call the handler anywhere before hist_add but after
   1961          NEWLINE is good for printf debugging from eol handler. */
   1962       TTYputs((STRING)NEWLINE);
   1963       TTYflush();
   1964       DISPOSE(H.Lines[--H.Size]);
   1965       gCALLBACK_EOL_HANDLER((char *)line, gCALLBACK_EOL_HANDLER_CTX);
   1966       /* We need to push the prompt after we're done with the end of line.
   1967          Because the end of line handler might process TCL script causing 
   1968          output which needs to occur before the prompt.
   1969 
   1970          Note that EOL_HANDLER might call into another shell changing the 
   1971          prompt. When returnning the following needs to occur verses just 
   1972          flushing Prompt.
   1973       */
   1974       rl_prompt_set(prompt);
   1975     } 
   1976 
   1977     /* flush is needed because at this point input was processed and 
   1978        pushed out. This could have been just the input character or
   1979        the history information processed i.e. up down arrows. */
   1980     TTYflush();
   1981 
   1982 #if     defined(USE_POSIX_SIGNALS)
   1983     if (Signal > 0) {
   1984       int s = Signal;
   1985       errno = EINTR;
   1986       Signal = 0;
   1987       (void)kill(getpid(), s);
   1988       if (line) {
   1989 	    DISPOSE(line);
   1990 	    line = NULL;
   1991       }
   1992     } else {
   1993       errno = 0;
   1994     }
   1995 #endif
   1996 }
   1997 
   1998 /**
   1999   Install an end-of-line handler.
   2000 
   2001   The end-of-line handler is only called when a complete line is parsed.
   2002   Users must call rl_callback_handler_remove when done.
   2003  */
   2004 void rl_callback_handler_install(CONST char *prompt, 
   2005                                  rl_vcpfunc_t eol_handler, void *eolCtx,
   2006                                  rf_vcpfunc_t eof_handler, void *eofCtx)
   2007 {
   2008   if (_rl_initialize(prompt)) {
   2009     /* save handler */
   2010     gCALLBACK_EOL_HANDLER     = eol_handler;
   2011     gCALLBACK_EOL_HANDLER_CTX = eolCtx;
   2012 
   2013     gCALLBACK_EOF_HANDLER     = eof_handler;
   2014     gCALLBACK_EOF_HANDLER_CTX = eofCtx;
   2015 
   2016     /* set terminal and init library */
   2017     _rl_editline_input_start();
   2018   }
   2019 }
   2020 
   2021 /**
   2022   Called when asynchronous editline is done.
   2023  */
   2024 void rl_callback_handler_remove(void **eolCtx, void **eofCtx)
   2025 {
   2026   if (eolCtx) {
   2027     (*eolCtx) = gCALLBACK_EOL_HANDLER_CTX;
   2028   }
   2029   if (eofCtx) {
   2030     (*eofCtx) = gCALLBACK_EOF_HANDLER_CTX;
   2031   }
   2032   _rl_done();
   2033   /* remove handler */
   2034   gCALLBACK_EOL_HANDLER     = NULL;
   2035   gCALLBACK_EOL_HANDLER_CTX = NULL;
   2036 
   2037   gCALLBACK_EOF_HANDLER     = NULL;
   2038   gCALLBACK_EOF_HANDLER_CTX = NULL;
   2039 }
   2040 
   2041 #else /* INCLUDE_EDITLINE */
   2042 int _editline_editline_not_empty;
   2043 #endif /* INCLUDE_EDITLINE */