Annotation of src/usr.bin/top/screen.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2:
! 3: /*
! 4: * Top users/processes display for Unix
! 5: * Version 3
! 6: *
! 7: * This program may be freely redistributed,
! 8: * but this entire comment MUST remain intact.
! 9: *
! 10: * Copyright (c) 1984, 1989, William LeFebvre, Rice University
! 11: * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
! 12: */
! 13:
! 14: /* This file contains the routines that interface to termcap and stty/gtty.
! 15: *
! 16: * Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
! 17: *
! 18: * I put in code to turn on the TOSTOP bit while top was running, but I
! 19: * didn't really like the results. If you desire it, turn on the
! 20: * preprocessor variable "TOStop". --wnl
! 21: */
! 22:
! 23: #include "os.h"
! 24: #include "top.h"
! 25:
! 26: #include <sys/ioctl.h>
! 27: #ifdef CBREAK
! 28: # include <sgtty.h>
! 29: # define SGTTY
! 30: #else
! 31: # ifdef TCGETA
! 32: # define TERMIO
! 33: # include <termio.h>
! 34: # else
! 35: # define TERMIOS
! 36: # include <termios.h>
! 37: # endif
! 38: #endif
! 39: #if defined(TERMIO) || defined(TERMIOS)
! 40: # ifndef TAB3
! 41: # ifdef OXTABS
! 42: # define TAB3 OXTABS
! 43: # else
! 44: # define TAB3 0
! 45: # endif
! 46: # endif
! 47: #endif
! 48: #include "screen.h"
! 49: #include "boolean.h"
! 50:
! 51: extern char *myname;
! 52:
! 53: int putstdout();
! 54:
! 55: int overstrike;
! 56: int screen_length;
! 57: int screen_width;
! 58: char ch_erase;
! 59: char ch_kill;
! 60: char smart_terminal;
! 61: char PC;
! 62: char *tgetstr();
! 63: char *tgoto();
! 64: char termcap_buf[1024];
! 65: char string_buffer[1024];
! 66: char home[15];
! 67: char lower_left[15];
! 68: char *clear_line;
! 69: char *clear_screen;
! 70: char *clear_to_end;
! 71: char *cursor_motion;
! 72: char *start_standout;
! 73: char *end_standout;
! 74: char *terminal_init;
! 75: char *terminal_end;
! 76: short ospeed;
! 77:
! 78: #ifdef SGTTY
! 79: static struct sgttyb old_settings;
! 80: static struct sgttyb new_settings;
! 81: #endif
! 82: #ifdef TERMIO
! 83: static struct termio old_settings;
! 84: static struct termio new_settings;
! 85: #endif
! 86: #ifdef TERMIOS
! 87: static struct termios old_settings;
! 88: static struct termios new_settings;
! 89: #endif
! 90: static char is_a_terminal = No;
! 91: #ifdef TOStop
! 92: static int old_lword;
! 93: static int new_lword;
! 94: #endif
! 95:
! 96: #define STDIN 0
! 97: #define STDOUT 1
! 98: #define STDERR 2
! 99:
! 100: init_termcap(interactive)
! 101:
! 102: int interactive;
! 103:
! 104: {
! 105: char *bufptr;
! 106: char *PCptr;
! 107: char *term_name;
! 108: char *getenv();
! 109: int status;
! 110:
! 111: /* set defaults in case we aren't smart */
! 112: screen_width = MAX_COLS;
! 113: screen_length = 0;
! 114:
! 115: if (!interactive)
! 116: {
! 117: /* pretend we have a dumb terminal */
! 118: smart_terminal = No;
! 119: return;
! 120: }
! 121:
! 122: /* assume we have a smart terminal until proven otherwise */
! 123: smart_terminal = Yes;
! 124:
! 125: /* get the terminal name */
! 126: term_name = getenv("TERM");
! 127:
! 128: /* if there is no TERM, assume it's a dumb terminal */
! 129: /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */
! 130: if (term_name == NULL)
! 131: {
! 132: smart_terminal = No;
! 133: return;
! 134: }
! 135:
! 136: /* now get the termcap entry */
! 137: if ((status = tgetent(termcap_buf, term_name)) != 1)
! 138: {
! 139: if (status == -1)
! 140: {
! 141: fprintf(stderr, "%s: can't open termcap file\n", myname);
! 142: }
! 143: else
! 144: {
! 145: fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
! 146: myname, term_name);
! 147: }
! 148:
! 149: /* pretend it's dumb and proceed */
! 150: smart_terminal = No;
! 151: return;
! 152: }
! 153:
! 154: /* "hardcopy" immediately indicates a very stupid terminal */
! 155: if (tgetflag("hc"))
! 156: {
! 157: smart_terminal = No;
! 158: return;
! 159: }
! 160:
! 161: /* set up common terminal capabilities */
! 162: if ((screen_length = tgetnum("li")) <= 0)
! 163: {
! 164: screen_length = smart_terminal = 0;
! 165: return;
! 166: }
! 167:
! 168: /* screen_width is a little different */
! 169: if ((screen_width = tgetnum("co")) == -1)
! 170: {
! 171: screen_width = 79;
! 172: }
! 173: else
! 174: {
! 175: screen_width -= 1;
! 176: }
! 177:
! 178: /* terminals that overstrike need special attention */
! 179: overstrike = tgetflag("os");
! 180:
! 181: /* initialize the pointer into the termcap string buffer */
! 182: bufptr = string_buffer;
! 183:
! 184: /* get "ce", clear to end */
! 185: if (!overstrike)
! 186: {
! 187: clear_line = tgetstr("ce", &bufptr);
! 188: }
! 189:
! 190: /* get necessary capabilities */
! 191: if ((clear_screen = tgetstr("cl", &bufptr)) == NULL ||
! 192: (cursor_motion = tgetstr("cm", &bufptr)) == NULL)
! 193: {
! 194: smart_terminal = No;
! 195: return;
! 196: }
! 197:
! 198: /* get some more sophisticated stuff -- these are optional */
! 199: clear_to_end = tgetstr("cd", &bufptr);
! 200: terminal_init = tgetstr("ti", &bufptr);
! 201: terminal_end = tgetstr("te", &bufptr);
! 202: start_standout = tgetstr("so", &bufptr);
! 203: end_standout = tgetstr("se", &bufptr);
! 204:
! 205: /* pad character */
! 206: PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
! 207:
! 208: /* set convenience strings */
! 209: (void) strcpy(home, tgoto(cursor_motion, 0, 0));
! 210: /* (lower_left is set in get_screensize) */
! 211:
! 212: /* get the actual screen size with an ioctl, if needed */
! 213: /* This may change screen_width and screen_length, and it always
! 214: sets lower_left. */
! 215: get_screensize();
! 216:
! 217: /* if stdout is not a terminal, pretend we are a dumb terminal */
! 218: #ifdef SGTTY
! 219: if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1)
! 220: {
! 221: smart_terminal = No;
! 222: }
! 223: #endif
! 224: #ifdef TERMIO
! 225: if (ioctl(STDOUT, TCGETA, &old_settings) == -1)
! 226: {
! 227: smart_terminal = No;
! 228: }
! 229: #endif
! 230: #ifdef TERMIOS
! 231: if (tcgetattr(STDOUT, &old_settings) == -1)
! 232: {
! 233: smart_terminal = No;
! 234: }
! 235: #endif
! 236: }
! 237:
! 238: init_screen()
! 239:
! 240: {
! 241: /* get the old settings for safe keeping */
! 242: #ifdef SGTTY
! 243: if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1)
! 244: {
! 245: /* copy the settings so we can modify them */
! 246: new_settings = old_settings;
! 247:
! 248: /* turn on CBREAK and turn off character echo and tab expansion */
! 249: new_settings.sg_flags |= CBREAK;
! 250: new_settings.sg_flags &= ~(ECHO|XTABS);
! 251: (void) ioctl(STDOUT, TIOCSETP, &new_settings);
! 252:
! 253: /* remember the erase and kill characters */
! 254: ch_erase = old_settings.sg_erase;
! 255: ch_kill = old_settings.sg_kill;
! 256:
! 257: #ifdef TOStop
! 258: /* get the local mode word */
! 259: (void) ioctl(STDOUT, TIOCLGET, &old_lword);
! 260:
! 261: /* modify it */
! 262: new_lword = old_lword | LTOSTOP;
! 263: (void) ioctl(STDOUT, TIOCLSET, &new_lword);
! 264: #endif
! 265: /* remember that it really is a terminal */
! 266: is_a_terminal = Yes;
! 267:
! 268: /* send the termcap initialization string */
! 269: putcap(terminal_init);
! 270: }
! 271: #endif
! 272: #ifdef TERMIO
! 273: if (ioctl(STDOUT, TCGETA, &old_settings) != -1)
! 274: {
! 275: /* copy the settings so we can modify them */
! 276: new_settings = old_settings;
! 277:
! 278: /* turn off ICANON, character echo and tab expansion */
! 279: new_settings.c_lflag &= ~(ICANON|ECHO);
! 280: new_settings.c_oflag &= ~(TAB3);
! 281: new_settings.c_cc[VMIN] = 1;
! 282: new_settings.c_cc[VTIME] = 0;
! 283: (void) ioctl(STDOUT, TCSETA, &new_settings);
! 284:
! 285: /* remember the erase and kill characters */
! 286: ch_erase = old_settings.c_cc[VERASE];
! 287: ch_kill = old_settings.c_cc[VKILL];
! 288:
! 289: /* remember that it really is a terminal */
! 290: is_a_terminal = Yes;
! 291:
! 292: /* send the termcap initialization string */
! 293: putcap(terminal_init);
! 294: }
! 295: #endif
! 296: #ifdef TERMIOS
! 297: if (tcgetattr(STDOUT, &old_settings) != -1)
! 298: {
! 299: /* copy the settings so we can modify them */
! 300: new_settings = old_settings;
! 301:
! 302: /* turn off ICANON, character echo and tab expansion */
! 303: new_settings.c_lflag &= ~(ICANON|ECHO);
! 304: new_settings.c_oflag &= ~(TAB3);
! 305: new_settings.c_cc[VMIN] = 1;
! 306: new_settings.c_cc[VTIME] = 0;
! 307: (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
! 308:
! 309: /* remember the erase and kill characters */
! 310: ch_erase = old_settings.c_cc[VERASE];
! 311: ch_kill = old_settings.c_cc[VKILL];
! 312:
! 313: /* remember that it really is a terminal */
! 314: is_a_terminal = Yes;
! 315:
! 316: /* send the termcap initialization string */
! 317: putcap(terminal_init);
! 318: }
! 319: #endif
! 320:
! 321: if (!is_a_terminal)
! 322: {
! 323: /* not a terminal at all---consider it dumb */
! 324: smart_terminal = No;
! 325: }
! 326: }
! 327:
! 328: end_screen()
! 329:
! 330: {
! 331: /* move to the lower left, clear the line and send "te" */
! 332: if (smart_terminal)
! 333: {
! 334: putcap(lower_left);
! 335: putcap(clear_line);
! 336: fflush(stdout);
! 337: putcap(terminal_end);
! 338: }
! 339:
! 340: /* if we have settings to reset, then do so */
! 341: if (is_a_terminal)
! 342: {
! 343: #ifdef SGTTY
! 344: (void) ioctl(STDOUT, TIOCSETP, &old_settings);
! 345: #ifdef TOStop
! 346: (void) ioctl(STDOUT, TIOCLSET, &old_lword);
! 347: #endif
! 348: #endif
! 349: #ifdef TERMIO
! 350: (void) ioctl(STDOUT, TCSETA, &old_settings);
! 351: #endif
! 352: #ifdef TERMIOS
! 353: (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings);
! 354: #endif
! 355: }
! 356: }
! 357:
! 358: reinit_screen()
! 359:
! 360: {
! 361: /* install our settings if it is a terminal */
! 362: if (is_a_terminal)
! 363: {
! 364: #ifdef SGTTY
! 365: (void) ioctl(STDOUT, TIOCSETP, &new_settings);
! 366: #ifdef TOStop
! 367: (void) ioctl(STDOUT, TIOCLSET, &new_lword);
! 368: #endif
! 369: #endif
! 370: #ifdef TERMIO
! 371: (void) ioctl(STDOUT, TCSETA, &new_settings);
! 372: #endif
! 373: #ifdef TERMIOS
! 374: (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings);
! 375: #endif
! 376: }
! 377:
! 378: /* send init string */
! 379: if (smart_terminal)
! 380: {
! 381: putcap(terminal_init);
! 382: }
! 383: }
! 384:
! 385: get_screensize()
! 386:
! 387: {
! 388:
! 389: #ifdef TIOCGWINSZ
! 390:
! 391: struct winsize ws;
! 392:
! 393: if (ioctl (1, TIOCGWINSZ, &ws) != -1)
! 394: {
! 395: if (ws.ws_row != 0)
! 396: {
! 397: screen_length = ws.ws_row;
! 398: }
! 399: if (ws.ws_col != 0)
! 400: {
! 401: screen_width = ws.ws_col - 1;
! 402: }
! 403: }
! 404:
! 405: #else
! 406: #ifdef TIOCGSIZE
! 407:
! 408: struct ttysize ts;
! 409:
! 410: if (ioctl (1, TIOCGSIZE, &ts) != -1)
! 411: {
! 412: if (ts.ts_lines != 0)
! 413: {
! 414: screen_length = ts.ts_lines;
! 415: }
! 416: if (ts.ts_cols != 0)
! 417: {
! 418: screen_width = ts.ts_cols - 1;
! 419: }
! 420: }
! 421:
! 422: #endif /* TIOCGSIZE */
! 423: #endif /* TIOCGWINSZ */
! 424:
! 425: (void) strcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1));
! 426: }
! 427:
! 428: standout(msg)
! 429:
! 430: char *msg;
! 431:
! 432: {
! 433: if (smart_terminal)
! 434: {
! 435: putcap(start_standout);
! 436: fputs(msg, stdout);
! 437: putcap(end_standout);
! 438: }
! 439: else
! 440: {
! 441: fputs(msg, stdout);
! 442: }
! 443: }
! 444:
! 445: clear()
! 446:
! 447: {
! 448: if (smart_terminal)
! 449: {
! 450: putcap(clear_screen);
! 451: }
! 452: }
! 453:
! 454: clear_eol(len)
! 455:
! 456: int len;
! 457:
! 458: {
! 459: if (smart_terminal && !overstrike && len > 0)
! 460: {
! 461: if (clear_line)
! 462: {
! 463: putcap(clear_line);
! 464: return(0);
! 465: }
! 466: else
! 467: {
! 468: while (len-- > 0)
! 469: {
! 470: putchar(' ');
! 471: }
! 472: return(1);
! 473: }
! 474: }
! 475: return(-1);
! 476: }
! 477:
! 478: go_home()
! 479:
! 480: {
! 481: if (smart_terminal)
! 482: {
! 483: putcap(home);
! 484: }
! 485: }
! 486:
! 487: /* This has to be defined as a subroutine for tputs (instead of a macro) */
! 488:
! 489: putstdout(ch)
! 490:
! 491: char ch;
! 492:
! 493: {
! 494: putchar(ch);
! 495: }
! 496: