36 #if !defined(lint) && !defined(SCCSID) 
   38 static char sccsid[] = 
"@(#)term.c      8.2 (Berkeley) 4/30/95";
 
   66 #if defined(HAVE_TERM_H) && !defined(__sun) 
   70 #include <sys/types.h> 
   71 #include <sys/ioctl.h> 
   86 #define TC_BUFSIZE      ((size_t)2048) 
   88 #define GoodStr(a)      (el->el_terminal.t_str[a] != NULL && \ 
   89                             el->el_terminal.t_str[a][0] != '\0') 
   90 #define Str(a)          el->el_terminal.t_str[a] 
   91 #define Val(a)          el->el_terminal.t_val[a] 
   95         const char *long_name;
 
   98         { 
"al", 
"add new blank line" },
 
  100         { 
"bl", 
"audible bell" },
 
  102         { 
"cd", 
"clear to bottom" },
 
  104         { 
"ce", 
"clear to end of line" },
 
  106         { 
"ch", 
"cursor to horiz pos" },
 
  108         { 
"cl", 
"clear screen" },
 
  110         { 
"dc", 
"delete a character" },
 
  112         { 
"dl", 
"delete a line" },
 
  114         { 
"dm", 
"start delete mode" },
 
  116         { 
"ed", 
"end delete mode" },
 
  118         { 
"ei", 
"end insert mode" },
 
  120         { 
"fs", 
"cursor from status line" },
 
  122         { 
"ho", 
"home cursor" },
 
  124         { 
"ic", 
"insert character" },
 
  126         { 
"im", 
"start insert mode" },
 
  128         { 
"ip", 
"insert padding" },
 
  130         { 
"kd", 
"sends cursor down" },
 
  132         { 
"kl", 
"sends cursor left" },
 
  134         { 
"kr", 
"sends cursor right" },
 
  136         { 
"ku", 
"sends cursor up" },
 
  138         { 
"md", 
"begin bold" },
 
  140         { 
"me", 
"end attributes" },
 
  142         { 
"nd", 
"non destructive space" },
 
  144         { 
"se", 
"end standout" },
 
  146         { 
"so", 
"begin standout" },
 
  148         { 
"ts", 
"cursor to status line" },
 
  150         { 
"up", 
"cursor up one" },
 
  152         { 
"us", 
"begin underline" },
 
  154         { 
"ue", 
"end underline" },
 
  156         { 
"vb", 
"visible bell" },
 
  158         { 
"DC", 
"delete multiple chars" },
 
  160         { 
"DO", 
"cursor down multiple" },
 
  162         { 
"IC", 
"insert multiple chars" },
 
  164         { 
"LE", 
"cursor left multiple" },
 
  166         { 
"RI", 
"cursor right multiple" },
 
  168         { 
"UP", 
"cursor up multiple" },
 
  170         { 
"kh", 
"send cursor home" },
 
  172         { 
"@7", 
"send cursor end" },
 
  179         const char *long_name;
 
  182         { 
"am", 
"has automatic margins" },
 
  184         { 
"pt", 
"has physical tabs" },
 
  186         { 
"li", 
"Number of lines" },
 
  188         { 
"co", 
"Number of columns" },
 
  190         { 
"km", 
"Has meta key" },
 
  192         { 
"xt", 
"Tab chars destructive" },
 
  194         { 
"xn", 
"newline ignored at right margin" },
 
  196         { 
"MT", 
"Has meta key" },                       
 
  202 private void    terminal_setflags(
EditLine *);
 
  203 private int     terminal_rebuffer_display(
EditLine *);
 
  204 private void    terminal_free_display(
EditLine *);
 
  205 private int     terminal_alloc_display(
EditLine *);
 
  208 private void    terminal_init_arrow(
EditLine *);
 
  209 private void    terminal_reset_arrow(
EditLine *);
 
  210 private int     terminal_putc(
int);
 
  211 private void    terminal_tputs(
EditLine *, 
const char *, 
int);
 
  214 private pthread_mutex_t terminal_mutex = PTHREAD_MUTEX_INITIALIZER;
 
  216 private FILE *terminal_outfile = NULL;
 
  226         if (el->el_tty.t_tabs)
 
  227                 EL_FLAGS |= (
Val(T_pt) && !
Val(T_xt)) ? TERM_CAN_TAB : 0;
 
  229         EL_FLAGS |= (
Val(T_km) || 
Val(T_MT)) ? TERM_HAS_META : 0;
 
  230         EL_FLAGS |= GoodStr(T_ce) ? TERM_CAN_CEOL : 0;
 
  231         EL_FLAGS |= (GoodStr(T_dc) || GoodStr(T_DC)) ? TERM_CAN_DELETE : 0;
 
  232         EL_FLAGS |= (GoodStr(T_im) || GoodStr(T_ic) || GoodStr(T_IC)) ?
 
  234         EL_FLAGS |= (GoodStr(T_up) || GoodStr(T_UP)) ? TERM_CAN_UP : 0;
 
  235         EL_FLAGS |= 
Val(T_am) ? TERM_HAS_AUTO_MARGINS : 0;
 
  236         EL_FLAGS |= 
Val(T_xn) ? TERM_HAS_MAGIC_MARGINS : 0;
 
  238         if (GoodStr(T_me) && GoodStr(T_ue))
 
  239                 EL_FLAGS |= (strcmp(Str(T_me), Str(T_ue)) == 0) ?
 
  242                 EL_FLAGS &= ~TERM_CAN_ME;
 
  243         if (GoodStr(T_me) && GoodStr(T_se))
 
  244                 EL_FLAGS |= (strcmp(Str(T_me), Str(T_se)) == 0) ?
 
  250                 (void) fprintf(el->el_errfile,
 
  251                     "WARNING: Your terminal cannot move up.\n");
 
  252                 (void) fprintf(el->el_errfile,
 
  253                     "Editing may be odd for long lines.\n");
 
  256                 (void) fprintf(el->el_errfile, 
"no clear EOL capability.\n");
 
  258                 (void) fprintf(el->el_errfile, 
"no delete char capability.\n");
 
  260                 (void) fprintf(el->el_errfile, 
"no insert char capability.\n");
 
  271         el->el_terminal.t_buf = el_malloc(TC_BUFSIZE *
 
  272             sizeof(*el->el_terminal.t_buf));
 
  273         if (el->el_terminal.t_buf == NULL)
 
  275         el->el_terminal.t_cap = el_malloc(TC_BUFSIZE *
 
  276             sizeof(*el->el_terminal.t_cap));
 
  277         if (el->el_terminal.t_cap == NULL)
 
  279         el->el_terminal.t_fkey = el_malloc(A_K_NKEYS *
 
  280             sizeof(*el->el_terminal.t_fkey));
 
  281         if (el->el_terminal.t_fkey == NULL)
 
  283         el->el_terminal.t_loc = 0;
 
  284         el->el_terminal.t_str = el_malloc(T_str *
 
  285             sizeof(*el->el_terminal.t_str));
 
  286         if (el->el_terminal.t_str == NULL)
 
  288         (void) memset(el->el_terminal.t_str, 0, T_str *
 
  289             sizeof(*el->el_terminal.t_str));
 
  290         el->el_terminal.t_val = el_malloc(T_val *
 
  291             sizeof(*el->el_terminal.t_val));
 
  292         if (el->el_terminal.t_val == NULL)
 
  294         (void) memset(el->el_terminal.t_val, 0, T_val *
 
  295             sizeof(*el->el_terminal.t_val));
 
  296         (void) terminal_set(el, NULL);
 
  297         terminal_init_arrow(el);
 
  308         el_free(el->el_terminal.t_buf);
 
  309         el->el_terminal.t_buf = NULL;
 
  310         el_free(el->el_terminal.t_cap);
 
  311         el->el_terminal.t_cap = NULL;
 
  312         el->el_terminal.t_loc = 0;
 
  313         el_free(el->el_terminal.t_str);
 
  314         el->el_terminal.t_str = NULL;
 
  315         el_free(el->el_terminal.t_val);
 
  316         el->el_terminal.t_val = NULL;
 
  317         el_free(el->el_terminal.t_fkey);
 
  318         el->el_terminal.t_fkey = NULL;
 
  319         terminal_free_display(el);
 
  329         char termbuf[TC_BUFSIZE];
 
  331         char **tlist = el->el_terminal.t_str;
 
  332         char **tmp, **str = &tlist[t - tstr];
 
  334         if (cap == NULL || *cap == 
'\0') {
 
  340         tlen = *str == NULL ? 0 : strlen(*str);
 
  347                         (void) strcpy(*str, cap);       
 
  353         if (el->el_terminal.t_loc + 3 < TC_BUFSIZE) {
 
  355                 (void) strcpy(*str = &el->el_terminal.t_buf[
 
  356                     el->el_terminal.t_loc], cap);
 
  357                 el->el_terminal.t_loc += clen + 1;      
 
  365         for (tmp = tlist; tmp < &tlist[T_str]; tmp++)
 
  366                 if (*tmp != NULL && *tmp != 
'\0' && *tmp != *str) {
 
  369                         for (ptr = *tmp; *ptr != 
'\0'; termbuf[tlen++] = *ptr++)
 
  371                         termbuf[tlen++] = 
'\0';
 
  373         memcpy(el->el_terminal.t_buf, termbuf, TC_BUFSIZE);
 
  374         el->el_terminal.t_loc = tlen;
 
  375         if (el->el_terminal.t_loc + 3 >= TC_BUFSIZE) {
 
  376                 (void) fprintf(el->el_errfile,
 
  377                     "Out of termcap string space.\n");
 
  381         (void) strcpy(*str = &el->el_terminal.t_buf[el->el_terminal.t_loc],
 
  383         el->el_terminal.t_loc += (size_t)clen + 1;      
 
  392 terminal_rebuffer_display(
EditLine *el)
 
  394         coord_t *c = &el->el_terminal.t_size;
 
  396         terminal_free_display(el);
 
  401         if (terminal_alloc_display(el) == -1)
 
  411 terminal_alloc_display(
EditLine *el)
 
  415         coord_t *c = &el->el_terminal.t_size;
 
  417         b =  el_malloc(
sizeof(*b) * (
size_t)(c->v + 1));
 
  420         for (i = 0; i < c->v; i++) {
 
  421                 b[
i] = el_malloc(
sizeof(**b) * (
size_t)(c->h + 1));
 
  432         b = el_malloc(
sizeof(*b) * (
size_t)(c->v + 1));
 
  435         for (i = 0; i < c->v; i++) {
 
  436                 b[
i] = el_malloc(
sizeof(**b) * (
size_t)(c->h + 1));
 
  460         el->el_display = NULL;
 
  462                 for (bufp = b; *bufp != NULL; bufp++)
 
  467         el->el_vdisplay = NULL;
 
  469                 for (bufp = b; *bufp != NULL; bufp++)
 
  481 terminal_move_to_line(
EditLine *el, 
int where)
 
  485         if (where == el->el_cursor.v)
 
  488         if (where > el->el_terminal.t_size.v) {
 
  490                 (void) fprintf(el->el_errfile,
 
  491                     "terminal_move_to_line: where is ridiculous: %d\r\n",
 
  496         if ((del = where - el->el_cursor.v) > 0) {
 
  498                         if (EL_HAS_AUTO_MARGINS &&
 
  499                             el->el_display[el->el_cursor.v][0] != 
'\0') {
 
  501                                     (el->el_terminal.t_size.h - 1);
 
  504                                          el->el_display[el->el_cursor.v][h] ==
 
  510                                 terminal_move_to_char(el, (
int)h);
 
  511                                 terminal_overwrite(el, &el->el_display
 
  512                                     [el->el_cursor.v][el->el_cursor.h],
 
  513                                     (
size_t)(el->el_terminal.t_size.h -
 
  518                                 if ((del > 1) && GoodStr(T_DO)) {
 
  519                                         terminal_tputs(el, tgoto(Str(T_DO), del,
 
  523                                         for (; del > 0; del--)
 
  524                                                 terminal__putc(el, 
'\n');
 
  531                 if (GoodStr(T_UP) && (-del > 1 || !GoodStr(T_up)))
 
  532                         terminal_tputs(el, tgoto(Str(T_UP), -del, -del), -del);
 
  535                                 for (; del < 0; del++)
 
  536                                         terminal_tputs(el, Str(T_up), 1);
 
  539         el->el_cursor.v = where;
 
  547 terminal_move_to_char(
EditLine *el, 
int where)
 
  552         if (where == el->el_cursor.h)
 
  555         if (where > el->el_terminal.t_size.h) {
 
  557                 (void) fprintf(el->el_errfile,
 
  558                     "terminal_move_to_char: where is riduculous: %d\r\n",
 
  564                 terminal__putc(el, 
'\r');       
 
  568         del = where - el->el_cursor.h;
 
  570         if ((del < -4 || del > 4) && GoodStr(T_ch))
 
  572                 terminal_tputs(el, tgoto(Str(T_ch), where, where), where);
 
  575                         if ((del > 4) && GoodStr(T_RI))
 
  576                                 terminal_tputs(el, tgoto(Str(T_RI), del, del),
 
  581                                         if ((el->el_cursor.h & 0370) !=
 
  585                                             el->el_cursor.v][where & 0370] !=
 
  591                                                     (el->el_cursor.h & 0370);
 
  597                                                 el->el_cursor.h = where & ~0x7;
 
  608                                 terminal_overwrite(el, &el->el_display[
 
  609                                     el->el_cursor.v][el->el_cursor.h],
 
  610                                     (
size_t)(where - el->el_cursor.h));
 
  614                         if ((-del > 4) && GoodStr(T_LE))
 
  615                                 terminal_tputs(el, tgoto(Str(T_LE), -del, -del),
 
  623                                     ((
unsigned int)-del >
 
  624                                     (((
unsigned int) where >> 3) +
 
  627                                         terminal__putc(el, 
'\r');
 
  631                                 for (i = 0; i < -del; i++)
 
  632                                         terminal__putc(el, 
'\b');
 
  636         el->el_cursor.h = where;                
 
  645 terminal_overwrite(
EditLine *el, 
const Char *cp, 
size_t n)
 
  654         if (n > (
size_t)el->el_terminal.t_size.h) {
 
  656                 (void) fprintf(el->el_errfile,
 
  657                     "terminal_overwrite: n is riduculous: %d\r\n", n);
 
  664                 width = wcwidth(*cp);    
 
  666                   el->el_cursor.h += width;
 
  671                 terminal__putc(el, *cp++);
 
  674         if (el->el_cursor.h >= el->el_terminal.t_size.h) {      
 
  675                 if (EL_HAS_AUTO_MARGINS) {      
 
  678                         if (EL_HAS_MAGIC_MARGINS) {
 
  682                                 if ((c = el->el_display[el->el_cursor.v]
 
  683                                     [el->el_cursor.h]) != 
'\0') {
 
  684                                         terminal_overwrite(el, &c, (
size_t)1);
 
  686                                         while (el->el_display[el->el_cursor.v]
 
  687                                             [el->el_cursor.h] == MB_FILL_CHAR)
 
  691                                         terminal__putc(el, 
' ');
 
  696                         el->el_cursor.h = el->el_terminal.t_size.h - 1;
 
  705 terminal_deletechars(
EditLine *el, 
int num)
 
  710         if (!EL_CAN_DELETE) {
 
  712                 (void) fprintf(el->el_errfile, 
"   ERROR: cannot delete   \n");
 
  716         if (num > el->el_terminal.t_size.h) {
 
  718                 (void) fprintf(el->el_errfile,
 
  719                     "terminal_deletechars: num is riduculous: %d\r\n", num);
 
  724                 if ((num > 1) || !GoodStr(T_dc)) {      
 
  726                         terminal_tputs(el, tgoto(Str(T_DC), num, num), num);
 
  730                 terminal_tputs(el, Str(T_dm), 1);
 
  734                         terminal_tputs(el, Str(T_dc), 1);
 
  737                 terminal_tputs(el, Str(T_ed), 1);
 
  747 terminal_insertwrite(
EditLine *el, Char *cp, 
int num)
 
  751         if (!EL_CAN_INSERT) {
 
  753                 (void) fprintf(el->el_errfile, 
"   ERROR: cannot insert   \n");
 
  757         if (num > el->el_terminal.t_size.h) {
 
  759                 (void) fprintf(el->el_errfile,
 
  760                     "StartInsert: num is riduculous: %d\r\n", num);
 
  765                 if ((num > 1) || !GoodStr(T_ic)) {
 
  767                         terminal_tputs(el, tgoto(Str(T_IC), num, num), num);
 
  768                         terminal_overwrite(el, cp, (
size_t)num);
 
  772         if (GoodStr(T_im) && GoodStr(T_ei)) {   
 
  773                 terminal_tputs(el, Str(T_im), 1);
 
  775                 el->el_cursor.h += num;
 
  777                         terminal__putc(el, *cp++);
 
  781                         terminal_tputs(el, Str(T_ip), 1);
 
  783                 terminal_tputs(el, Str(T_ei), 1);
 
  788                         terminal_tputs(el, Str(T_ic), 1);
 
  790                 terminal__putc(el, *cp++);
 
  795                         terminal_tputs(el, Str(T_ip), 1);
 
  806 terminal_clear_EOL(
EditLine *el, 
int num)
 
  810         if (EL_CAN_CEOL && GoodStr(T_ce))
 
  811                 terminal_tputs(el, Str(T_ce), 1);
 
  813                 for (i = 0; i < num; i++)
 
  814                         terminal__putc(el, 
' ');
 
  815                 el->el_cursor.h += num; 
 
  829                 terminal_tputs(el, Str(T_cl), 
Val(T_li));
 
  830         else if (GoodStr(T_ho) && GoodStr(T_cd)) {
 
  831                 terminal_tputs(el, Str(T_ho), 
Val(T_li));       
 
  833                 terminal_tputs(el, Str(T_cd), 
Val(T_li));
 
  835                 terminal__putc(el, 
'\r');
 
  836                 terminal__putc(el, 
'\n');
 
  849                 terminal_tputs(el, Str(T_bl), 1);
 
  851                 terminal__putc(el, 
'\007');     
 
  856 terminal_get(
EditLine *el, 
const char **term)
 
  858         *term = el->el_terminal.t_name;
 
  866 terminal_set(
EditLine *el, 
const char *term)
 
  869         char buf[TC_BUFSIZE];
 
  875         (void) sigemptyset(&nset);
 
  876         (void) sigaddset(&nset, SIGWINCH);
 
  877         (void) sigprocmask(SIG_BLOCK, &nset, &oset);
 
  883                 term = getenv(
"TERM");
 
  885         if (!term || !term[0])
 
  888         if (strcmp(term, 
"emacs") == 0)
 
  889                 el->el_flags |= EDIT_DISABLED;
 
  891         memset(el->el_terminal.t_cap, 0, TC_BUFSIZE);
 
  893         i = tgetent(el->el_terminal.t_cap, term);
 
  897                         (void) fprintf(el->el_errfile,
 
  898                             "Cannot read termcap database;\n");
 
  900                         (void) fprintf(el->el_errfile,
 
  901                             "No entry for terminal type \"%s\";\n", term);
 
  902                 (void) fprintf(el->el_errfile,
 
  903                     "using dumb terminal settings.\n");
 
  907                 for (t = tstr; t->name != NULL; t++)
 
  908                         terminal_alloc(el, t, NULL);
 
  911                 Val(T_am) = tgetflag(
"am");
 
  912                 Val(T_xn) = tgetflag(
"xn");
 
  914                 Val(T_pt) = tgetflag(
"pt");
 
  915                 Val(T_xt) = tgetflag(
"xt");
 
  917                 Val(T_km) = tgetflag(
"km");
 
  918                 Val(T_MT) = tgetflag(
"MT");
 
  920                 Val(T_co) = tgetnum(
"co");
 
  921                 Val(T_li) = tgetnum(
"li");
 
  922                 for (t = tstr; t->name != NULL; t++) {
 
  924                         terminal_alloc(el, t, tgetstr(strchr(t->name, *t->name),
 
  934         el->el_terminal.t_size.v = 
Val(T_co);
 
  935         el->el_terminal.t_size.h = 
Val(T_li);
 
  937         terminal_setflags(el);
 
  940         (void) terminal_get_size(el, &lins, &cols);
 
  941         if (terminal_change_size(el, lins, cols) == -1)
 
  943         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
 
  944         terminal_bind_arrow(el);
 
  945         el->el_terminal.t_name = term;
 
  946         return i <= 0 ? -1 : 0;
 
  955 terminal_get_size(
EditLine *el, 
int *lins, 
int *cols)
 
  964                 if (ioctl(el->el_infd, TIOCGWINSZ, &ws) != -1) {
 
  975                 if (ioctl(el->el_infd, TIOCGSIZE, &ts) != -1) {
 
  983         return Val(T_co) != *cols || 
Val(T_li) != *lins;
 
  991 terminal_change_size(
EditLine *el, 
int lins, 
int cols)
 
  996         Val(T_co) = (cols < 2) ? 80 : cols;
 
  997         Val(T_li) = (lins < 1) ? 24 : lins;
 
 1000         if (terminal_rebuffer_display(el) == -1)
 
 1002         re_clear_display(el);
 
 1013         funckey_t *arrow = el->el_terminal.t_fkey;
 
 1015         arrow[A_K_DN].name = STR(
"down");
 
 1016         arrow[A_K_DN].key = T_kd;
 
 1017         arrow[A_K_DN].fun.cmd = ED_NEXT_HISTORY;
 
 1018         arrow[A_K_DN].type = XK_CMD;
 
 1020         arrow[A_K_UP].name = STR(
"up");
 
 1021         arrow[A_K_UP].key = T_ku;
 
 1022         arrow[A_K_UP].fun.cmd = ED_PREV_HISTORY;
 
 1023         arrow[A_K_UP].type = XK_CMD;
 
 1025         arrow[A_K_LT].name = STR(
"left");
 
 1026         arrow[A_K_LT].key = T_kl;
 
 1027         arrow[A_K_LT].fun.cmd = ED_PREV_CHAR;
 
 1028         arrow[A_K_LT].type = XK_CMD;
 
 1030         arrow[A_K_RT].name = STR(
"right");
 
 1031         arrow[A_K_RT].key = T_kr;
 
 1032         arrow[A_K_RT].fun.cmd = ED_NEXT_CHAR;
 
 1033         arrow[A_K_RT].type = XK_CMD;
 
 1035         arrow[A_K_HO].name = STR(
"home");
 
 1036         arrow[A_K_HO].key = T_kh;
 
 1037         arrow[A_K_HO].fun.cmd = ED_MOVE_TO_BEG;
 
 1038         arrow[A_K_HO].type = XK_CMD;
 
 1040         arrow[A_K_EN].name = STR(
"end");
 
 1041         arrow[A_K_EN].key = T_at7;
 
 1042         arrow[A_K_EN].fun.cmd = ED_MOVE_TO_END;
 
 1043         arrow[A_K_EN].type = XK_CMD;
 
 1053         funckey_t *arrow = el->el_terminal.t_fkey;
 
 1054         static const Char strA[] = {033, 
'[', 
'A', 
'\0'};
 
 1055         static const Char strB[] = {033, 
'[', 
'B', 
'\0'};
 
 1056         static const Char strC[] = {033, 
'[', 
'C', 
'\0'};
 
 1057         static const Char strD[] = {033, 
'[', 
'D', 
'\0'};
 
 1058         static const Char strH[] = {033, 
'[', 
'H', 
'\0'};
 
 1059         static const Char strF[] = {033, 
'[', 
'F', 
'\0'};
 
 1060         static const Char stOA[] = {033, 
'O', 
'A', 
'\0'};
 
 1061         static const Char stOB[] = {033, 
'O', 
'B', 
'\0'};
 
 1062         static const Char stOC[] = {033, 
'O', 
'C', 
'\0'};
 
 1063         static const Char stOD[] = {033, 
'O', 
'D', 
'\0'};
 
 1064         static const Char stOH[] = {033, 
'O', 
'H', 
'\0'};
 
 1065         static const Char stOF[] = {033, 
'O', 
'F', 
'\0'};
 
 1067         keymacro_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].
type);
 
 1068         keymacro_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].
type);
 
 1069         keymacro_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].
type);
 
 1070         keymacro_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].
type);
 
 1071         keymacro_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].
type);
 
 1072         keymacro_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].
type);
 
 1073         keymacro_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].
type);
 
 1074         keymacro_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].
type);
 
 1075         keymacro_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].
type);
 
 1076         keymacro_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].
type);
 
 1077         keymacro_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].
type);
 
 1078         keymacro_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].
type);
 
 1080         if (el->el_map.type != MAP_VI)
 
 1082         keymacro_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].
type);
 
 1083         keymacro_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].
type);
 
 1084         keymacro_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].
type);
 
 1085         keymacro_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].
type);
 
 1086         keymacro_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].
type);
 
 1087         keymacro_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].
type);
 
 1088         keymacro_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].
type);
 
 1089         keymacro_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].
type);
 
 1090         keymacro_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].
type);
 
 1091         keymacro_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].
type);
 
 1092         keymacro_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].
type);
 
 1093         keymacro_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].
type);
 
 1104         funckey_t *arrow = el->el_terminal.t_fkey;
 
 1107         for (i = 0; i < A_K_NKEYS; i++)
 
 1108                 if (Strcmp(name, arrow[i].name) == 0) {
 
 1109                         arrow[
i].fun = *fun;
 
 1110                         arrow[
i].type = 
type;
 
 1121 terminal_clear_arrow(
EditLine *el, 
const Char *name)
 
 1123         funckey_t *arrow = el->el_terminal.t_fkey;
 
 1126         for (i = 0; i < A_K_NKEYS; i++)
 
 1127                 if (Strcmp(name, arrow[i].name) == 0) {
 
 1128                         arrow[
i].type = XK_NOD;
 
 1139 terminal_print_arrow(
EditLine *el, 
const Char *name)
 
 1142         funckey_t *arrow = el->el_terminal.t_fkey;
 
 1144         for (i = 0; i < A_K_NKEYS; i++)
 
 1145                 if (*name == 
'\0' || Strcmp(name, arrow[i].name) == 0)
 
 1146                         if (arrow[i].type != XK_NOD)
 
 1147                                 keymacro_kprint(el, arrow[i].name,
 
 1148                                     &arrow[i].fun, arrow[i].type);
 
 1159         const el_action_t *dmap;
 
 1162         funckey_t *arrow = el->el_terminal.t_fkey;
 
 1165         if (el->el_terminal.t_buf == NULL || el->el_map.key == NULL)
 
 1168         map = el->el_map.type == MAP_VI ? el->el_map.alt : el->el_map.key;
 
 1169         dmap = el->el_map.type == MAP_VI ? el->el_map.vic : el->el_map.emacs;
 
 1171         terminal_reset_arrow(el);
 
 1173         for (i = 0; i < A_K_NKEYS; i++) {
 
 1174                 Char wt_str[VISUAL_WIDTH_MAX];
 
 1178                 p = el->el_terminal.t_str[arrow[
i].key];
 
 1181                 for (n = 0; n < VISUAL_WIDTH_MAX && p[
n]; ++
n)
 
 1183                 while (n < VISUAL_WIDTH_MAX)
 
 1186                 j = (
unsigned char) *p;
 
 1197                 if (arrow[i].type == XK_NOD)
 
 1198                         keymacro_clear(el, map, px);
 
 1200                         if (p[1] && (dmap[j] == map[j] ||
 
 1201                                 map[j] == ED_SEQUENCE_LEAD_IN)) {
 
 1202                                 keymacro_add(el, px, &arrow[i].fun,
 
 1204                                 map[j] = ED_SEQUENCE_LEAD_IN;
 
 1205                         } 
else if (map[j] == ED_UNASSIGNED) {
 
 1206                                 keymacro_clear(el, map, px);
 
 1207                                 if (arrow[i].type == XK_CMD)
 
 1208                                         map[j] = arrow[
i].fun.cmd;
 
 1210                                         keymacro_add(el, px, &arrow[i].fun,
 
 1221 terminal_putc(
int c)
 
 1223         if (terminal_outfile == NULL)
 
 1225         return fputc(c, terminal_outfile);
 
 1229 terminal_tputs(
EditLine *el, 
const char *cap, 
int affcnt)
 
 1232         pthread_mutex_lock(&terminal_mutex);
 
 1234         terminal_outfile = el->el_outfile;
 
 1235         (void)tputs(cap, affcnt, terminal_putc);
 
 1237         pthread_mutex_unlock(&terminal_mutex);
 
 1245 terminal__putc(
EditLine *el, Int c)
 
 1247         char buf[MB_LEN_MAX +1];
 
 1251         memset(&state, 0, 
sizeof(mbstate_t));
 
 1252         if (c == (Int)MB_FILL_CHAR)
 
 1254         i = ct_encode_char(buf, (
size_t)MB_CUR_MAX, c, &state);
 
 1258         return fputs(buf, el->el_outfile);
 
 1268         (void) fflush(el->el_outfile);
 
 1275 terminal_writec(
EditLine *el, Int c)
 
 1277         Char visbuf[VISUAL_WIDTH_MAX +1];
 
 1278         ssize_t vcnt = ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
 
 1279         visbuf[vcnt] = 
'\0';
 
 1280         terminal_overwrite(el, visbuf, (
size_t)vcnt);
 
 1281         terminal__flush(el);
 
 1290 terminal_telltc(
EditLine *el, 
int argc __attribute__((__unused__)), 
 
 1291     const Char **argv __attribute__((__unused__)))
 
 1296         (void) fprintf(el->el_outfile, 
"\n\tYour terminal has the\n");
 
 1297         (void) fprintf(el->el_outfile, 
"\tfollowing characteristics:\n\n");
 
 1298         (void) fprintf(el->el_outfile, 
"\tIt has %d columns and %d lines\n",
 
 1300         (void) fprintf(el->el_outfile,
 
 1301             "\tIt has %s meta key\n", EL_HAS_META ? 
"a" : 
"no");
 
 1302         (void) fprintf(el->el_outfile,
 
 1303             "\tIt can%suse tabs\n", EL_CAN_TAB ? 
" " : 
"not ");
 
 1304         (void) fprintf(el->el_outfile, 
"\tIt %s automatic margins\n",
 
 1305             EL_HAS_AUTO_MARGINS ? 
"has" : 
"does not have");
 
 1306         if (EL_HAS_AUTO_MARGINS)
 
 1307                 (void) fprintf(el->el_outfile, 
"\tIt %s magic margins\n",
 
 1308                     EL_HAS_MAGIC_MARGINS ? 
"has" : 
"does not have");
 
 1310         for (t = tstr, ts = el->el_terminal.t_str; t->name != NULL; t++, ts++) {
 
 1313                         ub = ct_encode_string(ct_visual_string(
 
 1314                             ct_decode_string(*ts, &el->el_scratch)),
 
 1319                 (void) fprintf(el->el_outfile, 
"\t%25s (%s) == %s\n",
 
 1320                     t->long_name, t->name, ub);
 
 1322         (void) fputc(
'\n', el->el_outfile);
 
 1332 terminal_settc(
EditLine *el, 
int argc __attribute__((__unused__)),
 
 1337         char what[8], how[8];
 
 1339         if (argv == NULL || argv[1] == NULL || argv[2] == NULL)
 
 1342         strncpy(what, ct_encode_string(argv[1], &el->el_scratch), 
sizeof(what));
 
 1343         what[
sizeof(what) - 1] = 
'\0';
 
 1344         strncpy(how,  ct_encode_string(argv[2], &el->el_scratch), 
sizeof(how));
 
 1345         how[
sizeof(how) - 1] = 
'\0';
 
 1350         for (ts = tstr; ts->name != NULL; ts++)
 
 1351                 if (strcmp(ts->name, what) == 0)
 
 1354         if (ts->name != NULL) {
 
 1355                 terminal_alloc(el, ts, how);
 
 1356                 terminal_setflags(el);
 
 1362         for (tv = tval; tv->name != NULL; tv++)
 
 1363                 if (strcmp(tv->name, what) == 0)
 
 1366         if (tv->name != NULL)
 
 1369         if (tv == &tval[T_pt] || tv == &tval[T_km] ||
 
 1370             tv == &tval[T_am] || tv == &tval[T_xn]) {
 
 1371                 if (strcmp(how, 
"yes") == 0)
 
 1372                         el->el_terminal.t_val[tv - tval] = 1;
 
 1373                 else if (strcmp(how, 
"no") == 0)
 
 1374                         el->el_terminal.t_val[tv - tval] = 0;
 
 1376                         (void) fprintf(el->el_errfile,
 
 1377                             "" FSTR 
": Bad value `%s'.\n", argv[0], how);
 
 1380                 terminal_setflags(el);
 
 1381                 if (terminal_change_size(el, 
Val(T_li), 
Val(T_co)) == -1)
 
 1388                 i = strtol(how, &ep, 10);
 
 1390                         (void) fprintf(el->el_errfile,
 
 1391                             "" FSTR 
": Bad value `%s'.\n", argv[0], how);
 
 1394                 el->el_terminal.t_val[tv - tval] = (int) i;
 
 1395                 el->el_terminal.t_size.v = 
Val(T_co);
 
 1396                 el->el_terminal.t_size.h = 
Val(T_li);
 
 1397                 if (tv == &tval[T_co] || tv == &tval[T_li])
 
 1398                         if (terminal_change_size(el, 
Val(T_li), 
Val(T_co))
 
 1411 terminal_gettc(
EditLine *el, 
int argc __attribute__((__unused__)), 
char **argv)
 
 1418         if (argv == NULL || argv[1] == NULL || argv[2] == NULL)
 
 1427         for (ts = tstr; ts->name != NULL; ts++)
 
 1428                 if (strcmp(ts->name, what) == 0)
 
 1431         if (ts->name != NULL) {
 
 1432                 *(
char **)how = el->el_terminal.t_str[ts - tstr];
 
 1438         for (tv = tval; tv->name != NULL; tv++)
 
 1439                 if (strcmp(tv->name, what) == 0)
 
 1442         if (tv->name == NULL)
 
 1445         if (tv == &tval[T_pt] || tv == &tval[T_km] ||
 
 1446             tv == &tval[T_am] || tv == &tval[T_xn]) {
 
 1447                 static char yes[] = 
"yes";
 
 1448                 static char no[] = 
"no";
 
 1449                 if (el->el_terminal.t_val[tv - tval])
 
 1450                         *(
char **)how = yes;
 
 1455                 *(
int *)how = el->el_terminal.t_val[tv - tval];
 
 1465 terminal_echotc(
EditLine *el, 
int argc __attribute__((__unused__)),
 
 1470         int arg_need, arg_cols, arg_rows;
 
 1471         int verbose = 0, silent = 0;
 
 1473         static const char fmts[] = 
"%s\n", fmtd[] = 
"%d\n";
 
 1475         char buf[TC_BUFSIZE];
 
 1480         if (argv == NULL || argv[1] == NULL)
 
 1484         if (argv[0][0] == 
'-') {
 
 1485                 switch (argv[0][1]) {
 
 1498         if (!*argv || *argv[0] == 
'\0')
 
 1500         if (Strcmp(*argv, STR(
"tabs")) == 0) {
 
 1501                 (void) fprintf(el->el_outfile, fmts, EL_CAN_TAB ? 
"yes" : 
"no");
 
 1503         } 
else if (Strcmp(*argv, STR(
"meta")) == 0) {
 
 1504                 (void) fprintf(el->el_outfile, fmts, 
Val(T_km) ? 
"yes" : 
"no");
 
 1506         } 
else if (Strcmp(*argv, STR(
"xn")) == 0) {
 
 1507                 (void) fprintf(el->el_outfile, fmts, EL_HAS_MAGIC_MARGINS ?
 
 1510         } 
else if (Strcmp(*argv, STR(
"am")) == 0) {
 
 1511                 (void) fprintf(el->el_outfile, fmts, EL_HAS_AUTO_MARGINS ?
 
 1514         } 
else if (Strcmp(*argv, STR(
"baud")) == 0) {
 
 1515                 (void) fprintf(el->el_outfile, fmtd, (
int)el->el_tty.t_speed);
 
 1517         } 
else if (Strcmp(*argv, STR(
"rows")) == 0 ||
 
 1518                    Strcmp(*argv, STR(
"lines")) == 0) {
 
 1519                 (void) fprintf(el->el_outfile, fmtd, 
Val(T_li));
 
 1521         } 
else if (Strcmp(*argv, STR(
"cols")) == 0) {
 
 1522                 (void) fprintf(el->el_outfile, fmtd, 
Val(T_co));
 
 1529         for (t = tstr; t->name != NULL; t++)
 
 1531                     ct_encode_string(*argv, &el->el_scratch)) == 0) {
 
 1532                         scap = el->el_terminal.t_str[t - tstr];
 
 1535         if (t->name == NULL) {
 
 1537                 scap = tgetstr(ct_encode_string(*argv, &el->el_scratch), &area);
 
 1539         if (!scap || scap[0] == 
'\0') {
 
 1541                         (void) fprintf(el->el_errfile,
 
 1542                             "echotc: Termcap parameter `" FSTR 
"' not found.\n",
 
 1549         for (cap = scap, arg_need = 0; *cap; cap++)
 
 1572                                         (void) fprintf(el->el_errfile,
 
 1573                                 "echotc: Warning: unknown termcap %% `%c'.\n",
 
 1582                 if (*argv && *argv[0]) {
 
 1584                                 (void) fprintf(el->el_errfile,
 
 1585                                     "echotc: Warning: Extra argument `" FSTR 
"'.\n",
 
 1589                 terminal_tputs(el, scap, 1);
 
 1593                 if (!*argv || *argv[0] == 
'\0') {
 
 1595                                 (void) fprintf(el->el_errfile,
 
 1596                                     "echotc: Warning: Missing argument.\n");
 
 1600                 i = Strtol(*argv, &ep, 10);
 
 1601                 if (*ep != 
'\0' || i < 0) {
 
 1603                                 (void) fprintf(el->el_errfile,
 
 1604                                     "echotc: Bad value `" FSTR 
"' for rows.\n",
 
 1610                 if (*argv && *argv[0]) {
 
 1612                                 (void) fprintf(el->el_errfile,
 
 1613                                     "echotc: Warning: Extra argument `" FSTR
 
 1617                 terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), 1);
 
 1622                         (void) fprintf(el->el_errfile,
 
 1623                          "echotc: Warning: Too many required arguments (%d).\n",
 
 1628                 if (!*argv || *argv[0] == 
'\0') {
 
 1630                                 (void) fprintf(el->el_errfile,
 
 1631                                     "echotc: Warning: Missing argument.\n");
 
 1634                 i = Strtol(*argv, &ep, 10);
 
 1635                 if (*ep != 
'\0' || i < 0) {
 
 1637                                 (void) fprintf(el->el_errfile,
 
 1638                                     "echotc: Bad value `" FSTR 
"' for cols.\n",
 
 1644                 if (!*argv || *argv[0] == 
'\0') {
 
 1646                                 (void) fprintf(el->el_errfile,
 
 1647                                     "echotc: Warning: Missing argument.\n");
 
 1650                 i = Strtol(*argv, &ep, 10);
 
 1651                 if (*ep != 
'\0' || i < 0) {
 
 1653                                 (void) fprintf(el->el_errfile,
 
 1654                                     "echotc: Bad value `" FSTR 
"' for rows.\n",
 
 1661                                 (void) fprintf(el->el_errfile,
 
 1662                                     "echotc: Bad value `" FSTR 
"'.\n", *argv);
 
 1666                 if (*argv && *argv[0]) {
 
 1668                                 (void) fprintf(el->el_errfile,
 
 1669                                     "echotc: Warning: Extra argument `" FSTR
 
 1673                 terminal_tputs(el, tgoto(scap, arg_cols, arg_rows), arg_rows);