home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / less2912.zip / doscreen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-09  |  11.8 KB  |  609 lines

  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. public int can_goto_line;        /* Can move cursor to any line */
  53.  
  54. public int nm_fg_color = 7;            /* Color of normal text */
  55. public int nm_bg_color = 0;
  56. public int bo_fg_color = 15;        /* Color of bold text */
  57. public int bo_bg_color = 0;
  58. public int ul_fg_color = 9;            /* Color of underlined text */
  59. public int ul_bg_color = 0;
  60. public int so_fg_color = 0;            /* Color of standout text */
  61. public int so_bg_color = 7;
  62. public int bl_fg_color = 12;        /* Color of blinking text */
  63. public int bl_bg_color = 0;
  64.  
  65. static int sy_fg_color;
  66. static int sy_bg_color;
  67. static int flash_created = 0;
  68.  
  69. extern int quiet;        /* If VERY_QUIET, use visual bell for bell */
  70. extern int know_dumb;        /* Don't complain about a dumb terminal */
  71. extern int back_scroll;
  72. extern int swindow;
  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 = lgetenv("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 = lgetenv("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 the screen to the correct color at startup.
  185.  */
  186.     static void
  187. initcolor()
  188. {
  189.     struct videoconfig w;
  190.     char *blanks;
  191.     int row;
  192.     int col;
  193.     
  194.     /*
  195.      * Create a complete, blank screen using "normal" colors.
  196.      */
  197.     _settextcolor(nm_fg_color);
  198.     _setbkcolor(nm_bg_color);
  199.     _getvideoconfig(&w);
  200.     blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
  201.     for (col = 0;  col < w.numtextcols;  col++)
  202.         blanks[col] = ' ';
  203.     for (row = w.numtextrows;  row > 0;  row--)
  204.         _outmem(blanks, w.numtextcols);
  205.     free(blanks);
  206. }
  207.  
  208. /*
  209.  * Initialize terminal
  210.  */
  211.     public void
  212. init()
  213. {
  214.     /* {{ What could we take no_init (-X) to mean? }} */
  215.     sy_bg_color = _getbkcolor();
  216.     sy_fg_color = _gettextcolor();
  217.     initcolor();
  218.     flush();
  219.     init_done = 1;
  220. }
  221.  
  222. /*
  223.  * Create an alternate screen which is all white.
  224.  * This screen is used to create a "flash" effect, by displaying it
  225.  * briefly and then switching back to the normal screen.
  226.  * {{ Yuck!  There must be a better way to get a visual bell. }}
  227.  */
  228.     static void
  229. create_flash()
  230. {
  231.     struct videoconfig w;
  232.     char *blanks;
  233.     int row, col;
  234.     
  235.     _getvideoconfig(&w);
  236.     videopages = w.numvideopages;
  237.     if (videopages < 2)
  238.     {
  239.         so_enter();
  240.         so_exit();
  241.     } else
  242.     {
  243.         _setactivepage(1);
  244.         so_enter();
  245.         blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
  246.         for (col = 0;  col < w.numtextcols;  col++)
  247.             blanks[col] = ' ';
  248.         for (row = w.numtextrows;  row > 0;  row--)
  249.             _outmem(blanks, w.numtextcols);
  250.         _setactivepage(0);
  251.         _setvisualpage(0);
  252.         free(blanks);
  253.         so_exit();
  254.     }
  255.     flash_created = 1;
  256. }
  257.  
  258. /*
  259.  * Deinitialize terminal
  260.  */
  261.     public void
  262. deinit()
  263. {
  264.     if (!init_done)
  265.         return;
  266.     _setbkcolor(sy_bg_color);
  267.     _settextcolor(sy_fg_color);
  268.     putstr("\n");
  269.     init_done = 0;
  270. }
  271.  
  272. /*
  273.  * Home cursor (move to upper left corner of screen).
  274.  */
  275.     public void
  276. home()
  277. {
  278.     flush();
  279.     _settextposition(1,1);
  280. }
  281.  
  282. /*
  283.  * Add a blank line (called with cursor at home).
  284.  * Should scroll the display down.
  285.  */
  286.     public void
  287. add_line()
  288. {
  289.     flush();
  290.     _scrolltextwindow(_GSCROLLDOWN);
  291.     _settextposition(1,1);
  292. }
  293.  
  294. /*
  295.  * Move cursor to lower left corner of screen.
  296.  */
  297.     public void
  298. lower_left()
  299. {
  300.     flush();
  301.     _settextposition(sc_height,1);
  302. }
  303.  
  304. /*
  305.  * Goto a specific line on the screen.
  306.  */
  307.     public void
  308. goto_line(slinenum)
  309.     int slinenum;
  310. {
  311.     flush();
  312.     _settextposition(slinenum, 1);
  313. }
  314.  
  315. /*
  316.  * Delay for a specified number of milliseconds.
  317.  */
  318.     static void
  319. dummy_func()
  320. {
  321.     static long delay_dummy = 0;
  322.     delay_dummy++;
  323. }
  324.  
  325.     static void
  326. delay(msec)
  327.     int msec;
  328. {
  329.     long i;
  330.     
  331.     while (msec-- > 0)
  332.     {
  333.         for (i = 0;  i < msec_loops;  i++)
  334.         {
  335.             /*
  336.              * Make it look like we're doing something here,
  337.              * so the optimizer doesn't remove the whole loop.
  338.              */
  339.             dummy_func();
  340.         }
  341.     }
  342. }
  343.  
  344. /*
  345.  * Make a noise.
  346.  */
  347.     static void
  348. beep()
  349. {
  350.     write(1, "\7", 1);
  351. }
  352.  
  353. /*
  354.  * Output the "visual bell", if there is one.
  355.  */
  356.     public void
  357. vbell()
  358. {
  359.     if (!flash_created)
  360.         /*
  361.          * Create a "flash" on the second video page.
  362.          */
  363.         create_flash();
  364.     if (videopages < 2)
  365.         /*
  366.          * There is no "second video page".
  367.          */
  368.         return;
  369.     _setvisualpage(1);
  370.     /*
  371.      * Leave it displayed for 100 msec.
  372.      */
  373.     delay(100);
  374.     _setvisualpage(0);
  375. }
  376.  
  377. /*
  378.  * Ring the terminal bell.
  379.  */
  380.     public void
  381. bell()
  382. {
  383.     if (quiet == VERY_QUIET)
  384.         vbell();
  385.     else
  386.         beep();
  387. }
  388.  
  389. /*
  390.  * Clear the screen.
  391.  */
  392.     public void
  393. clear()
  394. {
  395.     flush();
  396.     _clearscreen(_GCLEARSCREEN);
  397. }
  398.  
  399. /*
  400.  * Clear from the cursor to the end of the cursor's line.
  401.  * {{ This must not move the cursor. }}
  402.  */
  403.     public void
  404. clear_eol()
  405. {
  406.     short top, left;
  407.     short bot, right;
  408.     struct rccoord tpos;
  409.     
  410.     flush();
  411.     /*
  412.      * Save current state.
  413.      */
  414.     tpos = _gettextposition();
  415.     _gettextwindow(&top, &left, &bot, &right);
  416.     /*
  417.      * Set a temporary window to the current line,
  418.      * from the cursor's position to the right edge of the screen.
  419.      * Then clear that window.
  420.      */
  421.     _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
  422.     _clearscreen(_GWINDOW);
  423.     /*
  424.      * Restore state.
  425.      */
  426.     _settextwindow(top, left, bot, right);
  427.     _settextposition(tpos.row, tpos.col);
  428. }
  429.  
  430. /*
  431.  * Clear the bottom line of the display.
  432.  * Leave the cursor at the beginning of the bottom line.
  433.  */
  434.     public void
  435. clear_bot()
  436. {
  437.     lower_left();
  438.     clear_eol();
  439. }
  440.  
  441. /*
  442.  * Begin "standout" (bold, underline, or whatever).
  443.  */
  444.     public void
  445. so_enter()
  446. {
  447.     flush();
  448.     _setbkcolor(so_bg_color);
  449.     _settextcolor(so_fg_color);
  450. }
  451.  
  452. /*
  453.  * End "standout".
  454.  */
  455.     public void
  456. so_exit()
  457. {
  458.     flush();
  459.     _setbkcolor(nm_bg_color);
  460.     _settextcolor(nm_fg_color);
  461. }
  462.  
  463. /*
  464.  * Begin "underline" (hopefully real underlining, 
  465.  * otherwise whatever the terminal provides).
  466.  */
  467.     public void
  468. ul_enter()
  469. {
  470.     flush();
  471.     _setbkcolor(ul_bg_color);
  472.     _settextcolor(ul_fg_color);
  473. }
  474.  
  475. /*
  476.  * End "underline".
  477.  */
  478.     public void
  479. ul_exit()
  480. {
  481.     flush();
  482.     _setbkcolor(nm_bg_color);
  483.     _settextcolor(nm_fg_color);
  484. }
  485.  
  486. /*
  487.  * Begin "bold"
  488.  */
  489.     public void
  490. bo_enter()
  491. {
  492.     flush();
  493.     _setbkcolor(bo_bg_color);
  494.     _settextcolor(bo_fg_color);
  495. }
  496.  
  497. /*
  498.  * End "bold".
  499.  */
  500.     public void
  501. bo_exit()
  502. {
  503.     flush();
  504.     _setbkcolor(nm_bg_color);
  505.     _settextcolor(nm_fg_color);
  506. }
  507.  
  508. /*
  509.  * Begin "blink"
  510.  */
  511.     public void
  512. bl_enter()
  513. {
  514.     flush();
  515.     _setbkcolor(bl_bg_color);
  516.     _settextcolor(bl_fg_color);
  517. }
  518.  
  519. /*
  520.  * End "blink".
  521.  */
  522.     public void
  523. bl_exit()
  524. {
  525.     flush();
  526.     _setbkcolor(nm_bg_color);
  527.     _settextcolor(nm_fg_color);
  528. }
  529.  
  530. /*
  531.  * Erase the character to the left of the cursor 
  532.  * and move the cursor left.
  533.  */
  534.     public void
  535. backspace()
  536. {
  537.     struct rccoord tpos;
  538.     
  539.     /* 
  540.      * Erase the previous character by overstriking with a space.
  541.      */
  542.     flush();
  543.     tpos = _gettextposition();
  544.     if (tpos.col <= 1)
  545.         return;
  546.     _settextposition(tpos.row, tpos.col-1);
  547.     _outtext(" ");
  548.     _settextposition(tpos.row, tpos.col-1);
  549. }
  550.  
  551. /*
  552.  * Output a plain backspace, without erasing the previous char.
  553.  */
  554.     public void
  555. putbs()
  556. {
  557.     struct rccoord tpos;
  558.     
  559.     flush();
  560.     tpos = _gettextposition();
  561.     if (tpos.col <= 1)
  562.         return;
  563.     _settextposition(tpos.row, tpos.col-1);
  564. }
  565.  
  566. /*
  567.  * Table of line editting characters, for editchar() in decode.c.
  568.  */
  569. char edittable[] = {
  570.     '\340','\115',0,    EC_RIGHT,    /* RIGHTARROW */
  571.     '\340','\113',0,    EC_LEFT,    /* LEFTARROW */
  572.     '\340','\163',0,    EC_W_LEFT,    /* CTRL-LEFTARROW */
  573.     '\340','\164',0,    EC_W_RIGHT,    /* CTRL-RIGHTARROW */
  574.     '\340','\122',0,    EC_INSERT,    /* INSERT */
  575.     '\340','\123',0,    EC_DELETE,    /* DELETE */
  576.     '\340','\223',0,    EC_W_DELETE,    /* CTRL-DELETE */
  577.     '\177',0,        EC_W_BACKSPACE,    /* CTRL-BACKSPACE */
  578.     '\340','\107',0,    EC_HOME,    /* HOME */
  579.     '\340','\117',0,    EC_END,        /* END */
  580.     '\340','\110',0,    EC_UP,        /* UPARROW */
  581.     '\340','\120',0,    EC_DOWN,    /* DOWNARROW */
  582.     '\t',0,            EC_F_COMPLETE,    /* TAB */
  583.     '\17',0,        EC_B_COMPLETE,    /* BACKTAB (?) */
  584.     '\340','\17',0,        EC_B_COMPLETE,    /* BACKTAB */
  585.     '\14',0,        EC_EXPAND,    /* CTRL-L */
  586.     0  /* Extra byte to terminate; subtracted from size, below */
  587. };
  588.  
  589. int sz_edittable = sizeof(edittable) -1;
  590.  
  591.  
  592. char kcmdtable[] =
  593. {
  594.     /*
  595.      * PC function keys.
  596.      * Note that '\0' is converted to '\340' on input.
  597.      */
  598.     '\340','\120',0,        A_F_LINE,        /* down arrow */
  599.     '\340','\121',0,        A_F_SCREEN,        /* page down */
  600.     '\340','\110',0,        A_B_LINE,        /* up arrow */
  601.     '\340','\111',0,        A_B_SCREEN,        /* page up */
  602.     '\340','\107',0,        A_GOLINE,        /* home */
  603.     '\340','\117',0,        A_GOEND,        /* end */
  604.     '\340','\073',0,        A_HELP,            /* F1 */
  605.     '\340','\022',0,        A_EXAMINE,        /* Alt-E */
  606.     0
  607. };
  608. int sz_kcmdtable = sizeof(kcmdtable) - 1;
  609.