aboutsummaryrefslogtreecommitdiffstats
path: root/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'tty.c')
-rw-r--r--tty.c1038
1 files changed, 0 insertions, 1038 deletions
diff --git a/tty.c b/tty.c
deleted file mode 100644
index 104c780..0000000
--- a/tty.c
+++ /dev/null
@@ -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, &ltcsave);
- 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, &ltc);
-#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, &ltcsave);
-#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, &ltc);
-#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 */