/*
* term.c: all the routines we need to do our stuff with the screen.
*
* Copyright(c) 1997-2000 - All Rights Reserved
*
* See the COPYRIGHT file.
*/
#ifndef lint
static char rcsid[] = "@(#)$Id: term.c,v 1.24 2000/07/31 22:33:56 kalt Exp $";
#endif
#include "os.h"
#include "term.h"
static struct termios oldt, newt;
static int mytty;
int LI, /* number of lines */
CO; /* number of columns */
char *CM, /* screen-relative cursor motion */
*ND, /* non destructive space (cursor right) */
*LE, /* move cursor left one position */
*CE, /* clear to end of line */
*CL, /* clear screen and home cursor */
*DC, /* delete character */ /* UNUSED */
*IC, /* insert character */ /* UNUSED */
*SO, *SE, /* begin and end standout mode */
*US, *UE, /* start and end underscore mode */
*MD, /* turn on extra bright (bold) */
*ME, /* turn off all attributes */
*CS, /* change scrolling region (vt100) */
*SF, /* scroll text up */
*NL, /* newline character */
*SR, /* scroll text down */
*BL; /* bell */
/*
* terminal initialization
* read termcap, setup the terminal the way we want it to be..
*/
void
term_init()
{
static char termcap[2048];
char area[1024], *term, *ptr;
int i = 0, missing = 0;
char *cap_name[] = { "cm", "nd", "le", "ce", "cl", "dc", "ic", "so", "se", "us", "ue", "md", "me", "cs", "sf", "nl", "sr", "bl", 0 };
char **cap_var[] = { &CM, &ND, &LE, &CE, &CL, &DC, &IC, &SO, &SE, &US, &UE, &MD, &ME, &CS, &SF, &NL, &SR, &BL };
/* Open the tty. Using it might not be necessary, but won't hurt */
mytty = open("/dev/tty", O_RDWR, 0);
if (mytty < 0)
{
perror("Unable to open /dev/tty");
exit(1);
}
/* Get all the info we need from the termcap entry */
if ((term = getenv("TERM")) == NULL)
{
fprintf(stderr, "TERM variable is not set!\n");
exit(1);
}
if (tgetent(termcap, term) < 1)
{
fprintf(stderr, "No TERMCAP entry for ``%s''.\n", term);
exit(1);
}
ptr = area;
if ((CO = tgetnum("co")) == -1) CO = 80;
if ((LI = tgetnum("li")) == -1) LI = 24;
while (cap_name[i])
{
*(cap_var[i]) = (char *) tgetstr(cap_name[i], &ptr);
if (strcmp(cap_name[i], "nl") && strcmp(cap_name[i], "bl")
&& *(cap_var[i]) == NULL)
{
missing += 1;
fprintf(stderr, "%s is undefined for this terminal.\n", cap_name[i]);
}
i += 1;
}
if (NL == NULL) NL = "\n";
if (BL == NULL) BL = "\007";
if (IC == NULL) missing -= 1; /* unused */
if (DC == NULL) missing -= 1; /* unused */
if (missing)
{
fprintf(stderr, "Things will probably not work well, but might be easy to fix.\n");
sleep(2);
}
if (SO == NULL || SE == NULL) { SO = ""; SE = ""; }
if (US == NULL || UE == NULL) { US = ""; UE = ""; }
if (MD == NULL || ME == NULL) { MD = ""; ME = ""; }
/* let's try to avoid silly crashes */
i = -1;
while (cap_name[++i])
if (*(cap_var[i]) == NULL)
*(cap_var[i]) = "";
tcgetattr(mytty, &oldt); /* save the tty settings */
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO); /* cbreak() noecho() */
newt.c_cc[VMIN] = 1; /* read() returns if >= 1 char */
newt.c_cc[VTIME] = 0; /* no timer on read() */
tcsetattr(mytty, TCSADRAIN, &newt); /* setup tty the way we like it */
term_size(); /* try to get the size, really */
term_clear(); /* clear the screen */
}
/* terminal reinitialization */
void
term_reinit()
{
tcsetattr(mytty, TCSADRAIN, &newt);
}
/* term_size: try to get the terminal size
* returns 0 if same as before
* returns 1 if changed
* returns -1 if ioctl() failed.
* returns -2 if no TIOCGWINSZ to get size
*/
int
term_size()
{
#if defined(TIOCGWINSZ)
struct winsize ws;
int nLI = LI, nCO = CO, ret = 0;
if (ioctl(mytty, TIOCGWINSZ, &ws) < 0)
return -1;
if (ws.ws_row)
nLI = ws.ws_row;
if (ws.ws_col)
nCO = ws.ws_col;
if (LI != nLI || CO != nCO)
ret = 1;
LI = nLI; CO = nCO;
return ret;
#else
return -2;
#endif
}
/* restore the terminal to what it was before */
void
term_end()
{
term_move_cursor(0, LI-1); /* last line */
term_clreol(); /* clear it */
sic_tputs(tgoto(CS, LI-1, 0)); /* reset scrolling region */
term_move_cursor(0, LI-1); /* go to last line again */
tcsetattr(mytty, TCSADRAIN, &oldt); /* reset tty settings */
fflush(stdout);
}
/* display a character on the screen.
* control characters are displayed in reverse video uppercase letters
*/
void
term_putchar(c)
unsigned int c;
{
if (c < 32)
{
term_standout_on();
c = (c & 127) | 64;
fputc(c, stdout);
term_standout_off();
}
else if (c == '\177')
{
term_standout_on();
c = '?';
fputc(c, stdout);
term_standout_off();
}
else
fputc(c, stdout);
}
/* display up to len characters from the string str on the screen */
int
term_puts(str, len)
char *str;
int len;
{
int i;
for (i = 0; *str && (i < len); str++, i++)
term_putchar(*str);
return (i);
}
/* display up to len characters from the string str on the screen
* the attr argument is optional, it's used for video attributes
* attrmask is a mask to be used on attributes
*/
int
term_putes(str, len, attr, attrmask)
char *str;
u_char *attr;
u_int attrmask;
int len;
{
int i;
u_char *ap = attr, av, hidden = 0;
unsigned int video = 0;
for (i = 0; *str && (i < len); ap++, str++, i++)
{
av = 0;
if (attr)
{
av = *ap & attrmask;
av = (av & 0x0F) | ((av & 0xF0) >> 4);
if (av & TERM_HIDE)
{
hidden = 1;
continue;
}
if (av & TERM_BOLD)
{
if (!(video & TERM_BOLD))
{
term_bold_on();
video |= TERM_BOLD;
}
}
else
if (video & TERM_BOLD)
{
term_bold_off();
video ^= TERM_BOLD;
}
if (av & TERM_STANDOUT)
{
if (!(video & TERM_STANDOUT))
{
term_standout_on();
video |= TERM_STANDOUT;
}
}
else
if (video & TERM_STANDOUT)
{
term_standout_off();
video ^= TERM_STANDOUT;
}
if (av & TERM_UNDERLINE)
{
if (!(video & TERM_UNDERLINE))
{
term_underline_on();
video |= TERM_UNDERLINE;
}
}
else
if (video & TERM_UNDERLINE)
{
term_underline_off();
video ^= TERM_UNDERLINE;
}
}
term_putchar(*str);
}
if (video & TERM_BOLD)
term_bold_off();
if (video & TERM_STANDOUT)
term_standout_off();
if (video & TERM_UNDERLINE)
term_underline_off();
if (hidden)
{
while (i++ < len)
term_putchar(' ');
term_standout_on();
term_putchar('+');
term_standout_off();
}
return (i);
}
/* flush the standard output */
void
term_flush()
{
fflush(stdout);
}
/* scroll n lines from line1 to line2 */
int
term_scroll(line1, line2, n)
int line1, line2, n;
{
int i;
char *code = NULL;
if (CS == NULL)
return -1;
if (n > 0)
code = SF ? SF : NL;
else if (n < 0)
code = SR;
assert(code); /* a little bit excessive, but makes a point */
sic_tputs(tgoto(CS, line2, line1));
if (n < 0)
{
term_move_cursor(0, line1);
n = -n;
}
else
term_move_cursor(0, line2);
for (i = 0; i < n; i++)
sic_tputs(code);
sic_tputs(tgoto(CS, LI - 1, 0));
return 0;
}
void
term_status(str, bold)
char *str;
int bold;
{
static int i;
term_move_cursor(0, LI-2);
if (bold)
term_bold_on();
else
{
term_standout_on();
for (i = strlen(str); i < CO-1; i++)
str[i] = ' ';
str[CO] = '\0';
}
term_puts(str, CO-1);
if (bold)
term_bold_off();
else
term_standout_off();
}
/* displays the string at the bottom of the screen (input line) */
void
term_input(str, pos)
char *str;
int pos;
{
static int c = 0;
if (str)
{
term_move_cursor(0, LI-1);
term_puts(str, CO-1);
term_clreol();
c = pos;
}
term_move_cursor(c, LI-1);
}
syntax highlighted by Code2HTML, v. 0.9.1