Annotation of src/usr.bin/less/doscreen.c, Revision 1.1
1.1 ! etheisen 1: /*
! 2: * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice in the documentation and/or other materials provided with
! 12: * the distribution.
! 13: *
! 14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
! 15: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 17: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
! 18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 19: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
! 20: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
! 21: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
! 23: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
! 24: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27:
! 28: /*
! 29: * Routines which deal with the characteristics of the terminal.
! 30: *
! 31: * This file is specific to MS-DOS and uses Microsoft C graphics functions.
! 32: */
! 33:
! 34: #include "less.h"
! 35: #include "cmd.h"
! 36:
! 37: #include <graph.h>
! 38: #include <time.h>
! 39:
! 40: static int init_done = 0;
! 41: static int videopages;
! 42: static long msec_loops;
! 43:
! 44: public int auto_wrap; /* Terminal does \r\n when write past margin */
! 45: public int ignaw; /* Terminal ignores \n immediately after wrap */
! 46: public int erase_char, kill_char; /* The user's erase and line-kill chars */
! 47: public int sc_width, sc_height; /* Height & width of screen */
! 48: public int bo_s_width, bo_e_width; /* Printing width of boldface seq */
! 49: public int ul_s_width, ul_e_width; /* Printing width of underline seq */
! 50: public int so_s_width, so_e_width; /* Printing width of standout seq */
! 51: public int bl_s_width, bl_e_width; /* Printing width of blink seq */
! 52:
! 53: public int nm_fg_color = 7; /* Color of normal text */
! 54: public int nm_bg_color = 0;
! 55: public int bo_fg_color = 15; /* Color of bold text */
! 56: public int bo_bg_color = 0;
! 57: public int ul_fg_color = 9; /* Color of underlined text */
! 58: public int ul_bg_color = 0;
! 59: public int so_fg_color = 0; /* Color of standout text */
! 60: public int so_bg_color = 7;
! 61: public int bl_fg_color = 12; /* Color of blinking text */
! 62: public int bl_bg_color = 0;
! 63:
! 64: static int sy_fg_color;
! 65: static int sy_bg_color;
! 66: static int flash_created = 0;
! 67:
! 68: extern int quiet; /* If VERY_QUIET, use visual bell for bell */
! 69: extern int know_dumb; /* Don't complain about a dumb terminal */
! 70: extern int back_scroll;
! 71: extern int swindow;
! 72: extern char *getenv();
! 73:
! 74: /*
! 75: * Change terminal to "raw mode", or restore to "normal" mode.
! 76: * "Raw mode" means
! 77: * 1. An outstanding read will complete on receipt of a single keystroke.
! 78: * 2. Input is not echoed.
! 79: * 3. On output, \n is mapped to \r\n.
! 80: * 4. \t is NOT expanded into spaces.
! 81: * 5. Signal-causing characters such as ctrl-C (interrupt),
! 82: * etc. are NOT disabled.
! 83: * It doesn't matter whether an input \n is mapped to \r, or vice versa.
! 84: */
! 85: public void
! 86: raw_mode(on)
! 87: int on;
! 88: {
! 89: static int curr_on = 0;
! 90:
! 91: if (on == curr_on)
! 92: return;
! 93: erase_char = CONTROL('h');
! 94: kill_char = '\33'; /* ESC */
! 95: curr_on = on;
! 96: }
! 97:
! 98: /*
! 99: * Get size of the output screen.
! 100: */
! 101: public void
! 102: scrsize(p_height, p_width)
! 103: int *p_height;
! 104: int *p_width;
! 105: {
! 106: register char *s;
! 107: struct videoconfig w;
! 108:
! 109: _getvideoconfig(&w);
! 110:
! 111: if (w.numtextrows)
! 112: *p_height = w.numtextrows;
! 113: else if ((s = getenv("LINES")) != NULL && *s != '\0')
! 114: *p_height = atoi(s);
! 115: if (*p_height <= 0)
! 116: *p_height = 24;
! 117:
! 118: if (w.numtextcols > 0)
! 119: *p_width = w.numtextcols;
! 120: else if ((s = getenv("COLUMNS")) != NULL)
! 121: *p_width = atoi(s);
! 122: if (*p_width <= 0)
! 123: *p_width = 80;
! 124: }
! 125:
! 126: /*
! 127: * Figure out how many empty loops it takes to delay a millisecond.
! 128: */
! 129: static void
! 130: get_clock()
! 131: {
! 132: clock_t start;
! 133:
! 134: /*
! 135: * Get synchronized at the start of a tick.
! 136: */
! 137: start = clock();
! 138: while (clock() == start)
! 139: ;
! 140: /*
! 141: * Now count loops till the next tick.
! 142: */
! 143: start = clock();
! 144: msec_loops = 0;
! 145: while (clock() == start)
! 146: msec_loops++;
! 147: /*
! 148: * Convert from (loops per clock) to (loops per millisecond).
! 149: */
! 150: msec_loops *= CLOCKS_PER_SEC;
! 151: msec_loops /= 1000;
! 152: }
! 153:
! 154: public void
! 155: get_editkeys()
! 156: {
! 157: }
! 158:
! 159: /*
! 160: * Get terminal capabilities via termcap.
! 161: */
! 162: public void
! 163: get_term()
! 164: {
! 165: scrsize(&sc_height, &sc_width);
! 166: pos_init();
! 167: auto_wrap = 1;
! 168: ignaw = 0;
! 169: so_e_width = so_s_width = 0;
! 170: bo_s_width = bo_e_width = 0;
! 171: ul_s_width = ul_e_width = 0;
! 172: bl_s_width = bl_e_width = 0;
! 173: get_clock();
! 174: }
! 175:
! 176:
! 177: /*
! 178: * Below are the functions which perform all the
! 179: * terminal-specific screen manipulation.
! 180: */
! 181:
! 182:
! 183: /*
! 184: * Initialize terminal
! 185: */
! 186: public void
! 187: init()
! 188: {
! 189: /* {{ What could we take no_init (-X) to mean? }} */
! 190: sy_bg_color = _getbkcolor();
! 191: sy_fg_color = _gettextcolor();
! 192: flush();
! 193: init_done = 1;
! 194: }
! 195:
! 196: /*
! 197: * Create an alternate screen which is all white.
! 198: * This screen is used to create a "flash" effect, by displaying it
! 199: * briefly and then switching back to the normal screen.
! 200: * {{ Yuck! There must be a better way to get a visual bell. }}
! 201: */
! 202: static void
! 203: create_flash()
! 204: {
! 205: struct videoconfig w;
! 206: char *blanks;
! 207: int row, col;
! 208:
! 209: _getvideoconfig(&w);
! 210: videopages = w.numvideopages;
! 211: if (videopages < 2)
! 212: {
! 213: so_enter();
! 214: so_exit();
! 215: } else
! 216: {
! 217: _setactivepage(1);
! 218: so_enter();
! 219: blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
! 220: for (col = 0; col < w.numtextcols; col++)
! 221: blanks[col] = ' ';
! 222: for (row = w.numtextrows; row > 0; row--)
! 223: _outmem(blanks, w.numtextcols);
! 224: _setactivepage(0);
! 225: _setvisualpage(0);
! 226: free(blanks);
! 227: so_exit();
! 228: }
! 229: flash_created = 1;
! 230: }
! 231:
! 232: /*
! 233: * Deinitialize terminal
! 234: */
! 235: public void
! 236: deinit()
! 237: {
! 238: if (!init_done)
! 239: return;
! 240: _setbkcolor(sy_bg_color);
! 241: _settextcolor(sy_fg_color);
! 242: putstr("\n");
! 243: init_done = 0;
! 244: }
! 245:
! 246: /*
! 247: * Home cursor (move to upper left corner of screen).
! 248: */
! 249: public void
! 250: home()
! 251: {
! 252: flush();
! 253: _settextposition(1,1);
! 254: }
! 255:
! 256: /*
! 257: * Add a blank line (called with cursor at home).
! 258: * Should scroll the display down.
! 259: */
! 260: public void
! 261: add_line()
! 262: {
! 263: flush();
! 264: _scrolltextwindow(_GSCROLLDOWN);
! 265: _settextposition(1,1);
! 266: }
! 267:
! 268: /*
! 269: * Move cursor to lower left corner of screen.
! 270: */
! 271: public void
! 272: lower_left()
! 273: {
! 274: flush();
! 275: _settextposition(sc_height,1);
! 276: }
! 277:
! 278: /*
! 279: * Delay for a specified number of milliseconds.
! 280: */
! 281: static void
! 282: dummy_func()
! 283: {
! 284: static long delay_dummy = 0;
! 285: delay_dummy++;
! 286: }
! 287:
! 288: static void
! 289: delay(msec)
! 290: int msec;
! 291: {
! 292: long i;
! 293:
! 294: while (msec-- > 0)
! 295: {
! 296: for (i = 0; i < msec_loops; i++)
! 297: {
! 298: /*
! 299: * Make it look like we're doing something here,
! 300: * so the optimizer doesn't remove the whole loop.
! 301: */
! 302: dummy_func();
! 303: }
! 304: }
! 305: }
! 306:
! 307: /*
! 308: * Make a noise.
! 309: */
! 310: static void
! 311: beep()
! 312: {
! 313: write(1, "\7", 1);
! 314: }
! 315:
! 316: /*
! 317: * Output the "visual bell", if there is one.
! 318: */
! 319: public void
! 320: vbell()
! 321: {
! 322: if (!flash_created)
! 323: /*
! 324: * Create a "flash" on the second video page.
! 325: */
! 326: create_flash();
! 327: if (videopages < 2)
! 328: /*
! 329: * There is no "second video page".
! 330: */
! 331: return;
! 332: _setvisualpage(1);
! 333: /*
! 334: * Leave it displayed for 100 msec.
! 335: */
! 336: delay(100);
! 337: _setvisualpage(0);
! 338: }
! 339:
! 340: /*
! 341: * Ring the terminal bell.
! 342: */
! 343: public void
! 344: bell()
! 345: {
! 346: if (quiet == VERY_QUIET)
! 347: vbell();
! 348: else
! 349: beep();
! 350: }
! 351:
! 352: /*
! 353: * Clear the screen.
! 354: */
! 355: public void
! 356: clear()
! 357: {
! 358: flush();
! 359: _clearscreen(_GCLEARSCREEN);
! 360: }
! 361:
! 362: /*
! 363: * Clear from the cursor to the end of the cursor's line.
! 364: * {{ This must not move the cursor. }}
! 365: */
! 366: public void
! 367: clear_eol()
! 368: {
! 369: short top, left;
! 370: short bot, right;
! 371: struct rccoord tpos;
! 372:
! 373: flush();
! 374: /*
! 375: * Save current state.
! 376: */
! 377: tpos = _gettextposition();
! 378: _gettextwindow(&top, &left, &bot, &right);
! 379: /*
! 380: * Set a temporary window to the current line,
! 381: * from the cursor's position to the right edge of the screen.
! 382: * Then clear that window.
! 383: */
! 384: _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
! 385: _clearscreen(_GWINDOW);
! 386: /*
! 387: * Restore state.
! 388: */
! 389: _settextwindow(top, left, bot, right);
! 390: _settextposition(tpos.row, tpos.col);
! 391: }
! 392:
! 393: /*
! 394: * Clear the bottom line of the display.
! 395: * Leave the cursor at the beginning of the bottom line.
! 396: */
! 397: public void
! 398: clear_bot()
! 399: {
! 400: lower_left();
! 401: clear_eol();
! 402: }
! 403:
! 404: /*
! 405: * Begin "standout" (bold, underline, or whatever).
! 406: */
! 407: public void
! 408: so_enter()
! 409: {
! 410: flush();
! 411: _setbkcolor(so_bg_color);
! 412: _settextcolor(so_fg_color);
! 413: }
! 414:
! 415: /*
! 416: * End "standout".
! 417: */
! 418: public void
! 419: so_exit()
! 420: {
! 421: flush();
! 422: _setbkcolor(nm_bg_color);
! 423: _settextcolor(nm_fg_color);
! 424: }
! 425:
! 426: /*
! 427: * Begin "underline" (hopefully real underlining,
! 428: * otherwise whatever the terminal provides).
! 429: */
! 430: public void
! 431: ul_enter()
! 432: {
! 433: flush();
! 434: _setbkcolor(ul_bg_color);
! 435: _settextcolor(ul_fg_color);
! 436: }
! 437:
! 438: /*
! 439: * End "underline".
! 440: */
! 441: public void
! 442: ul_exit()
! 443: {
! 444: flush();
! 445: _setbkcolor(nm_bg_color);
! 446: _settextcolor(nm_fg_color);
! 447: }
! 448:
! 449: /*
! 450: * Begin "bold"
! 451: */
! 452: public void
! 453: bo_enter()
! 454: {
! 455: flush();
! 456: _setbkcolor(bo_bg_color);
! 457: _settextcolor(bo_fg_color);
! 458: }
! 459:
! 460: /*
! 461: * End "bold".
! 462: */
! 463: public void
! 464: bo_exit()
! 465: {
! 466: flush();
! 467: _setbkcolor(nm_bg_color);
! 468: _settextcolor(nm_fg_color);
! 469: }
! 470:
! 471: /*
! 472: * Begin "blink"
! 473: */
! 474: public void
! 475: bl_enter()
! 476: {
! 477: flush();
! 478: _setbkcolor(bl_bg_color);
! 479: _settextcolor(bl_fg_color);
! 480: }
! 481:
! 482: /*
! 483: * End "blink".
! 484: */
! 485: public void
! 486: bl_exit()
! 487: {
! 488: flush();
! 489: _setbkcolor(nm_bg_color);
! 490: _settextcolor(nm_fg_color);
! 491: }
! 492:
! 493: /*
! 494: * Erase the character to the left of the cursor
! 495: * and move the cursor left.
! 496: */
! 497: public void
! 498: backspace()
! 499: {
! 500: struct rccoord tpos;
! 501:
! 502: /*
! 503: * Erase the previous character by overstriking with a space.
! 504: */
! 505: flush();
! 506: tpos = _gettextposition();
! 507: if (tpos.col <= 1)
! 508: return;
! 509: _settextposition(tpos.row, tpos.col-1);
! 510: _outtext(" ");
! 511: _settextposition(tpos.row, tpos.col-1);
! 512: }
! 513:
! 514: /*
! 515: * Output a plain backspace, without erasing the previous char.
! 516: */
! 517: public void
! 518: putbs()
! 519: {
! 520: struct rccoord tpos;
! 521:
! 522: flush();
! 523: tpos = _gettextposition();
! 524: if (tpos.col <= 1)
! 525: return;
! 526: _settextposition(tpos.row, tpos.col-1);
! 527: }
! 528:
! 529: /*
! 530: * Table of line editting characters, for editchar() in decode.c.
! 531: */
! 532: char edittable[] = {
! 533: '\340','\115',0, EC_RIGHT, /* RIGHTARROW */
! 534: '\340','\113',0, EC_LEFT, /* LEFTARROW */
! 535: '\340','\163',0, EC_W_LEFT, /* CTRL-LEFTARROW */
! 536: '\340','\164',0, EC_W_RIGHT, /* CTRL-RIGHTARROW */
! 537: '\340','\122',0, EC_INSERT, /* INSERT */
! 538: '\340','\123',0, EC_DELETE, /* DELETE */
! 539: '\340','\223',0, EC_W_DELETE, /* CTRL-DELETE */
! 540: '\177',0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */
! 541: '\340','\107',0, EC_HOME, /* HOME */
! 542: '\340','\117',0, EC_END, /* END */
! 543: '\340','\110',0, EC_UP, /* UPARROW */
! 544: '\340','\120',0, EC_DOWN, /* DOWNARROW */
! 545: '\t',0, EC_F_COMPLETE, /* TAB */
! 546: '\17',0, EC_B_COMPLETE, /* BACKTAB (?) */
! 547: '\340','\17',0, EC_B_COMPLETE, /* BACKTAB */
! 548: '\14',0, EC_EXPAND, /* CTRL-L */
! 549: 0 /* Extra byte to terminate; subtracted from size, below */
! 550: };
! 551:
! 552: int sz_edittable = sizeof(edittable) -1;
! 553:
! 554:
! 555: char kcmdtable[] =
! 556: {
! 557: /*
! 558: * PC function keys.
! 559: * Note that '\0' is converted to '\340' on input.
! 560: */
! 561: '\340','\120',0, A_F_LINE, /* down arrow */
! 562: '\340','\121',0, A_F_SCREEN, /* page down */
! 563: '\340','\110',0, A_B_LINE, /* up arrow */
! 564: '\340','\111',0, A_B_SCREEN, /* page up */
! 565: '\340','\107',0, A_GOLINE, /* home */
! 566: '\340','\117',0, A_GOEND, /* end */
! 567: '\340','\073',0, A_HELP, /* F1 */
! 568: '\340','\022',0, A_EXAMINE, /* Alt-E */
! 569: 0
! 570: };
! 571: int sz_kcmdtable = sizeof(kcmdtable) - 1;