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