diff options
author | Steve Slaven <bpk@hoopajoo.net> | 2019-11-05 06:26:14 (GMT) |
---|---|---|
committer | Steve Slaven <bpk@hoopajoo.net> | 2019-11-05 06:26:14 (GMT) |
commit | 9c4c0a1e366b9d932e4ab2ce03a0e80126d93d9b (patch) | |
tree | 928e4c6f49ac50f7e69777b00073df37d7d11e3f /tty.c | |
parent | eb9898c7fcc017a35c240c1bd83c8a8ff451431a (diff) | |
download | powwow-9c4c0a1e366b9d932e4ab2ce03a0e80126d93d9b.zip powwow-9c4c0a1e366b9d932e4ab2ce03a0e80126d93d9b.tar.gz powwow-9c4c0a1e366b9d932e4ab2ce03a0e80126d93d9b.tar.bz2 |
reorganizing files
Diffstat (limited to 'tty.c')
-rw-r--r-- | tty.c | 1038 |
1 files changed, 0 insertions, 1038 deletions
@@ -1,1038 +0,0 @@ -/* - * tty.c -- terminal handling routines for powwow - * - * Copyright (C) 1998 by Massimiliano Ghilardi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ -#include <alloca.h> -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> - -#ifdef USE_LOCALE -#include <wchar.h> -#include <locale.h> -#endif - -#include "defines.h" -#include "main.h" -#include "edit.h" -#include "utils.h" -#include "list.h" -#include "tty.h" -#include "tcp.h" - -#ifndef USE_SGTTY -# ifdef APOLLO -# include "/sys5.3/usr/include/sys/termio.h" -# else -/* - * including both termio.h and termios.h might be an overkill, and gives - * many warnings, but seems to be necessary at times. works anyway. - */ -# include <termios.h> -# include <termio.h> -# endif -/* #else USE_SGTTY */ -#endif - -/* - * SunOS 4 doesn't have function headers and has the defs needed from - * ioctl.h in termios.h. Does it compile with USE_SGTTY? - */ -#if (defined(sun) && defined(sparc) && ! defined(__SVR4)) - extern int printf(); -#else -# include <sys/ioctl.h> -#endif - -#ifdef BSD_LIKE -# include <sys/ioctl_compat.h> -# define O_RAW RAW -# define O_ECHO ECHO -# define O_CBREAK CBREAK -#endif - -#if defined(TCSETS) || defined(TCSETATTR) -# ifndef TCSETS /* cc for HP-UX SHOULD define this... */ -# define TCSETS TCSETATTR -# define TCGETS TCGETATTR -# endif -typedef struct termios termiostruct; -#else -# define TCSETS TCSETA -# define TCGETS TCGETA -typedef struct termio termiostruct; -#endif - -#ifdef VSUSP -# define O_SUSP VSUSP -#else -# ifdef SWTCH -# define O_SUSP SWTCH -# else -# define O_SUSP SUSP -# endif -#endif - -/* int ioctl(); */ - -#ifdef USE_VT100 /* hard-coded vt100 features if no termcap: */ - -static char kpadstart[] = "", kpadend[] = "", begoln[] = "\r", - clreoln[] = "\033[K", clreoscr[] = "\033[J", - leftcur[] = "\033[D", rightcur[] = "\033[C", upcur[] = "\033[A", - modebold[] = "\033[1m", modeblink[] = "\033[5m", modeinv[] = "\033[7m", - modeuline[] = "\033[4m", modestandon[] = "", modestandoff[] = "", - modenorm[] = "\033[m", modenormbackup[4], - cursor_left[] = "\033[D", cursor_right[] = "\033[C", - cursor_up[] = "\033[A", cursor_down[] = "\033[B"; - -#define insertfinish (0) -static int len_begoln = 1, len_leftcur = 3, len_upcur = 3, gotocost = 8; - -#else /* not USE_VT100, termcap function declarations */ - -int tgetent(); -int tgetnum(); -int tgetflag(); -char *tgetstr(); -char *tgoto(); - -/* terminal escape sequences */ -static char kpadstart[CAPLEN], kpadend[CAPLEN], - leftcur[CAPLEN], rightcur[CAPLEN], upcur[CAPLEN], curgoto[CAPLEN], - delchar[CAPLEN], insstart[CAPLEN], insstop[CAPLEN], - inschar[CAPLEN], - begoln[CAPLEN], clreoln[CAPLEN], clreoscr[CAPLEN], - cursor_left[CAPLEN], cursor_right[CAPLEN], cursor_up[CAPLEN], - cursor_down[CAPLEN]; - -/* attribute changers: */ -static char modebold[CAPLEN], modeblink[CAPLEN], modeinv[CAPLEN], - modeuline[CAPLEN], modestandon[CAPLEN], modestandoff[CAPLEN], - modenorm[CAPLEN], modenormbackup[CAPLEN]; - -static int len_begoln, len_clreoln, len_leftcur, len_upcur, gotocost, - deletecost, insertcost, insertfinish, inscharcost; - -static int extract(char *cap, char *buf); - -#endif /* USE_VT100 */ - - -char *tty_modebold = modebold, *tty_modeblink = modeblink, - *tty_modeinv = modeinv, *tty_modeuline = modeuline, - *tty_modestandon = modestandon, *tty_modestandoff = modestandoff, - *tty_modenorm = modenorm, *tty_modenormbackup = modenormbackup, - *tty_begoln = begoln, *tty_clreoln = clreoln, - *tty_clreoscr = clreoscr; - -int tty_read_fd = 0; -static int wrapglitch = 0; - -#ifdef USE_LOCALE -FILE *tty_read_stream; -static int orig_read_fd_fl; -static struct { - mbstate_t mbstate; /* multibyte output shift state */ - char data[4096]; /* buffer for pending data */ - size_t used; /* bytes used of data */ - int fd; /* file descriptor to write to */ -} tty_write_state; -#endif /* USE_LOCALE */ - -#ifdef USE_SGTTY -static struct sgttyb ttybsave; -static struct tchars tcsave; -static struct ltchars ltcsave; -#else /* not USE_SGTTY */ -static termiostruct ttybsave; -#endif /* USE_SGTTY */ - -/* - * Terminal handling routines: - * These are one big mess of left-justified chicken scratches. - * It should be handled more cleanly...but unix portability is what it is. - */ - -/* - * Set the terminal to character-at-a-time-without-echo mode, and save the - * original state in ttybsave - */ -void tty_start(void) -{ -#ifdef USE_SGTTY - struct sgttyb ttyb; - struct ltchars ltc; - ioctl(tty_read_fd, TIOCGETP, &ttybsave); - ioctl(tty_read_fd, TIOCGETC, &tcsave); - ioctl(tty_read_fd, TIOCGLTC, <csave); - ttyb = ttybsave; - ttyb.sg_flags = (ttyb.sg_flags|O_CBREAK) & ~O_ECHO; - ioctl(tty_read_fd, TIOCSETP, &ttyb); - ltc = ltcsave; - ltc.t_suspc = -1; - ioctl(tty_read_fd, TIOCSLTC, <c); -#else /* not USE_SGTTY */ - termiostruct ttyb; - ioctl(tty_read_fd, TCGETS, &ttyb); - ttybsave = ttyb; - ttyb.c_lflag &= ~(ECHO|ICANON); - ttyb.c_cc[VTIME] = 0; - ttyb.c_cc[VMIN] = 1; - /* disable the special handling of the suspend key (handle it ourselves) */ - ttyb.c_cc[O_SUSP] = 0; - ioctl(tty_read_fd, TCSETS, &ttyb); -#endif /* USE_SGTTY */ - -#ifdef USE_LOCALE - orig_read_fd_fl = fcntl(tty_read_fd, F_GETFL); - fcntl(tty_read_fd, F_SETFL, O_NONBLOCK | orig_read_fd_fl); -#endif - - tty_puts(kpadstart); - tty_flush(); - -#ifdef USE_LOCALE - tty_write_state.fd = 1; - wcrtomb(NULL, L'\0', &tty_write_state.mbstate); -#else /* ! USE_LOCALE */ - #ifdef DEBUG_TTY - setvbuf(stdout, NULL, _IONBF, BUFSIZ); - #else - setvbuf(stdout, NULL, _IOFBF, BUFSIZ); - #endif -#endif /* ! USE_LOCALE */ -} - -/* - * Reset the terminal to its original state - */ -void tty_quit(void) -{ -#ifdef USE_SGTTY - ioctl(tty_read_fd, TIOCSETP, &ttybsave); - ioctl(tty_read_fd, TIOCSETC, &tcsave); - ioctl(tty_read_fd, TIOCSLTC, <csave); -#else /* not USE_SGTTY */ - ioctl(tty_read_fd, TCSETS, &ttybsave); -#endif /* USE_SGTTY */ - tty_puts(kpadend); - tty_flush(); -#ifdef USE_LOCALE - fcntl(tty_read_fd, F_SETFL, orig_read_fd_fl); -#endif -} - -/* - * enable/disable special keys depending on the current linemode - */ -void tty_special_keys(void) -{ -#ifdef USE_SGTTY - struct tchars tc = {-1, -1, -1, -1, -1, -1}; - struct ltchars ltc = {-1, -1, -1, -1, -1, -1}; - struct sgttyb ttyb; - ioctl(tty_read_fd, TIOCGETP, &ttyb); - if (linemode & LM_CHAR) { - /* char-by-char mode: set RAW mode*/ - ttyb.sg_flags |= RAW; - } else { - /* line-at-a-time mode: enable spec keys, disable RAW */ - tc = tcsave; - ltc = ltcsave; - ltc.t_suspc = -1; /* suspend key remains disabled */ - ttyb.sg_flags &= ~RAW; - } - ioctl(tty_read_fd, TIOCSETP, &ttyb); - ioctl(tty_read_fd, TIOCSETC, &tc); - ioctl(tty_read_fd, TIOCSLTC, <c); -#else /* not USE_SGTTY */ - int i; - termiostruct ttyb; - ioctl(tty_read_fd, TCGETS, &ttyb); - if (linemode & LM_CHAR) { - /* char-by-char mode: disable all special keys and set raw mode */ - for(i = 0; i < NCCS; i++) - ttyb.c_cc[i] = 0; - ttyb.c_oflag &= ~OPOST; - } else { - /* line at a time mode: enable them, except suspend */ - for(i = 0; i < NCCS; i++) - ttyb.c_cc[i] = ttybsave.c_cc[i]; - /* disable the suspend key (handle it ourselves) */ - ttyb.c_cc[O_SUSP] = 0; - /* set cooked mode */ - ttyb.c_oflag |= OPOST; - } - ioctl(tty_read_fd, TCSETS, &ttyb); -#endif /* USE_SGTTY */ -} - -/* - * get window size and react to any window size change - */ -void tty_sig_winch_bottomhalf(void) -{ - struct winsize wsiz; - /* if ioctl fails or gives silly values, don't change anything */ - - if (ioctl(tty_read_fd, TIOCGWINSZ, &wsiz) == 0 - && wsiz.ws_row > 0 && wsiz.ws_col > 0 - && (lines != wsiz.ws_row || cols != wsiz.ws_col)) - { - lines = wsiz.ws_row; - cols_1 = cols = wsiz.ws_col; - if (!wrapglitch) - cols_1--; - - if (tcp_main_fd != -1) - tcp_write_tty_size(); - line0 += lines - olines; - - tty_gotoxy(0, line0); - /* so we know where the cursor is */ -#ifdef BUG_ANSI - if (edattrbg) - tty_printf("%s%s", edattrend, tty_clreoscr); - else -#endif - tty_puts(tty_clreoscr); - - olines = lines; - status(1); - } -} - -/* - * read termcap definitions - */ -void tty_bootstrap(void) -{ -#ifdef USE_LOCALE - tty_read_stream = stdin; -#endif - -#ifndef USE_VT100 - struct tc_init_node { - char cap[4], *buf; - int *len, critic; - }; - static struct tc_init_node tc_init[] = { - { "cm", curgoto, 0, 1 }, - { "ce", clreoln, &len_clreoln, 1 }, - { "cd", clreoscr, 0, 1 }, - { "nd", rightcur, 0, 1 }, - { "le", leftcur, &len_leftcur, 0 }, - { "up", upcur, &len_upcur, 0 }, - { "cr", begoln, &len_begoln, 0 }, - { "ic", inschar, &inscharcost, 0 }, - { "im", insstart, &insertcost, 0 }, - { "ei", insstop, &insertcost, 0 }, - { "dm", delchar, &deletecost, 0 }, - { "dc", delchar, &deletecost, 0 }, - { "ed", delchar, &deletecost, 0 }, - { "me", modenorm, 0, 0 }, - { "md", modebold, 0, 0 }, - { "mb", modeblink, 0, 0 }, - { "mr", modeinv, 0, 0 }, - { "us", modeuline, 0, 0 }, - { "so", modestandon, 0, 0 }, - { "se", modestandoff, 0, 0 }, - { "ks", kpadstart, 0, 0 }, - { "ke", kpadend, 0, 0 }, - { "kl", cursor_left, 0, 0 }, - { "kr", cursor_right, 0, 0 }, - { "ku", cursor_up, 0, 0 }, - { "kd", cursor_down, 0, 0 }, - { "", NULL, 0, 0 } - }; - struct tc_init_node *np; - char tcbuf[2048]; /* by convention, this is enough */ - int i; -#endif /* not USE_VT100 */ -#if !defined(USE_VT100) || defined(BUG_TELNET) - char *term = getenv("TERM"); - if (!term) { - fprintf(stderr, "$TERM not set\n"); - exit(1); - } -#endif /* !defined(USE_VT100) || defined(BUG_TELNET) */ -#ifdef USE_VT100 - cols = 80; -# ifdef LINES - lines = LINES; -# else /* not LINES */ - lines = 24; -# endif /* LINES */ -#else /* not USE_VT100 */ - switch(tgetent(tcbuf, term)) { - case 1: - break; - case 0: - fprintf(stderr, - "There is no entry for \"%s\" in the terminal data base.\n", term); - fprintf(stderr, - "Please set your $TERM environment variable correctly.\n"); - exit(1); - default: - syserr("tgetent"); - } - for(np = tc_init; np->cap[0]; np++) - if ((i = extract(np->cap, np->buf))) { - if (np->len) *np->len += i; - } else if (np->critic) { - fprintf(stderr, - "Your \"%s\" terminal is not powerful enough, missing \"%s\".\n", - term, np->cap); - exit(1); - } - if (!len_begoln) - strcpy(begoln, "\r"), len_begoln = 1; - if (!len_leftcur) - strcpy(leftcur, "\b"), len_leftcur = 1; - - gotocost = strlen(tgoto(curgoto, cols - 1, lines - 1)); - insertfinish = gotocost + len_clreoln; - - /* this must be before getting window size */ - wrapglitch = tgetflag("xn"); - - tty_sig_winch_bottomhalf(); /* get window size */ - -#endif /* not USE_VT100 */ - strcpy(modenormbackup, modenorm); -#ifdef BUG_TELNET - if (strncmp(term, "vt10", 4) == 0) { - /* might be NCSA Telnet 2.2 for PC, which doesn't reset colours */ - sprintf(modenorm, "\033[;%c%d;%s%dm", - DEFAULTFG<LOWCOLORS ? '3' : '9', DEFAULTFG % LOWCOLORS, - DEFAULTBG<LOWCOLORS ? "4" : "10", DEFAULTBG % LOWCOLORS); - } -#endif /* BUG_TELNET */ -} - -/* - * add the default keypad bindings to the list - */ -void tty_add_walk_binds(void) -{ - /* - * Note: termcap doesn't have sequences for the numeric keypad, so we just - * assume they are the same as for a vt100. They can be redefined - * at runtime anyway (using #bind or #rebind) - */ - add_keynode("KP2", "\033Or", 0, key_run_command, "s"); - add_keynode("KP3", "\033Os", 0, key_run_command, "d"); - add_keynode("KP4", "\033Ot", 0, key_run_command, "w"); - add_keynode("KP5", "\033Ou", 0, key_run_command, "exits"); - add_keynode("KP6", "\033Ov", 0, key_run_command, "e"); - add_keynode("KP7", "\033Ow", 0, key_run_command, "look"); - add_keynode("KP8", "\033Ox", 0, key_run_command, "n"); - add_keynode("KP9", "\033Oy", 0, key_run_command, "u"); -} - -/* - * initialize the key binding list - */ -void tty_add_initial_binds(void) -{ - struct b_init_node { - char *label, *seq; - function_any funct; - }; - static struct b_init_node b_init[] = { - { "LF", "\n", enter_line }, - { "Ret", "\r", enter_line }, - { "BS", "\b", del_char_left }, - { "Del", "\177", del_char_left }, - { "Tab", "\t", complete_word }, - { "C-a", "\001", begin_of_line }, - { "C-b", "\002", prev_char }, - { "C-d", "\004", del_char_right }, - { "C-e", "\005", end_of_line }, - { "C-f", "\006", next_char }, - { "C-k", "\013", kill_to_eol }, - { "C-l", "\014", redraw_line }, - { "C-n", "\016", next_line }, - { "C-p", "\020", prev_line }, - { "C-t", "\024", transpose_chars }, - { "C-w", "\027", to_history }, - { "C-z", "\032", suspend_powwow }, - { "M-Tab", "\033\t", complete_line }, - { "M-b", "\033b", prev_word }, - { "M-d", "\033d", del_word_right }, - { "M-f", "\033f", next_word }, - { "M-k", "\033k", redraw_line_noprompt }, - { "M-t", "\033t", transpose_words }, - { "M-u", "\033u", upcase_word }, - { "M-l", "\033l", downcase_word }, - { "M-BS", "\033\b", del_word_left }, - { "M-Del", "\033\177", del_word_left }, - { "", "", 0 } - }; - struct b_init_node *p = b_init; - do { - add_keynode(p->label, p->seq, 0, p->funct, NULL); - } while((++p)->seq[0]); - - if (*cursor_left ) add_keynode("Left" , cursor_left , 0, prev_char, NULL); - if (*cursor_right) add_keynode("Right", cursor_right, 0, next_char, NULL); - if (*cursor_up ) add_keynode("Up" , cursor_up , 0, prev_line, NULL); - if (*cursor_down ) add_keynode("Down" , cursor_down , 0, next_line, NULL); -} - -#ifndef USE_VT100 -/* - * extract termcap 'cap' and strcat it to buf. - * return the lenght of the extracted string. - */ -static int extract(char *cap, char *buf) -{ - static char *bp; - char *d = buf + strlen(buf); - char *s = tgetstr(cap, (bp = d, &bp)); - int len; - if (!s) return (*bp = 0); - /* - * Remove the padding information. We assume that no terminals - * need padding nowadays. At least it makes things much easier. - */ - s += strspn(s, "0123456789*"); - for(len = 0; *s; *d++ = *s++, len++) - if (*s == '$' && *(s + 1) == '<') - if (!(s = strchr(s, '>')) || !*++s) break; - *d = 0; - return len; -} -#endif /* not USE_VT100 */ - -/* - * position the cursor using absolute coordinates - * note: does not flush the output buffer - */ -void tty_gotoxy(int col, int line) -{ -#ifdef USE_VT100 - tty_printf("\033[%d;%dH", line + 1, col + 1); -#else - tty_puts(tgoto(curgoto, col, line)); -#endif -} - -/* - * optimized cursor movement - * from (fromcol, fromline) to (tocol, toline) - * if tocol > 0, (tocol, toline) must lie on editline. - */ -void tty_gotoxy_opt(int fromcol, int fromline, int tocol, int toline) -{ - static char buf[BUFSIZE]; - char *cp = buf; - int cost, i, dist; - - CLIP(fromline, 0, lines-1); - CLIP(toline , 0, lines-1); - - /* First, move vertically to the correct line, then horizontally - * to the right column. If this turns out to be fewer characters - * than a direct cursor positioning (tty_gotoxy), use that. - */ - for (;;) { /* gotoless */ - if ((i = toline - fromline) < 0) { - if (!len_upcur || (cost = -i * len_upcur) >= gotocost) - break; - do { - strcpy(cp, upcur); - cp += len_upcur; - } while(++i); - } else if ((cost = 2 * i)) { /* lf is mapped to crlf on output */ - if (cost >= gotocost) - break; - do - *cp++ = '\n'; - while (--i); - fromcol = 0; - } - if ((i = tocol - fromcol) < 0) { - dist = -i * len_leftcur; - if (dist <= len_begoln + tocol) { - if ((cost += dist) > gotocost) - break; - do { - strcpy(cp, leftcur); - cp += len_leftcur; - } while(++i); - } else { - if ((cost += len_begoln) > gotocost) - break; - strcpy(cp, begoln); - cp += len_begoln; - fromcol = 0; i = tocol; - } - } - if (i) { - /* - * if hiliting in effect or prompt contains escape sequences, - * just use tty_gotoxy - */ - if (cost + i > gotocost || *edattrbeg || promptlen != col0) - break; - if (fromcol < col0 && toline == line0) { - strcpy(cp, promptstr+fromcol); - cp += promptlen-fromcol; - fromcol = col0; - } - my_strncpy(cp, edbuf + (toline - line0) * cols_1 + fromcol - col0, - tocol - fromcol); - cp += tocol - fromcol; - } - *cp = 0; - tty_puts(buf); - return; - } - tty_gotoxy(tocol, toline); -} - - -/* - * GH: change the position on input line (gotoxy there, and set pos) - * from cancan 2.6.3a - */ -void input_moveto(int new_pos) -{ - /* - * FEATURE: the line we are moving to might be less than 0, or greater - * than lines - 1, if the display is too small to hold the whole editline. - * In that case, the input line should be (partially) redrawn. - */ - if (new_pos < 0) - new_pos = 0; - else if (new_pos > edlen) - new_pos = edlen; - if (new_pos == pos) - return; - - if (line_status == 0) { - int fromline = CURLINE(pos), toline = CURLINE(new_pos); - if (toline < 0) - line0 -= toline, toline = 0; - else if (toline > lines - 1) - line0 -= toline - lines + 1, toline = lines - 1; - tty_gotoxy_opt(CURCOL(pos), fromline, CURCOL(new_pos), toline); - } - pos = new_pos; -} - -/* - * delete n characters at current position (the position is unchanged) - * assert(n < edlen - pos) - */ -void input_delete_nofollow_chars(int n) -{ - int r_cost, p = pos, d_cost; - int nl = pos - CURCOL(pos); /* this line's starting pos (can be <= 0) */ - int cl = CURLINE(pos); /* current line */ - - if (n > edlen - p) - n = edlen - p; - if (n <= 0) - return; - - d_cost = p + n; - if (line_status != 0) { - memmove(edbuf + p, edbuf + d_cost, edlen - d_cost + 1); - edlen -= n; - return; - } - - memmove(edbuf + p, edbuf + d_cost, edlen - d_cost); - memset(edbuf + edlen - n, (int)' ', n); - for (;; tty_putc('\n'), p = nl, cl++) { - d_cost = 0; - /* FEATURE: ought to be "d_cost = n > gotocost ? -gotocost : -n;" - * since redraw will need to goto back. Of little importance */ - if ((r_cost = edlen) > (nl += cols_1)) - r_cost = nl, d_cost = n + gotocost; - r_cost -= p; -#ifndef USE_VT100 - /* - * FEATURE: no clreoln is used (it might cost less in the occasion - * we delete more than one char). Simplicity - */ - if (deletecost && deletecost * n + d_cost < r_cost) { -#ifdef BUG_ANSI - if (edattrbg) - tty_puts(edattrend); -#endif - for (d_cost = n; d_cost; d_cost--) - tty_puts(delchar); -#ifdef BUG_ANSI - if (edattrbg) - tty_puts(edattrbeg); -#endif - - if (edlen <= nl) - break; - - tty_gotoxy(cols_1 - n, cl); - tty_printf("%.*s", n, edbuf + nl - n); - } else -#endif /* not USE_VT100 */ - { -#ifdef BUG_ANSI - if (edattrbg && p <= edlen - n && p + r_cost >= edlen - n) - tty_printf("%.*s%s%.*s", edlen - p - n, edbuf + p, - edattrend, - r_cost - edlen + p + n, edbuf + edlen - n); - else -#endif - tty_printf("%.*s", r_cost, edbuf + p); - - p += r_cost; - - if (edlen <= nl) { -#ifdef BUG_ANSI - if (edattrbg) - tty_puts(edattrbeg); -#endif - break; - } - } - } - edbuf[edlen -= n] = '\0'; - switch(pos - p) { - case 1: - tty_puts(leftcur); - break; - case 0: - break; - default: - tty_gotoxy_opt(CURCOL(p), cl, CURCOL(pos), CURLINE(pos)); - break; - } -} - -/* - * GH: print a char on current position (overwrite), advance position - * from cancan 2.6.3a - */ -void input_overtype_follow(char c) -{ - if (pos >= edlen) - return; - edbuf[pos++] = c; - - if (line_status == 0) { - tty_putc(c); - if (!CURCOL(pos)) { -#ifdef BUG_ANSI - if (edattrbg) - tty_printf("%s\n%s", edattrend, edattrbeg); - else -#endif - tty_putc('\n'); - } - } -} - -/* - * insert n characters at input line current position. - * The position is set to after the inserted characters. - */ -void input_insert_follow_chars(char *str, int n) -{ - int r_cost, i_cost, p = pos; - int nl = p - CURCOL(p); /* next line's starting pos */ - int cl = CURLINE(p); /* current line */ - - if (edlen + n >= BUFSIZE) - n = BUFSIZE - edlen - 1; - if (n <= 0) - return; - - memmove(edbuf + p + n, edbuf + p, edlen + 1 - p); - memmove(edbuf + p, str, n); - edlen += n; pos += n; - - if (line_status != 0) - return; - - do { - i_cost = n; - if ((r_cost = edlen) > (nl += cols_1)) - r_cost = nl, i_cost += insertfinish; - r_cost -= p; -#ifndef USE_VT100 - /* FEATURE: insert mode is used only when one char is inserted - (which is probably true > 95% of the time). Simplicity */ - if (n == 1 && inscharcost && inscharcost + i_cost < r_cost) { - tty_printf("%s%c", inschar, edbuf[p++]); - if (edlen > nl && !wrapglitch) { - tty_gotoxy(cols_1, cl); - tty_puts(clreoln); - } - } else -#endif /* not USE_VT100 */ - { - tty_printf("%.*s", r_cost, edbuf + p); p += r_cost; - } - if (edlen < nl) - break; -#ifdef BUG_ANSI - if (edattrbg) - tty_printf("%s\n%s", edattrend, edattrbeg); - else -#endif - tty_puts("\n"); - p = nl; - if (++cl > lines - 1) { - cl = lines - 1; - line0--; - } - } while (edlen > nl); - - if (p != pos) - tty_gotoxy_opt(CURCOL(p), cl, CURCOL(pos), CURLINE(pos)); -} - -#ifdef USE_LOCALE -/* curses wide character support by Dain */ - -void tty_puts(const char *s) -{ - while (*s) - tty_putc(*s++); -} - -void tty_putc(char c) -{ - size_t r; - int ignore_error = 0; - if (tty_write_state.used + MB_LEN_MAX > sizeof tty_write_state.data) - tty_flush(); -again: - r = wcrtomb(tty_write_state.data + tty_write_state.used, (unsigned char)c, - &tty_write_state.mbstate); - if (r == (size_t)-1) { - if (ignore_error) - return; - if (errno != EILSEQ) { - perror("mcrtomb()"); - abort(); - } - /* character cannot be represented; try to write a question - * mark instead, but ignore any errors */ - ignore_error = 1; - c = '?'; - goto again; - } - assert(r <= MB_LEN_MAX); - tty_write_state.used += r; -} - -int tty_printf(const char *format, ...) -{ - char buf[1024], *bufp = buf; - va_list va; - int res; - - char *old_locale = strdup(setlocale(LC_ALL, NULL)); - - setlocale(LC_ALL, "C"); - - va_start(va, format); - res = vsnprintf(buf, sizeof buf, format, va); - va_end(va); - - if (res >= sizeof buf) { - bufp = alloca(res + 1); - va_start(va, format); - vsprintf(bufp, format, va); - assert(strlen(bufp) == res); - va_end(va); - } - - setlocale(LC_ALL, old_locale); - free(old_locale); - - tty_puts(bufp); - - return res; -} - -static char tty_in_buf[MB_LEN_MAX + 1]; -static size_t tty_in_buf_used = 0; - -int tty_has_chars(void) -{ - return tty_in_buf_used != 0; -} - -static int safe_mbtowc(wchar_t *pwc, char *s, size_t *n) -{ - static mbstate_t ps; - - size_t r; - -again: - r = mbrtowc(pwc, s, *n, &ps); - if (r == (size_t)-2) { - /* incomplete character */ - *n = 0; - return -1; - } - if (r == (size_t)-1 && errno == EILSEQ) { - /* invalid character */ - --*n; - memmove(s, s + 1, *n); - goto again; - } - if (r == 0 && n > 0 && s[0] == 0) { - *pwc = L'\0'; - r = 1; - } - return r; -} - -int tty_read(char *buf, size_t count) -{ - int result = 0; - int converted; - wchar_t wc; - int did_read = 0, should_read = 0; - - if (count && tty_in_buf_used) { - converted = safe_mbtowc(&wc, tty_in_buf, &tty_in_buf_used); - if (converted >= 0) - goto another; - } - - while (count) { - should_read = sizeof tty_in_buf - tty_in_buf_used; - did_read = read(tty_read_fd, tty_in_buf + tty_in_buf_used, - should_read); - - if (did_read < 0 && errno == EINTR) - continue; - if (did_read <= 0) - break; - - tty_in_buf_used += did_read; - - converted = safe_mbtowc(&wc, tty_in_buf, &tty_in_buf_used); - if (converted < 0) - break; - - another: - if (converted == 0) - converted = 1; - - if (!(wc & ~0xff)) { - *buf++ = (unsigned char)wc; - --count; - ++result; - } - - tty_in_buf_used -= converted; - memmove(tty_in_buf, tty_in_buf + converted, tty_in_buf_used); - - if (count == 0) - break; - - converted = safe_mbtowc(&wc, tty_in_buf, &tty_in_buf_used); - if (converted >= 0 && tty_in_buf_used) - goto another; - - if (did_read < should_read) - break; - } - - return result; -} - - -void tty_gets(char *s, int size) -{ - wchar_t *ws = alloca(size * sizeof *ws); - - if (!fgetws(ws, size, stdin)) - return; - - while (*ws) { - if (!(*ws & ~0xff)) - *s++ = (unsigned char)*ws; - ++ws; - } -} - -void tty_flush(void) -{ - size_t n = tty_write_state.used; - char *data = tty_write_state.data; - while (n > 0) { - ssize_t r; - for (;;) { - r = write(tty_write_state.fd, data, n); - if (r >= 0) - break; - if (errno == EINTR) - continue; - if (errno != EAGAIN) { - fprintf(stderr, "Cannot write to tty: %s\n", strerror(errno)); - abort(); - } - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(tty_write_state.fd, &wfds); - do { - r = select(tty_write_state.fd + 1, NULL, &wfds, NULL, NULL); - } while (r < 0 && errno == EINTR); - if (r <= 0) { - fprintf(stderr, "Cannot write to tty; select failed: %s\n", - r == 0 ? "returned zero" : strerror(errno)); - abort(); - } - } - if (r < 0) { - fprintf(stderr, "Cannot write to tty: %s\n", strerror(errno)); - abort(); - } - n -= r; - data += r; - } - tty_write_state.used = 0; -} - -void tty_raw_write(char *data, size_t len) -{ - if (len == 0) return; - - for (;;) { - size_t s = sizeof tty_write_state.data - tty_write_state.used; - if (s > len) s = len; - memcpy(tty_write_state.data + tty_write_state.used, data, s); - len -= s; - tty_write_state.used += s; - if (len == 0) - break; - data += s; - tty_flush(); - } -} - -#endif /* USE_LOCALE */ |