/* * 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); }