diff options
Diffstat (limited to 'mdk-stage1/slang/slrline.c')
-rw-r--r-- | mdk-stage1/slang/slrline.c | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/mdk-stage1/slang/slrline.c b/mdk-stage1/slang/slrline.c new file mode 100644 index 000000000..1874be0bb --- /dev/null +++ b/mdk-stage1/slang/slrline.c @@ -0,0 +1,836 @@ +/* SLang_read_line interface --- uses SLang tty stuff */ +/* Copyright (c) 1992, 1999, 2001 John E. Davis + * This file is part of the S-Lang library. + * + * You may distribute under the terms of either the GNU General Public + * License or the Perl Artistic License. + */ + +#include "slinclud.h" + +#include "slang.h" +#include "_slang.h" + +#ifdef REAL_UNIX_SYSTEM +int SLang_RL_EOF_Char = 4; +#else +int SLang_RL_EOF_Char = 26; +#endif + +int SLang_Rline_Quit; +static SLang_RLine_Info_Type *This_RLI; + +static unsigned char Char_Widths[256]; +static void position_cursor (int); + +static void rl_beep (void) +{ + putc(7, stdout); + fflush (stdout); +} + +/* editing functions */ +static int rl_bol (void) +{ + if (This_RLI->point == 0) return 0; + This_RLI->point = 0; + return 1; +} + +static int rl_eol (void) +{ + if (This_RLI->point == This_RLI->len) return 0; + This_RLI->point = This_RLI->len; + return 1; +} + +static int rl_right (void) +{ + if (This_RLI->point == This_RLI->len) return 0; + This_RLI->point++; + return 1; +} + +static int rl_left (void) +{ + if (This_RLI->point == 0) return 0; + This_RLI->point--; + return 1; +} + +static int rl_self_insert (void) +{ + unsigned char *pmin, *p; + + if (This_RLI->len == This_RLI->buf_len) + { + rl_beep (); + return 0; + } + + pmin = This_RLI->buf + This_RLI->point; + p = This_RLI->buf + This_RLI->len; + while (p > pmin) + { + *p = *(p - 1); + p--; + } + *pmin = SLang_Last_Key_Char; + + This_RLI->len++; + This_RLI->point++; + if ((This_RLI->curs_pos + 2 >= This_RLI->edit_width) + || (This_RLI->tt_insert == NULL) + || (Char_Widths[SLang_Last_Key_Char] != 1)) return 1; + + (*This_RLI->tt_insert)((char) SLang_Last_Key_Char); + /* update screen buf */ + p = This_RLI->old_upd + (This_RLI->len - 1); + pmin = This_RLI->old_upd + (This_RLI->point - 1); + while (p > pmin) + { + *p = *(p - 1); + p--; + } + *pmin = SLang_Last_Key_Char; + return 0; +} + +int SLang_rline_insert (char *s) +{ + unsigned char *pmin, *p; + int n; + + n = strlen (s); + if (n > This_RLI->buf_len - This_RLI->len) + n = This_RLI->buf_len - This_RLI->len; + + if (n == 0) return 0; + + pmin = This_RLI->buf + This_RLI->point; + p = This_RLI->buf + (This_RLI->len - 1); + + while (p >= pmin) + { + *(p + n) = *p; + p--; + } + SLMEMCPY ((char *) pmin, s, n); + + This_RLI->len += n; + This_RLI->point += n; + return n; +} + +static int rl_deln (int n) +{ + unsigned char *pmax, *p; + + p = This_RLI->buf + This_RLI->point; + pmax = This_RLI->buf + This_RLI->len; + + if (p + n > pmax) n = (int) (pmax - p); + while (p < pmax) + { + *p = *(p + n); + p++; + } + This_RLI->len -= n; + return n; +} + +static int rl_del (void) +{ + return rl_deln(1); +} + +static int rl_quote_insert (void) +{ + int err = SLang_Error; + SLang_Error = 0; + SLang_Last_Key_Char = (*This_RLI->getkey)(); + rl_self_insert (); + if (SLang_Error == SL_USER_BREAK) SLang_Error = 0; + else SLang_Error = err; + return 1; +} + +static int rl_trim (void) +{ + unsigned char *p, *pmax, *p1; + p = This_RLI->buf + This_RLI->point; + pmax = This_RLI->buf + This_RLI->len; + + if (p == pmax) + { + if (p == This_RLI->buf) return 0; + p--; + } + + if ((*p != ' ') && (*p != '\t')) return 0; + p1 = p; + while ((p1 < pmax) && ((*p1 == ' ') || (*p1 == '\t'))) p1++; + pmax = p1; + p1 = This_RLI->buf; + + while ((p >= p1) && ((*p == ' ') || (*p == '\t'))) p--; + if (p == pmax) return 0; + p++; + + This_RLI->point = (int) (p - p1); + return rl_deln ((int) (pmax - p)); +} + +static int rl_bdel (void) +{ + if (rl_left()) return rl_del(); + return 0; +} + +static int rl_deleol (void) +{ + if (This_RLI->point == This_RLI->len) return 0; + *(This_RLI->buf + This_RLI->point) = 0; + This_RLI->len = This_RLI->point; + return 1; +} + +static int rl_delete_line (void) +{ + This_RLI->point = 0; + *(This_RLI->buf + This_RLI->point) = 0; + This_RLI->len = 0; + return 1; +} + +static int rl_enter (void) +{ + *(This_RLI->buf + This_RLI->len) = 0; + SLang_Rline_Quit = 1; + return 1; +} + +static SLKeyMap_List_Type *RL_Keymap; + +/* This update is designed for dumb terminals. It assumes only that the + * terminal can backspace via ^H, and move cursor to start of line via ^M. + * There is a hook so the user can provide a more sophisticated update if + * necessary. + */ + +static void position_cursor (int col) +{ + unsigned char *p, *pmax; + int dc; + + if (col == This_RLI->curs_pos) + { + fflush (stdout); + return; + } + + if (This_RLI->tt_goto_column != NULL) + { + (*This_RLI->tt_goto_column)(col); + This_RLI->curs_pos = col; + fflush (stdout); + return; + } + + dc = This_RLI->curs_pos - col; + if (dc < 0) + { + p = This_RLI->new_upd + This_RLI->curs_pos; + pmax = This_RLI->new_upd + col; + while (p < pmax) putc((char) *p++, stdout); + } + else + { + if (dc < col) + { + while (dc--) putc(8, stdout); + } + else + { + putc('\r', stdout); + p = This_RLI->new_upd; + pmax = This_RLI->new_upd + col; + while (p < pmax) putc((char) *p++, stdout); + } + } + This_RLI->curs_pos = col; + fflush (stdout); +} + +static void erase_eol (SLang_RLine_Info_Type *rli) +{ + unsigned char *p, *pmax; + + p = rli->old_upd + rli->curs_pos; + pmax = rli->old_upd + rli->old_upd_len; + + while (p++ < pmax) putc(' ', stdout); + + rli->curs_pos = rli->old_upd_len; +} + +static unsigned char *spit_out(SLang_RLine_Info_Type *rli, unsigned char *p) +{ + unsigned char *pmax; + position_cursor ((int) (p - rli->new_upd)); + pmax = rli->new_upd + rli->new_upd_len; + while (p < pmax) putc((char) *p++, stdout); + rli->curs_pos = rli->new_upd_len; + return pmax; +} + +static void really_update (SLang_RLine_Info_Type *rli, int new_curs_position) +{ + unsigned char *b = rli->old_upd, *p = rli->new_upd, chb, chp; + unsigned char *pmax; + + if (rli->update_hook != NULL) + { + (*rli->update_hook)(p, rli->edit_width, new_curs_position); + } + else + { + pmax = p + rli->edit_width; + while (p < pmax) + { + chb = *b++; chp = *p++; + if (chb == chp) continue; + + if (rli->old_upd_len <= rli->new_upd_len) + { + /* easy one */ + (void) spit_out (rli, p - 1); + break; + } + spit_out(rli, p - 1); + erase_eol (rli); + break; + } + position_cursor (new_curs_position); + } + + /* update finished, so swap */ + + rli->old_upd_len = rli->new_upd_len; + p = rli->old_upd; + rli->old_upd = rli->new_upd; + rli->new_upd = p; +} + +static void RLupdate (SLang_RLine_Info_Type *rli) +{ + int len, dlen, start_len = 0, prompt_len = 0, tw = 0, count; + int want_cursor_pos; + unsigned char *b, chb, *b_point, *p; + int no_echo; + + no_echo = rli->flags & SL_RLINE_NO_ECHO; + + b_point = (unsigned char *) (rli->buf + rli->point); + *(rli->buf + rli->len) = 0; + + /* expand characters for output buffer --- handle prompt first. + * Do two passes --- first to find out where to begin upon horiz + * scroll and the second to actually fill the buffer. */ + len = 0; + count = 2; /* once for prompt and once for buf */ + + b = (unsigned char *) rli->prompt; + while (count--) + { + if ((count == 0) && no_echo) + break; + + /* The prompt could be NULL */ + if (b != NULL) while ((chb = *b) != 0) + { + /* This will ensure that the screen is scrolled a third of the edit + * width each time */ + if (b_point == b) break; + dlen = Char_Widths[chb]; + if ((chb == '\t') && tw) + { + dlen = tw * ((len - prompt_len) / tw + 1) - (len - prompt_len); + } + len += dlen; + b++; + } + tw = rli->tab; + b = (unsigned char *) rli->buf; + if (count == 1) want_cursor_pos = prompt_len = len; + } + + if (len < rli->edit_width - rli->dhscroll) start_len = 0; + else if ((rli->start_column > len) + || (rli->start_column + rli->edit_width <= len)) + { + start_len = len - (rli->edit_width - rli->dhscroll); + if (start_len < 0) start_len = 0; + } + else start_len = rli->start_column; + rli->start_column = start_len; + + want_cursor_pos = len - start_len; + + /* second pass */ + p = rli->new_upd; + + len = 0; + count = 2; + b = (unsigned char *) rli->prompt; + if (b == NULL) b = (unsigned char *) ""; + + while ((len < start_len) && (*b)) + { + len += Char_Widths[*b++]; + } + + tw = 0; + if (*b == 0) + { + b = (unsigned char *) rli->buf; + while (len < start_len) + { + len += Char_Widths[*b++]; + } + tw = rli->tab; + count--; + } + + len = 0; + while (count--) + { + if ((count == 0) && (no_echo)) + break; + + while ((len < rli->edit_width) && ((chb = *b++) != 0)) + { + dlen = Char_Widths[chb]; + if (dlen == 1) *p++ = chb; + else + { + if ((chb == '\t') && tw) + { + dlen = tw * ((len + start_len - prompt_len) / tw + 1) - (len + start_len - prompt_len); + len += dlen; /* ok since dlen comes out 0 */ + if (len > rli->edit_width) dlen = len - rli->edit_width; + while (dlen--) *p++ = ' '; + dlen = 0; + } + else + { + if (dlen == 3) + { + chb &= 0x7F; + *p++ = '~'; + } + + *p++ = '^'; + if (chb == 127) *p++ = '?'; + else *p++ = chb + '@'; + } + } + len += dlen; + } + /* if (start_len > prompt_len) break; */ + tw = rli->tab; + b = (unsigned char *) rli->buf; + } + + rli->new_upd_len = (int) (p - rli->new_upd); + while (p < rli->new_upd + rli->edit_width) *p++ = ' '; + really_update (rli, want_cursor_pos); +} + +void SLrline_redraw (SLang_RLine_Info_Type *rli) +{ + unsigned char *p = rli->new_upd; + unsigned char *pmax = p + rli->edit_width; + while (p < pmax) *p++ = ' '; + rli->new_upd_len = rli->edit_width; + really_update (rli, 0); + RLupdate (rli); +} + +static int rl_eof_insert (void) +{ + if (This_RLI->len == 0) + { + SLang_Last_Key_Char = SLang_RL_EOF_Char; + /* rl_self_insert (); */ + return rl_enter (); + } + return 0; +} + +/* This is very naive. It knows very little about nesting and nothing + * about quoting. + */ +static void blink_match (SLang_RLine_Info_Type *rli) +{ + unsigned char bra, ket; + unsigned int delta_column; + unsigned char *p, *pmin; + int dq_level, sq_level; + int level; + + pmin = rli->buf; + p = pmin + rli->point; + if (pmin == p) + return; + + ket = SLang_Last_Key_Char; + switch (ket) + { + case ')': + bra = '('; + break; + case ']': + bra = '['; + break; + case '}': + bra = '{'; + break; + default: + return; + } + + level = 0; + sq_level = dq_level = 0; + + delta_column = 0; + while (p > pmin) + { + char ch; + + p--; + delta_column++; + ch = *p; + + if (ch == ket) + { + if ((dq_level == 0) && (sq_level == 0)) + level++; + } + else if (ch == bra) + { + if ((dq_level != 0) || (sq_level != 0)) + continue; + + level--; + if (level == 0) + { + rli->point -= delta_column; + RLupdate (rli); + (*rli->input_pending)(10); + rli->point += delta_column; + RLupdate (rli); + break; + } + if (level < 0) + break; + } + else if (ch == '"') dq_level = !dq_level; + else if (ch == '\'') sq_level = !sq_level; + } +} + +int SLang_read_line (SLang_RLine_Info_Type *rli) +{ + unsigned char *p, *pmax; + SLang_Key_Type *key; + + SLang_Rline_Quit = 0; + This_RLI = rli; + p = rli->old_upd; pmax = p + rli->edit_width; + while (p < pmax) *p++ = ' '; + + /* Sanity checking */ + rli->len = strlen ((char *) rli->buf); + if (rli->len >= rli->buf_len) + { + rli->len = 0; + *rli->buf = 0; + } + if (rli->point > rli->len) rli->point = rli->len; + if (rli->point < 0) rli->point = 0; + + rli->curs_pos = rli->start_column = 0; + rli->new_upd_len = rli->old_upd_len = 0; + + This_RLI->last_fun = NULL; + if (rli->update_hook == NULL) + putc ('\r', stdout); + + RLupdate (rli); + + while (1) + { + key = SLang_do_key (RL_Keymap, (int (*)(void)) rli->getkey); + + if ((key == NULL) || (key->f.f == NULL)) + rl_beep (); + else + { + if ((SLang_Last_Key_Char == SLang_RL_EOF_Char) + && (*key->str == 2) + && (This_RLI->len == 0)) + rl_eof_insert (); + else if (key->type == SLKEY_F_INTRINSIC) + { + if ((key->f.f)()) + RLupdate (rli); + + if ((rli->flags & SL_RLINE_BLINK_MATCH) + && (rli->input_pending != NULL)) + blink_match (rli); + } + + if (SLang_Rline_Quit) + { + This_RLI->buf[This_RLI->len] = 0; + if (SLang_Error == SL_USER_BREAK) + { + SLang_Error = 0; + return -1; + } + return This_RLI->len; + } + } + if (key != NULL) + This_RLI->last_fun = key->f.f; + } +} + +static int rl_abort (void) +{ + rl_delete_line (); + return rl_enter (); +} + +/* TTY interface --- ANSI */ + +static void ansi_goto_column (int n) +{ + putc('\r', stdout); + if (n) fprintf(stdout, "\033[%dC", n); +} + +static void rl_select_line (SLang_Read_Line_Type *p) +{ + This_RLI->last = p; + strcpy ((char *) This_RLI->buf, (char *) p->buf); + This_RLI->point = This_RLI->len = strlen((char *) p->buf); +} +static int rl_next_line (void); +static int rl_prev_line (void) +{ + SLang_Read_Line_Type *prev; + + if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line) + && (This_RLI->last_fun != (FVOID_STAR) rl_next_line)) + || (This_RLI->last == NULL)) + { + prev = This_RLI->tail; + } + else prev = This_RLI->last->prev; + + if (prev == NULL) + { + rl_beep (); + return 0; + } + + rl_select_line (prev); + return 1; +} +static int rl_redraw (void) +{ + SLrline_redraw (This_RLI); + return 1; +} + +static int rl_next_line (void) +{ + SLang_Read_Line_Type *next; + + if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line) + && (This_RLI->last_fun != (FVOID_STAR) rl_next_line)) + || (This_RLI->last == NULL)) + { + rl_beep (); + return 0; + } + + next = This_RLI->last->next; + + if (next == NULL) + { + This_RLI->len = This_RLI->point = 0; + *This_RLI->buf = 0; + This_RLI->last = NULL; + } + else rl_select_line (next); + return 1; +} + +static SLKeymap_Function_Type SLReadLine_Functions[] = +{ + {"up", rl_prev_line}, + {"down", rl_next_line}, + {"bol", rl_bol}, + {"eol", rl_eol}, + {"right", rl_right}, + {"left", rl_left}, + {"self_insert", rl_self_insert}, + {"bdel", rl_bdel}, + {"del", rl_del}, + {"deleol", rl_deleol}, + {"enter", rl_enter}, + {"trim", rl_trim}, + {"quoted_insert", rl_quote_insert}, + {(char *) NULL, NULL} +}; + +int SLang_init_readline (SLang_RLine_Info_Type *rli) +{ + int ch; + char simple[2]; + + if (RL_Keymap == NULL) + { + simple[1] = 0; + if (NULL == (RL_Keymap = SLang_create_keymap ("ReadLine", NULL))) + return -1; + + RL_Keymap->functions = SLReadLine_Functions; + + /* This breaks under some DEC ALPHA compilers (scary!) */ +#ifndef __DECC + for (ch = ' '; ch < 256; ch++) + { + simple[0] = (char) ch; + SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap); + } +#else + ch = ' '; + while (1) + { + simple[0] = (char) ch; + SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap); + ch = ch + 1; + if (ch == 256) break; + } +#endif /* NOT __DECC */ + + simple[0] = SLang_Abort_Char; + SLkm_define_key (simple, (FVOID_STAR) rl_abort, RL_Keymap); + simple[0] = SLang_RL_EOF_Char; + SLkm_define_key (simple, (FVOID_STAR) rl_eof_insert, RL_Keymap); + +#ifndef IBMPC_SYSTEM + SLkm_define_key ("^[[A", (FVOID_STAR) rl_prev_line, RL_Keymap); + SLkm_define_key ("^[[B", (FVOID_STAR) rl_next_line, RL_Keymap); + SLkm_define_key ("^[[C", (FVOID_STAR) rl_right, RL_Keymap); + SLkm_define_key ("^[[D", (FVOID_STAR) rl_left, RL_Keymap); + SLkm_define_key ("^[OA", (FVOID_STAR) rl_prev_line, RL_Keymap); + SLkm_define_key ("^[OB", (FVOID_STAR) rl_next_line, RL_Keymap); + SLkm_define_key ("^[OC", (FVOID_STAR) rl_right, RL_Keymap); + SLkm_define_key ("^[OD", (FVOID_STAR) rl_left, RL_Keymap); +#else + SLkm_define_key ("^@H", (FVOID_STAR) rl_prev_line, RL_Keymap); + SLkm_define_key ("^@P", (FVOID_STAR) rl_next_line, RL_Keymap); + SLkm_define_key ("^@M", (FVOID_STAR) rl_right, RL_Keymap); + SLkm_define_key ("^@K", (FVOID_STAR) rl_left, RL_Keymap); + SLkm_define_key ("^@S", (FVOID_STAR) rl_del, RL_Keymap); + SLkm_define_key ("^@O", (FVOID_STAR) rl_eol, RL_Keymap); + SLkm_define_key ("^@G", (FVOID_STAR) rl_bol, RL_Keymap); + + SLkm_define_key ("\xE0H", (FVOID_STAR) rl_prev_line, RL_Keymap); + SLkm_define_key ("\xE0P", (FVOID_STAR) rl_next_line, RL_Keymap); + SLkm_define_key ("\xE0M", (FVOID_STAR) rl_right, RL_Keymap); + SLkm_define_key ("\xE0K", (FVOID_STAR) rl_left, RL_Keymap); + SLkm_define_key ("\xE0S", (FVOID_STAR) rl_del, RL_Keymap); + SLkm_define_key ("\xE0O", (FVOID_STAR) rl_eol, RL_Keymap); + SLkm_define_key ("\xE0G", (FVOID_STAR) rl_bol, RL_Keymap); +#endif + SLkm_define_key ("^C", (FVOID_STAR) rl_abort, RL_Keymap); + SLkm_define_key ("^E", (FVOID_STAR) rl_eol, RL_Keymap); + SLkm_define_key ("^G", (FVOID_STAR) rl_abort, RL_Keymap); + SLkm_define_key ("^I", (FVOID_STAR) rl_self_insert, RL_Keymap); + SLkm_define_key ("^A", (FVOID_STAR) rl_bol, RL_Keymap); + SLkm_define_key ("\r", (FVOID_STAR) rl_enter, RL_Keymap); + SLkm_define_key ("\n", (FVOID_STAR) rl_enter, RL_Keymap); + SLkm_define_key ("^K", (FVOID_STAR) rl_deleol, RL_Keymap); + SLkm_define_key ("^L", (FVOID_STAR) rl_deleol, RL_Keymap); + SLkm_define_key ("^V", (FVOID_STAR) rl_del, RL_Keymap); + SLkm_define_key ("^D", (FVOID_STAR) rl_del, RL_Keymap); + SLkm_define_key ("^F", (FVOID_STAR) rl_right, RL_Keymap); + SLkm_define_key ("^B", (FVOID_STAR) rl_left, RL_Keymap); + SLkm_define_key ("^?", (FVOID_STAR) rl_bdel, RL_Keymap); + SLkm_define_key ("^H", (FVOID_STAR) rl_bdel, RL_Keymap); + SLkm_define_key ("^P", (FVOID_STAR) rl_prev_line, RL_Keymap); + SLkm_define_key ("^N", (FVOID_STAR) rl_next_line, RL_Keymap); + SLkm_define_key ("^R", (FVOID_STAR) rl_redraw, RL_Keymap); + SLkm_define_key ("`", (FVOID_STAR) rl_quote_insert, RL_Keymap); + SLkm_define_key ("\033\\", (FVOID_STAR) rl_trim, RL_Keymap); + if (SLang_Error) return -1; + } + + if (rli->prompt == NULL) rli->prompt = ""; + if (rli->keymap == NULL) rli->keymap = RL_Keymap; + rli->old_upd = rli->upd_buf1; + rli->new_upd = rli->upd_buf2; + *rli->buf = 0; + rli->point = 0; + + if (rli->flags & SL_RLINE_USE_ANSI) + { + if (rli->tt_goto_column == NULL) rli->tt_goto_column = ansi_goto_column; + } + + if (Char_Widths[0] == 2) return 0; + + for (ch = 0; ch < 32; ch++) Char_Widths[ch] = 2; + for (ch = 32; ch < 256; ch++) Char_Widths[ch] = 1; + Char_Widths[127] = 2; +#ifndef IBMPC_SYSTEM + for (ch = 128; ch < 160; ch++) Char_Widths[ch] = 3; +#endif + + return 0; +} + +SLang_Read_Line_Type *SLang_rline_save_line (SLang_RLine_Info_Type *rli) +{ + SLang_Read_Line_Type *rl = NULL; + unsigned char *buf; + + if ((rli == NULL) || (rli->buf == NULL)) + return NULL; + + if (NULL == (rl = (SLang_Read_Line_Type *) SLmalloc (sizeof (SLang_Read_Line_Type))) + || (NULL == (buf = (unsigned char *) SLmake_string ((char *)rli->buf)))) + { + SLfree ((char *)rl); + return NULL; + } + rl->buf = buf; + rl->buf_len = strlen ((char *)buf); + rl->num = rl->misc = 0; + rl->next = rl->prev = NULL; + + if (rli->tail != NULL) + { + rli->tail->next = rl; + rl->prev = rli->tail; + } + rli->tail = rl; + + return rl; +} |