Annotation of src/usr.bin/less/screen.c, Revision 1.15
1.1 etheisen 1: /*
1.15 ! shadchin 2: * Copyright (C) 1984-2011 Mark Nudelman
1.1 etheisen 3: *
1.11 millert 4: * You may distribute under the terms of either the GNU General Public
5: * License or the Less License, as specified in the README file.
1.1 etheisen 6: *
1.11 millert 7: * For more information about less, or for information on how to
8: * contact the author, see the README file.
1.1 etheisen 9: */
10:
11:
12: /*
13: * Routines which deal with the characteristics of the terminal.
14: * Uses termcap to be as terminal-independent as possible.
15: */
16:
17: #include "less.h"
18: #include "cmd.h"
19:
1.11 millert 20: #if MSDOS_COMPILER
21: #include "pckeys.h"
22: #if MSDOS_COMPILER==MSOFTC
23: #include <graph.h>
24: #else
25: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
26: #include <conio.h>
27: #if MSDOS_COMPILER==DJGPPC
28: #include <pc.h>
29: extern int fd0;
30: #endif
31: #else
32: #if MSDOS_COMPILER==WIN32C
33: #include <windows.h>
34: #endif
35: #endif
36: #endif
37: #include <time.h>
38:
39: #else
40:
1.12 david 41: #if HAVE_SYS_IOCTL_H
1.1 etheisen 42: #include <sys/ioctl.h>
43: #endif
1.15 ! shadchin 44:
! 45: #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
! 46: #include <termios.h>
1.1 etheisen 47: #else
48: #if HAVE_TERMIO_H
49: #include <termio.h>
50: #else
1.11 millert 51: #if HAVE_SGSTAT_H
52: #include <sgstat.h>
53: #else
1.1 etheisen 54: #include <sgtty.h>
1.11 millert 55: #endif
1.1 etheisen 56: #endif
57: #endif
1.11 millert 58:
1.1 etheisen 59: #if HAVE_TERMCAP_H
60: #include <termcap.h>
61: #endif
1.11 millert 62: #ifdef _OSK
63: #include <signal.h>
64: #endif
65: #if OS2
1.1 etheisen 66: #include <sys/signal.h>
1.11 millert 67: #include "pckeys.h"
1.1 etheisen 68: #endif
69: #if HAVE_SYS_STREAM_H
70: #include <sys/stream.h>
71: #endif
72: #if HAVE_SYS_PTEM_H
73: #include <sys/ptem.h>
74: #endif
75:
1.11 millert 76: #endif /* MSDOS_COMPILER */
77:
78: /*
79: * Check for broken termios package that forces you to manually
80: * set the line discipline.
81: */
82: #ifdef __ultrix__
83: #define MUST_SET_LINE_DISCIPLINE 1
84: #else
85: #define MUST_SET_LINE_DISCIPLINE 0
86: #endif
87:
1.1 etheisen 88: #if OS2
89: #define DEFAULT_TERM "ansi"
1.11 millert 90: static char *windowid;
1.1 etheisen 91: #else
92: #define DEFAULT_TERM "unknown"
93: #endif
94:
1.11 millert 95: #if MSDOS_COMPILER==MSOFTC
96: static int videopages;
97: static long msec_loops;
98: static int flash_created = 0;
99: #define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); }
100: #endif
101:
102: #if MSDOS_COMPILER==BORLANDC
103: static unsigned short *whitescreen;
104: static int flash_created = 0;
105: #endif
106: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
107: #define _settextposition(y,x) gotoxy(x,y)
108: #define _clearscreen(m) clrscr()
109: #define _outtext(s) cputs(s)
110: #define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); }
111: extern int sc_height;
112: #endif
113:
114: #if MSDOS_COMPILER==WIN32C
115: struct keyRecord
116: {
117: int ascii;
118: int scan;
119: } currentKey;
120:
121: static int keyCount = 0;
122: static WORD curr_attr;
123: static int pending_scancode = 0;
124: static WORD *whitescreen;
125:
126: static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */
127: static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */
128: HANDLE con_out = INVALID_HANDLE_VALUE; /* current console */
129:
130: extern int quitting;
131: static void win32_init_term();
132: static void win32_deinit_term();
133:
134: #define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)
135: #define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY)
136: #define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4)))
137: #define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \
138: if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \
139: error("SETCOLORS failed"); }
140: #endif
141:
142: #if MSDOS_COMPILER
143: public int nm_fg_color; /* Color of normal text */
144: public int nm_bg_color;
145: public int bo_fg_color; /* Color of bold text */
146: public int bo_bg_color;
147: public int ul_fg_color; /* Color of underlined text */
148: public int ul_bg_color;
149: public int so_fg_color; /* Color of standout text */
150: public int so_bg_color;
151: public int bl_fg_color; /* Color of blinking text */
152: public int bl_bg_color;
153: static int sy_fg_color; /* Color of system text (before less) */
154: static int sy_bg_color;
155:
156: #else
157:
1.1 etheisen 158: /*
159: * Strings passed to tputs() to do various terminal functions.
160: */
161: static char
162: *sc_pad, /* Pad string */
163: *sc_home, /* Cursor home */
164: *sc_addline, /* Add line, scroll down following lines */
165: *sc_lower_left, /* Cursor to last line, first column */
1.15 ! shadchin 166: *sc_return, /* Cursor to beginning of current line */
1.1 etheisen 167: *sc_move, /* General cursor positioning */
168: *sc_clear, /* Clear screen */
169: *sc_eol_clear, /* Clear to end of line */
170: *sc_eos_clear, /* Clear to end of screen */
171: *sc_s_in, /* Enter standout (highlighted) mode */
172: *sc_s_out, /* Exit standout mode */
173: *sc_u_in, /* Enter underline mode */
174: *sc_u_out, /* Exit underline mode */
175: *sc_b_in, /* Enter bold mode */
176: *sc_b_out, /* Exit bold mode */
177: *sc_bl_in, /* Enter blink mode */
178: *sc_bl_out, /* Exit blink mode */
179: *sc_visual_bell, /* Visual bell (flash screen) sequence */
180: *sc_backspace, /* Backspace cursor */
181: *sc_s_keypad, /* Start keypad mode */
182: *sc_e_keypad, /* End keypad mode */
183: *sc_init, /* Startup terminal initialization */
184: *sc_deinit; /* Exit terminal de-initialization */
1.11 millert 185: #endif
1.1 etheisen 186:
187: static int init_done = 0;
188:
189: public int auto_wrap; /* Terminal does \r\n when write past margin */
190: public int ignaw; /* Terminal ignores \n immediately after wrap */
1.15 ! shadchin 191: public int erase_char; /* The user's erase char */
! 192: public int erase2_char; /* The user's other erase char */
! 193: public int kill_char; /* The user's line-kill char */
1.1 etheisen 194: public int werase_char; /* The user's word-erase char */
195: public int sc_width, sc_height; /* Height & width of screen */
196: public int bo_s_width, bo_e_width; /* Printing width of boldface seq */
197: public int ul_s_width, ul_e_width; /* Printing width of underline seq */
198: public int so_s_width, so_e_width; /* Printing width of standout seq */
199: public int bl_s_width, bl_e_width; /* Printing width of blink seq */
200: public int above_mem, below_mem; /* Memory retained above/below screen */
201: public int can_goto_line; /* Can move cursor to any line */
1.11 millert 202: public int clear_bg; /* Clear fills with background color */
203: public int missing_cap = 0; /* Some capability is missing */
204:
205: static int attrmode = AT_NORMAL;
1.15 ! shadchin 206: extern int binattr;
1.1 etheisen 207:
1.11 millert 208: #if !MSDOS_COMPILER
1.1 etheisen 209: static char *cheaper();
1.11 millert 210: static void tmodes();
211: #endif
1.1 etheisen 212:
213: /*
214: * These two variables are sometimes defined in,
215: * and needed by, the termcap library.
216: */
217: #if MUST_DEFINE_OSPEED
218: extern short ospeed; /* Terminal output baud rate */
219: extern char PC; /* Pad character */
220: #endif
1.11 millert 221: #ifdef _OSK
222: short ospeed;
223: char PC_, *UP, *BC;
224: #endif
1.1 etheisen 225:
226: extern int quiet; /* If VERY_QUIET, use visual bell for bell */
1.11 millert 227: extern int no_back_scroll;
1.1 etheisen 228: extern int swindow;
229: extern int no_init;
1.11 millert 230: extern int no_keypad;
231: extern int sigs;
232: extern int wscroll;
233: extern int screen_trashed;
234: extern int tty;
1.15 ! shadchin 235: extern int top_scroll;
! 236: extern int oldbot;
1.1 etheisen 237: #if HILITE_SEARCH
238: extern int hilite_search;
239: #endif
240:
241: extern char *tgetstr();
242: extern char *tgoto();
243:
244:
245: /*
246: * Change terminal to "raw mode", or restore to "normal" mode.
247: * "Raw mode" means
248: * 1. An outstanding read will complete on receipt of a single keystroke.
249: * 2. Input is not echoed.
250: * 3. On output, \n is mapped to \r\n.
251: * 4. \t is NOT expanded into spaces.
252: * 5. Signal-causing characters such as ctrl-C (interrupt),
253: * etc. are NOT disabled.
254: * It doesn't matter whether an input \n is mapped to \r, or vice versa.
255: */
256: public void
257: raw_mode(on)
258: int on;
259: {
260: static int curr_on = 0;
261:
262: if (on == curr_on)
263: return;
1.15 ! shadchin 264: erase2_char = '\b'; /* in case OS doesn't know about erase2 */
1.1 etheisen 265: #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
266: {
267: struct termios s;
268: static struct termios save_term;
1.11 millert 269: static int saved_term = 0;
1.1 etheisen 270:
271: if (on)
272: {
273: /*
274: * Get terminal modes.
275: */
1.11 millert 276: tcgetattr(tty, &s);
1.1 etheisen 277:
278: /*
279: * Save modes and set certain variables dependent on modes.
280: */
1.11 millert 281: if (!saved_term)
282: {
283: save_term = s;
284: saved_term = 1;
285: }
1.1 etheisen 286: #if HAVE_OSPEED
287: switch (cfgetospeed(&s))
288: {
289: #ifdef B0
290: case B0: ospeed = 0; break;
291: #endif
292: #ifdef B50
293: case B50: ospeed = 1; break;
294: #endif
295: #ifdef B75
296: case B75: ospeed = 2; break;
297: #endif
298: #ifdef B110
299: case B110: ospeed = 3; break;
300: #endif
301: #ifdef B134
302: case B134: ospeed = 4; break;
303: #endif
304: #ifdef B150
305: case B150: ospeed = 5; break;
306: #endif
307: #ifdef B200
308: case B200: ospeed = 6; break;
309: #endif
310: #ifdef B300
311: case B300: ospeed = 7; break;
312: #endif
313: #ifdef B600
314: case B600: ospeed = 8; break;
315: #endif
316: #ifdef B1200
317: case B1200: ospeed = 9; break;
318: #endif
319: #ifdef B1800
320: case B1800: ospeed = 10; break;
321: #endif
322: #ifdef B2400
323: case B2400: ospeed = 11; break;
324: #endif
325: #ifdef B4800
326: case B4800: ospeed = 12; break;
327: #endif
328: #ifdef B9600
329: case B9600: ospeed = 13; break;
330: #endif
331: #ifdef EXTA
332: case EXTA: ospeed = 14; break;
333: #endif
334: #ifdef EXTB
335: case EXTB: ospeed = 15; break;
336: #endif
337: #ifdef B57600
338: case B57600: ospeed = 16; break;
339: #endif
340: #ifdef B115200
341: case B115200: ospeed = 17; break;
342: #endif
343: default: ;
344: }
345: #endif
346: erase_char = s.c_cc[VERASE];
1.15 ! shadchin 347: #ifdef VERASE2
! 348: erase2_char = s.c_cc[VERASE2];
! 349: #endif
1.1 etheisen 350: kill_char = s.c_cc[VKILL];
351: #ifdef VWERASE
352: werase_char = s.c_cc[VWERASE];
353: #else
1.11 millert 354: werase_char = CONTROL('W');
1.1 etheisen 355: #endif
356:
357: /*
358: * Set the modes to the way we want them.
359: */
360: s.c_lflag &= ~(0
361: #ifdef ICANON
362: | ICANON
363: #endif
364: #ifdef ECHO
365: | ECHO
366: #endif
367: #ifdef ECHOE
368: | ECHOE
369: #endif
370: #ifdef ECHOK
371: | ECHOK
372: #endif
373: #if ECHONL
374: | ECHONL
375: #endif
376: );
377:
378: s.c_oflag |= (0
1.11 millert 379: #ifdef OXTABS
380: | OXTABS
1.1 etheisen 381: #else
382: #ifdef TAB3
383: | TAB3
384: #else
1.11 millert 385: #ifdef XTABS
386: | XTABS
1.1 etheisen 387: #endif
388: #endif
389: #endif
390: #ifdef OPOST
391: | OPOST
392: #endif
393: #ifdef ONLCR
394: | ONLCR
395: #endif
396: );
397:
398: s.c_oflag &= ~(0
399: #ifdef ONOEOT
400: | ONOEOT
401: #endif
402: #ifdef OCRNL
403: | OCRNL
404: #endif
405: #ifdef ONOCR
406: | ONOCR
407: #endif
408: #ifdef ONLRET
409: | ONLRET
410: #endif
411: );
412: s.c_cc[VMIN] = 1;
413: s.c_cc[VTIME] = 0;
1.11 millert 414: #ifdef VLNEXT
415: s.c_cc[VLNEXT] = 0;
416: #endif
417: #ifdef VDSUSP
418: s.c_cc[VDSUSP] = 0;
419: #endif
420: #if MUST_SET_LINE_DISCIPLINE
421: /*
422: * System's termios is broken; need to explicitly
423: * request TERMIODISC line discipline.
424: */
425: s.c_line = TERMIODISC;
426: #endif
1.1 etheisen 427: } else
428: {
429: /*
430: * Restore saved modes.
431: */
432: s = save_term;
433: }
1.13 millert 434: tcsetattr(tty, TCSASOFT | TCSADRAIN, &s);
1.11 millert 435: #if HAVE_FSYNC
436: fsync(tty);
437: #endif
438: #if MUST_SET_LINE_DISCIPLINE
439: if (!on)
440: {
441: /*
442: * Broken termios *ignores* any line discipline
443: * except TERMIODISC. A different old line discipline
444: * is therefore not restored, yet. Restore the old
445: * line discipline by hand.
446: */
447: ioctl(tty, TIOCSETD, &save_term.c_line);
448: }
449: #endif
1.1 etheisen 450: }
451: #else
452: #ifdef TCGETA
453: {
454: struct termio s;
455: static struct termio save_term;
1.11 millert 456: static int saved_term = 0;
1.1 etheisen 457:
458: if (on)
459: {
460: /*
461: * Get terminal modes.
462: */
1.11 millert 463: ioctl(tty, TCGETA, &s);
1.1 etheisen 464:
465: /*
466: * Save modes and set certain variables dependent on modes.
467: */
1.11 millert 468: if (!saved_term)
469: {
470: save_term = s;
471: saved_term = 1;
472: }
1.1 etheisen 473: #if HAVE_OSPEED
474: ospeed = s.c_cflag & CBAUD;
475: #endif
476: erase_char = s.c_cc[VERASE];
477: kill_char = s.c_cc[VKILL];
478: #ifdef VWERASE
479: werase_char = s.c_cc[VWERASE];
480: #else
1.11 millert 481: werase_char = CONTROL('W');
1.1 etheisen 482: #endif
483:
484: /*
485: * Set the modes to the way we want them.
486: */
487: s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
488: s.c_oflag |= (OPOST|ONLCR|TAB3);
489: s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
490: s.c_cc[VMIN] = 1;
491: s.c_cc[VTIME] = 0;
492: } else
493: {
494: /*
495: * Restore saved modes.
496: */
497: s = save_term;
498: }
1.11 millert 499: ioctl(tty, TCSETAW, &s);
1.1 etheisen 500: }
501: #else
1.11 millert 502: #ifdef TIOCGETP
1.1 etheisen 503: {
504: struct sgttyb s;
505: static struct sgttyb save_term;
1.11 millert 506: static int saved_term = 0;
1.1 etheisen 507:
508: if (on)
509: {
510: /*
511: * Get terminal modes.
512: */
1.11 millert 513: ioctl(tty, TIOCGETP, &s);
1.1 etheisen 514:
515: /*
516: * Save modes and set certain variables dependent on modes.
517: */
1.11 millert 518: if (!saved_term)
519: {
520: save_term = s;
521: saved_term = 1;
522: }
1.1 etheisen 523: #if HAVE_OSPEED
524: ospeed = s.sg_ospeed;
525: #endif
526: erase_char = s.sg_erase;
527: kill_char = s.sg_kill;
1.11 millert 528: werase_char = CONTROL('W');
1.1 etheisen 529:
530: /*
531: * Set the modes to the way we want them.
532: */
533: s.sg_flags |= CBREAK;
534: s.sg_flags &= ~(ECHO|XTABS);
535: } else
536: {
537: /*
538: * Restore saved modes.
539: */
540: s = save_term;
541: }
1.11 millert 542: ioctl(tty, TIOCSETN, &s);
543: }
544: #else
545: #ifdef _OSK
546: {
547: struct sgbuf s;
548: static struct sgbuf save_term;
549: static int saved_term = 0;
550:
551: if (on)
552: {
553: /*
554: * Get terminal modes.
555: */
556: _gs_opt(tty, &s);
557:
558: /*
559: * Save modes and set certain variables dependent on modes.
560: */
561: if (!saved_term)
562: {
563: save_term = s;
564: saved_term = 1;
565: }
566: erase_char = s.sg_bspch;
567: kill_char = s.sg_dlnch;
568: werase_char = CONTROL('W');
569:
570: /*
571: * Set the modes to the way we want them.
572: */
573: s.sg_echo = 0;
574: s.sg_eofch = 0;
575: s.sg_pause = 0;
576: s.sg_psch = 0;
577: } else
578: {
579: /*
580: * Restore saved modes.
581: */
582: s = save_term;
583: }
584: _ss_opt(tty, &s);
1.1 etheisen 585: }
1.11 millert 586: #else
587: /* MS-DOS, Windows, or OS2 */
588: #if OS2
589: /* OS2 */
590: LSIGNAL(SIGINT, SIG_IGN);
591: #endif
592: erase_char = '\b';
593: #if MSDOS_COMPILER==DJGPPC
594: kill_char = CONTROL('U');
595: /*
596: * So that when we shell out or run another program, its
597: * stdin is in cooked mode. We do not switch stdin to binary
598: * mode if fd0 is zero, since that means we were called before
599: * tty was reopened in open_getchr, in which case we would be
600: * changing the original stdin device outside less.
601: */
602: if (fd0 != 0)
603: setmode(0, on ? O_BINARY : O_TEXT);
604: #else
605: kill_char = ESC;
606: #endif
607: werase_char = CONTROL('W');
608: #endif
1.1 etheisen 609: #endif
610: #endif
611: #endif
612: curr_on = on;
613: }
614:
1.11 millert 615: #if !MSDOS_COMPILER
616: /*
617: * Some glue to prevent calling termcap functions if tgetent() failed.
618: */
619: static int hardcopy;
620:
621: static char *
622: ltget_env(capname)
623: char *capname;
1.1 etheisen 624: {
1.11 millert 625: char name[16];
1.15 ! shadchin 626: char *s;
1.1 etheisen 627:
1.15 ! shadchin 628: s = lgetenv("LESS_TERMCAP_DEBUG");
! 629: if (s != NULL && *s != '\0')
! 630: {
! 631: struct env { struct env *next; char *name; char *value; };
! 632: static struct env *envs = NULL;
! 633: struct env *p;
! 634: size_t len;
! 635: for (p = envs; p != NULL; p = p->next)
! 636: if (strcmp(p->name, capname) == 0)
! 637: return p->value;
! 638: p = (struct env *) ecalloc(1, sizeof(struct env));
! 639: p->name = save(capname);
! 640: len = strlen(capname) + 3;
! 641: p->value = (char *) ecalloc(len, sizeof(char));
! 642: snprintf(p->value, len, "<%s>", capname);
! 643: p->next = envs;
! 644: envs = p;
! 645: return p->value;
! 646: }
1.11 millert 647: strlcpy(name, "LESS_TERMCAP_", sizeof(name));
648: strlcat(name, capname, sizeof(name));
649: return (lgetenv(name));
1.1 etheisen 650: }
651:
1.11 millert 652: static int
653: ltgetflag(capname)
654: char *capname;
1.1 etheisen 655: {
1.11 millert 656: char *s;
1.1 etheisen 657:
1.11 millert 658: if ((s = ltget_env(capname)) != NULL)
659: return (*s != '\0' && *s != '0');
660: if (hardcopy)
661: return (0);
662: return (tgetflag(capname));
1.1 etheisen 663: }
664:
1.11 millert 665: static int
666: ltgetnum(capname)
667: char *capname;
1.1 etheisen 668: {
1.8 mpech 669: char *s;
1.1 etheisen 670:
1.11 millert 671: if ((s = ltget_env(capname)) != NULL)
672: return (atoi(s));
673: if (hardcopy)
674: return (-1);
675: return (tgetnum(capname));
676: }
1.5 millert 677:
1.11 millert 678: static char *
679: ltgetstr(capname, pp)
680: char *capname;
681: char **pp;
682: {
683: char *s;
1.1 etheisen 684:
1.11 millert 685: if ((s = ltget_env(capname)) != NULL)
686: return (s);
687: if (hardcopy)
688: return (NULL);
689: return (tgetstr(capname, pp));
1.1 etheisen 690: }
1.11 millert 691: #endif /* MSDOS_COMPILER */
1.1 etheisen 692:
693: /*
1.11 millert 694: * Get size of the output screen.
1.1 etheisen 695: */
696: public void
1.11 millert 697: scrsize()
1.1 etheisen 698: {
1.11 millert 699: register char *s;
700: int sys_height;
701: int sys_width;
702: #if !MSDOS_COMPILER
703: int n;
704: #endif
1.1 etheisen 705:
1.11 millert 706: #define DEF_SC_WIDTH 80
707: #if MSDOS_COMPILER
708: #define DEF_SC_HEIGHT 25
709: #else
710: #define DEF_SC_HEIGHT 24
711: #endif
1.1 etheisen 712:
713:
1.11 millert 714: sys_width = sys_height = 0;
1.1 etheisen 715:
1.11 millert 716: #if MSDOS_COMPILER==MSOFTC
1.1 etheisen 717: {
1.11 millert 718: struct videoconfig w;
719: _getvideoconfig(&w);
720: sys_height = w.numtextrows;
721: sys_width = w.numtextcols;
1.1 etheisen 722: }
1.11 millert 723: #else
724: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
1.1 etheisen 725: {
1.11 millert 726: struct text_info w;
727: gettextinfo(&w);
728: sys_height = w.screenheight;
729: sys_width = w.screenwidth;
1.1 etheisen 730: }
1.11 millert 731: #else
732: #if MSDOS_COMPILER==WIN32C
1.1 etheisen 733: {
1.11 millert 734: CONSOLE_SCREEN_BUFFER_INFO scr;
735: GetConsoleScreenBufferInfo(con_out, &scr);
736: sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1;
737: sys_width = scr.srWindow.Right - scr.srWindow.Left + 1;
1.1 etheisen 738: }
1.11 millert 739: #else
740: #if OS2
1.1 etheisen 741: {
1.11 millert 742: int s[2];
743: _scrsize(s);
744: sys_width = s[0];
745: sys_height = s[1];
746: /*
747: * When using terminal emulators for XFree86/OS2, the
748: * _scrsize function does not work well.
749: * Call the scrsize.exe program to get the window size.
750: */
751: windowid = getenv("WINDOWID");
752: if (windowid != NULL)
753: {
754: FILE *fd = popen("scrsize", "rt");
755: if (fd != NULL)
756: {
757: int w, h;
758: fscanf(fd, "%i %i", &w, &h);
759: if (w > 0 && h > 0)
760: {
761: sys_width = w;
762: sys_height = h;
763: }
764: pclose(fd);
765: }
766: }
1.1 etheisen 767: }
1.11 millert 768: #else
769: #ifdef TIOCGWINSZ
1.1 etheisen 770: {
1.11 millert 771: struct winsize w;
772: if (ioctl(2, TIOCGWINSZ, &w) == 0)
773: {
774: if (w.ws_row > 0)
775: sys_height = w.ws_row;
776: if (w.ws_col > 0)
777: sys_width = w.ws_col;
778: }
1.1 etheisen 779: }
1.11 millert 780: #else
781: #ifdef WIOCGETD
1.1 etheisen 782: {
1.11 millert 783: struct uwdata w;
784: if (ioctl(2, WIOCGETD, &w) == 0)
785: {
786: if (w.uw_height > 0)
787: sys_height = w.uw_height / w.uw_vs;
788: if (w.uw_width > 0)
789: sys_width = w.uw_width / w.uw_hs;
790: }
1.1 etheisen 791: }
1.11 millert 792: #endif
793: #endif
794: #endif
795: #endif
796: #endif
797: #endif
1.1 etheisen 798:
1.11 millert 799: if (sys_height > 0)
800: sc_height = sys_height;
801: else if ((s = lgetenv("LINES")) != NULL)
802: sc_height = atoi(s);
803: #if !MSDOS_COMPILER
804: else if ((n = ltgetnum("li")) > 0)
805: sc_height = n;
806: #endif
807: else
808: sc_height = DEF_SC_HEIGHT;
1.1 etheisen 809:
1.11 millert 810: if (sys_width > 0)
811: sc_width = sys_width;
812: else if ((s = lgetenv("COLUMNS")) != NULL)
813: sc_width = atoi(s);
814: #if !MSDOS_COMPILER
815: else if ((n = ltgetnum("co")) > 0)
816: sc_width = n;
817: #endif
818: else
819: sc_width = DEF_SC_WIDTH;
820: }
1.1 etheisen 821:
1.11 millert 822: #if MSDOS_COMPILER==MSOFTC
823: /*
824: * Figure out how many empty loops it takes to delay a millisecond.
825: */
826: static void
827: get_clock()
828: {
829: clock_t start;
830:
831: /*
832: * Get synchronized at the start of a tick.
833: */
834: start = clock();
835: while (clock() == start)
836: ;
837: /*
838: * Now count loops till the next tick.
839: */
840: start = clock();
841: msec_loops = 0;
842: while (clock() == start)
843: msec_loops++;
1.1 etheisen 844: /*
1.11 millert 845: * Convert from (loops per clock) to (loops per millisecond).
1.1 etheisen 846: */
1.11 millert 847: msec_loops *= CLOCKS_PER_SEC;
848: msec_loops /= 1000;
849: }
850:
851: /*
852: * Delay for a specified number of milliseconds.
853: */
854: static void
855: dummy_func()
856: {
857: static long delay_dummy = 0;
858: delay_dummy++;
1.1 etheisen 859: }
860:
861: static void
1.11 millert 862: delay(msec)
863: int msec;
1.1 etheisen 864: {
1.11 millert 865: long i;
866:
867: while (msec-- > 0)
868: {
869: for (i = 0; i < msec_loops; i++)
870: {
871: /*
872: * Make it look like we're doing something here,
873: * so the optimizer doesn't remove the whole loop.
874: */
875: dummy_func();
876: }
877: }
1.1 etheisen 878: }
879: #endif
880:
881: /*
1.11 millert 882: * Return the characters actually input by a "special" key.
1.1 etheisen 883: */
1.11 millert 884: public char *
885: special_key_str(key)
886: int key;
1.1 etheisen 887: {
1.11 millert 888: static char tbuf[40];
889: char *s;
890: #if MSDOS_COMPILER || OS2
891: static char k_right[] = { '\340', PCK_RIGHT, 0 };
892: static char k_left[] = { '\340', PCK_LEFT, 0 };
893: static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 };
894: static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 };
895: static char k_insert[] = { '\340', PCK_INSERT, 0 };
896: static char k_delete[] = { '\340', PCK_DELETE, 0 };
897: static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 };
898: static char k_ctl_backspace[] = { '\177', 0 };
899: static char k_home[] = { '\340', PCK_HOME, 0 };
900: static char k_end[] = { '\340', PCK_END, 0 };
901: static char k_up[] = { '\340', PCK_UP, 0 };
902: static char k_down[] = { '\340', PCK_DOWN, 0 };
903: static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 };
904: static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 };
905: static char k_pageup[] = { '\340', PCK_PAGEUP, 0 };
906: static char k_f1[] = { '\340', PCK_F1, 0 };
907: #endif
908: #if !MSDOS_COMPILER
909: char *sp = tbuf;
910: #endif
1.1 etheisen 911:
1.11 millert 912: switch (key)
913: {
914: #if OS2
1.1 etheisen 915: /*
1.11 millert 916: * If windowid is not NULL, assume less is executed in
917: * the XFree86 environment.
1.1 etheisen 918: */
1.11 millert 919: case SK_RIGHT_ARROW:
920: s = windowid ? ltgetstr("kr", &sp) : k_right;
921: break;
922: case SK_LEFT_ARROW:
923: s = windowid ? ltgetstr("kl", &sp) : k_left;
924: break;
925: case SK_UP_ARROW:
926: s = windowid ? ltgetstr("ku", &sp) : k_up;
927: break;
928: case SK_DOWN_ARROW:
929: s = windowid ? ltgetstr("kd", &sp) : k_down;
930: break;
931: case SK_PAGE_UP:
932: s = windowid ? ltgetstr("kP", &sp) : k_pageup;
933: break;
934: case SK_PAGE_DOWN:
935: s = windowid ? ltgetstr("kN", &sp) : k_pagedown;
936: break;
937: case SK_HOME:
938: s = windowid ? ltgetstr("kh", &sp) : k_home;
939: break;
940: case SK_END:
941: s = windowid ? ltgetstr("@7", &sp) : k_end;
942: break;
943: case SK_DELETE:
944: if (windowid)
945: {
946: s = ltgetstr("kD", &sp);
947: if (s == NULL)
948: {
949: tbuf[0] = '\177';
950: tbuf[1] = '\0';
951: s = tbuf;
952: }
953: } else
954: s = k_delete;
955: break;
956: #endif
957: #if MSDOS_COMPILER
958: case SK_RIGHT_ARROW:
959: s = k_right;
960: break;
961: case SK_LEFT_ARROW:
962: s = k_left;
963: break;
964: case SK_UP_ARROW:
965: s = k_up;
966: break;
967: case SK_DOWN_ARROW:
968: s = k_down;
969: break;
970: case SK_PAGE_UP:
971: s = k_pageup;
972: break;
973: case SK_PAGE_DOWN:
974: s = k_pagedown;
975: break;
976: case SK_HOME:
977: s = k_home;
978: break;
979: case SK_END:
980: s = k_end;
981: break;
982: case SK_DELETE:
983: s = k_delete;
984: break;
985: #endif
986: #if MSDOS_COMPILER || OS2
987: case SK_INSERT:
988: s = k_insert;
989: break;
990: case SK_CTL_LEFT_ARROW:
991: s = k_ctl_left;
992: break;
993: case SK_CTL_RIGHT_ARROW:
994: s = k_ctl_right;
995: break;
996: case SK_CTL_BACKSPACE:
997: s = k_ctl_backspace;
998: break;
999: case SK_CTL_DELETE:
1000: s = k_ctl_delete;
1001: break;
1002: case SK_F1:
1003: s = k_f1;
1004: break;
1005: case SK_BACKTAB:
1006: s = k_backtab;
1007: break;
1008: #else
1009: case SK_RIGHT_ARROW:
1010: s = ltgetstr("kr", &sp);
1011: break;
1012: case SK_LEFT_ARROW:
1013: s = ltgetstr("kl", &sp);
1014: break;
1015: case SK_UP_ARROW:
1016: s = ltgetstr("ku", &sp);
1017: break;
1018: case SK_DOWN_ARROW:
1019: s = ltgetstr("kd", &sp);
1020: break;
1021: case SK_PAGE_UP:
1022: s = ltgetstr("kP", &sp);
1023: break;
1024: case SK_PAGE_DOWN:
1025: s = ltgetstr("kN", &sp);
1026: break;
1027: case SK_HOME:
1028: s = ltgetstr("kh", &sp);
1029: break;
1030: case SK_END:
1031: s = ltgetstr("@7", &sp);
1032: break;
1033: case SK_DELETE:
1034: s = ltgetstr("kD", &sp);
1035: if (s == NULL)
1.1 etheisen 1036: {
1.11 millert 1037: tbuf[0] = '\177';
1038: tbuf[1] = '\0';
1039: s = tbuf;
1040: }
1041: break;
1042: #endif
1043: case SK_CONTROL_K:
1044: tbuf[0] = CONTROL('K');
1045: tbuf[1] = '\0';
1046: s = tbuf;
1047: break;
1048: default:
1049: return (NULL);
1050: }
1051: return (s);
1052: }
1053:
1054: /*
1055: * Get terminal capabilities via termcap.
1056: */
1057: public void
1058: get_term()
1059: {
1060: #if MSDOS_COMPILER
1061: auto_wrap = 1;
1062: ignaw = 0;
1063: can_goto_line = 1;
1064: clear_bg = 1;
1065: /*
1066: * Set up default colors.
1067: * The xx_s_width and xx_e_width vars are already initialized to 0.
1068: */
1069: #if MSDOS_COMPILER==MSOFTC
1070: sy_bg_color = _getbkcolor();
1071: sy_fg_color = _gettextcolor();
1072: get_clock();
1073: #else
1074: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
1075: {
1076: struct text_info w;
1077: gettextinfo(&w);
1078: sy_bg_color = (w.attribute >> 4) & 0x0F;
1079: sy_fg_color = (w.attribute >> 0) & 0x0F;
1080: }
1081: #else
1082: #if MSDOS_COMPILER==WIN32C
1083: {
1084: DWORD nread;
1085: CONSOLE_SCREEN_BUFFER_INFO scr;
1086:
1087: con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE);
1088: /*
1089: * Always open stdin in binary. Note this *must* be done
1090: * before any file operations have been done on fd0.
1091: */
1092: SET_BINARY(0);
1093: GetConsoleScreenBufferInfo(con_out, &scr);
1094: ReadConsoleOutputAttribute(con_out, &curr_attr,
1095: 1, scr.dwCursorPosition, &nread);
1096: sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */
1097: sy_fg_color = curr_attr & FG_COLORS;
1098: }
1099: #endif
1100: #endif
1101: #endif
1102: nm_fg_color = sy_fg_color;
1103: nm_bg_color = sy_bg_color;
1104: bo_fg_color = 11;
1105: bo_bg_color = 0;
1106: ul_fg_color = 9;
1107: ul_bg_color = 0;
1108: so_fg_color = 15;
1109: so_bg_color = 9;
1110: bl_fg_color = 15;
1111: bl_bg_color = 0;
1112:
1113: /*
1114: * Get size of the screen.
1115: */
1116: scrsize();
1117: pos_init();
1118:
1119:
1120: #else /* !MSDOS_COMPILER */
1121:
1122: char *sp;
1123: register char *t1, *t2;
1124: char *term;
1125: char termbuf[TERMBUF_SIZE];
1126:
1127: static char sbuf[TERMSBUF_SIZE];
1128:
1129: #if OS2
1130: /*
1131: * Make sure the termcap database is available.
1132: */
1133: sp = lgetenv("TERMCAP");
1134: if (sp == NULL || *sp == '\0')
1135: {
1136: char *termcap;
1137: if ((sp = homefile("termcap.dat")) != NULL)
1138: {
1139: size_t len = strlen(sp) + 9;
1140: termcap = (char *) ecalloc(len, sizeof(char));
1141: snprintf(termcap, len, "TERMCAP=%s", sp);
1142: free(sp);
1143: putenv(termcap);
1.1 etheisen 1144: }
1145: }
1146: #endif
1147: /*
1148: * Find out what kind of terminal this is.
1149: */
1.11 millert 1150: if ((term = lgetenv("TERM")) == NULL)
1.1 etheisen 1151: term = DEFAULT_TERM;
1.11 millert 1152: hardcopy = 0;
1.15 ! shadchin 1153: if (tgetent(termbuf, term) != TGETENT_OK)
1.11 millert 1154: hardcopy = 1;
1155: if (ltgetflag("hc"))
1156: hardcopy = 1;
1.1 etheisen 1157:
1158: /*
1159: * Get size of the screen.
1160: */
1161: scrsize();
1162: pos_init();
1163:
1.11 millert 1164: auto_wrap = ltgetflag("am");
1165: ignaw = ltgetflag("xn");
1166: above_mem = ltgetflag("da");
1167: below_mem = ltgetflag("db");
1168: clear_bg = ltgetflag("ut");
1.1 etheisen 1169:
1170: /*
1171: * Assumes termcap variable "sg" is the printing width of:
1172: * the standout sequence, the end standout sequence,
1173: * the underline sequence, the end underline sequence,
1174: * the boldface sequence, and the end boldface sequence.
1175: */
1.11 millert 1176: if ((so_s_width = ltgetnum("sg")) < 0)
1.1 etheisen 1177: so_s_width = 0;
1178: so_e_width = so_s_width;
1179:
1180: bo_s_width = bo_e_width = so_s_width;
1181: ul_s_width = ul_e_width = so_s_width;
1182: bl_s_width = bl_e_width = so_s_width;
1183:
1184: #if HILITE_SEARCH
1185: if (so_s_width > 0 || so_e_width > 0)
1186: /*
1187: * Disable highlighting by default on magic cookie terminals.
1188: * Turning on highlighting might change the displayed width
1189: * of a line, causing the display to get messed up.
1190: * The user can turn it back on with -g,
1191: * but she won't like the results.
1192: */
1193: hilite_search = 0;
1194: #endif
1195:
1196: /*
1197: * Get various string-valued capabilities.
1198: */
1199: sp = sbuf;
1200:
1201: #if HAVE_OSPEED
1.11 millert 1202: sc_pad = ltgetstr("pc", &sp);
1.1 etheisen 1203: if (sc_pad != NULL)
1204: PC = *sc_pad;
1205: #endif
1206:
1.11 millert 1207: sc_s_keypad = ltgetstr("ks", &sp);
1.1 etheisen 1208: if (sc_s_keypad == NULL)
1209: sc_s_keypad = "";
1.11 millert 1210: sc_e_keypad = ltgetstr("ke", &sp);
1.1 etheisen 1211: if (sc_e_keypad == NULL)
1212: sc_e_keypad = "";
1213:
1.15 ! shadchin 1214: sc_init = ltgetstr("ti", &sp);
1.1 etheisen 1215: if (sc_init == NULL)
1216: sc_init = "";
1.11 millert 1217:
1.15 ! shadchin 1218: sc_deinit= ltgetstr("te", &sp);
1.1 etheisen 1219: if (sc_deinit == NULL)
1220: sc_deinit = "";
1221:
1.11 millert 1222: sc_eol_clear = ltgetstr("ce", &sp);
1223: if (sc_eol_clear == NULL || *sc_eol_clear == '\0')
1.1 etheisen 1224: {
1.11 millert 1225: missing_cap = 1;
1.1 etheisen 1226: sc_eol_clear = "";
1227: }
1228:
1.11 millert 1229: sc_eos_clear = ltgetstr("cd", &sp);
1230: if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0'))
1.1 etheisen 1231: {
1.11 millert 1232: missing_cap = 1;
1.15 ! shadchin 1233: sc_eos_clear = "";
1.1 etheisen 1234: }
1235:
1.11 millert 1236: sc_clear = ltgetstr("cl", &sp);
1237: if (sc_clear == NULL || *sc_clear == '\0')
1.1 etheisen 1238: {
1.11 millert 1239: missing_cap = 1;
1.1 etheisen 1240: sc_clear = "\n\n";
1241: }
1242:
1.11 millert 1243: sc_move = ltgetstr("cm", &sp);
1244: if (sc_move == NULL || *sc_move == '\0')
1.1 etheisen 1245: {
1246: /*
1247: * This is not an error here, because we don't
1248: * always need sc_move.
1249: * We need it only if we don't have home or lower-left.
1250: */
1251: sc_move = "";
1252: can_goto_line = 0;
1253: } else
1254: can_goto_line = 1;
1255:
1.11 millert 1256: tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp);
1257: tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp);
1258: tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp);
1259: tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp);
1.1 etheisen 1260:
1.11 millert 1261: sc_visual_bell = ltgetstr("vb", &sp);
1262: if (sc_visual_bell == NULL)
1.1 etheisen 1263: sc_visual_bell = "";
1264:
1.11 millert 1265: if (ltgetflag("bs"))
1.1 etheisen 1266: sc_backspace = "\b";
1267: else
1268: {
1.11 millert 1269: sc_backspace = ltgetstr("bc", &sp);
1.1 etheisen 1270: if (sc_backspace == NULL || *sc_backspace == '\0')
1271: sc_backspace = "\b";
1272: }
1273:
1274: /*
1275: * Choose between using "ho" and "cm" ("home" and "cursor move")
1276: * to move the cursor to the upper left corner of the screen.
1277: */
1.11 millert 1278: t1 = ltgetstr("ho", &sp);
1279: if (t1 == NULL)
1.1 etheisen 1280: t1 = "";
1281: if (*sc_move == '\0')
1282: t2 = "";
1283: else
1284: {
1.11 millert 1285: strlcpy(sp, tgoto(sc_move, 0, 0), sbuf + sizeof(sbuf) - sp);
1.1 etheisen 1286: t2 = sp;
1287: sp += strlen(sp) + 1;
1288: }
1.11 millert 1289: sc_home = cheaper(t1, t2, "|\b^");
1.1 etheisen 1290:
1291: /*
1292: * Choose between using "ll" and "cm" ("lower left" and "cursor move")
1293: * to move the cursor to the lower left corner of the screen.
1294: */
1.11 millert 1295: t1 = ltgetstr("ll", &sp);
1296: if (t1 == NULL)
1.1 etheisen 1297: t1 = "";
1298: if (*sc_move == '\0')
1299: t2 = "";
1300: else
1301: {
1.11 millert 1302: strlcpy(sp, tgoto(sc_move, 0, sc_height-1),
1303: sbuf + sizeof(sbuf) - sp);
1.1 etheisen 1304: t2 = sp;
1305: sp += strlen(sp) + 1;
1306: }
1.11 millert 1307: sc_lower_left = cheaper(t1, t2, "\r");
1.1 etheisen 1308:
1309: /*
1.15 ! shadchin 1310: * Get carriage return string.
! 1311: */
! 1312: sc_return = ltgetstr("cr", &sp);
! 1313: if (sc_return == NULL)
! 1314: sc_return = "\r";
! 1315:
! 1316: /*
1.1 etheisen 1317: * Choose between using "al" or "sr" ("add line" or "scroll reverse")
1318: * to add a line at the top of the screen.
1319: */
1.11 millert 1320: t1 = ltgetstr("al", &sp);
1321: if (t1 == NULL)
1.1 etheisen 1322: t1 = "";
1.11 millert 1323: t2 = ltgetstr("sr", &sp);
1324: if (t2 == NULL)
1.1 etheisen 1325: t2 = "";
1326: #if OS2
1327: if (*t1 == '\0' && *t2 == '\0')
1328: sc_addline = "";
1329: else
1330: #endif
1331: if (above_mem)
1332: sc_addline = t1;
1333: else
1.11 millert 1334: sc_addline = cheaper(t1, t2, "");
1.1 etheisen 1335: if (*sc_addline == '\0')
1336: {
1337: /*
1338: * Force repaint on any backward movement.
1339: */
1.11 millert 1340: no_back_scroll = 1;
1.1 etheisen 1341: }
1.11 millert 1342: #endif /* MSDOS_COMPILER */
1.1 etheisen 1343: }
1344:
1.11 millert 1345: #if !MSDOS_COMPILER
1.1 etheisen 1346: /*
1347: * Return the cost of displaying a termcap string.
1348: * We use the trick of calling tputs, but as a char printing function
1349: * we give it inc_costcount, which just increments "costcount".
1350: * This tells us how many chars would be printed by using this string.
1351: * {{ Couldn't we just use strlen? }}
1352: */
1353: static int costcount;
1354:
1355: /*ARGSUSED*/
1356: static int
1357: inc_costcount(c)
1358: int c;
1359: {
1360: costcount++;
1361: return (c);
1362: }
1363:
1364: static int
1365: cost(t)
1366: char *t;
1367: {
1368: costcount = 0;
1369: tputs(t, sc_height, inc_costcount);
1370: return (costcount);
1371: }
1372:
1373: /*
1374: * Return the "best" of the two given termcap strings.
1375: * The best, if both exist, is the one with the lower
1376: * cost (see cost() function).
1377: */
1378: static char *
1.11 millert 1379: cheaper(t1, t2, def)
1.1 etheisen 1380: char *t1, *t2;
1381: char *def;
1382: {
1383: if (*t1 == '\0' && *t2 == '\0')
1384: {
1.11 millert 1385: missing_cap = 1;
1.1 etheisen 1386: return (def);
1387: }
1388: if (*t1 == '\0')
1389: return (t2);
1390: if (*t2 == '\0')
1391: return (t1);
1392: if (cost(t1) < cost(t2))
1393: return (t1);
1394: return (t2);
1395: }
1396:
1.11 millert 1397: static void
1398: tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp)
1399: char *incap;
1400: char *outcap;
1401: char **instr;
1402: char **outstr;
1403: char *def_instr;
1404: char *def_outstr;
1405: char **spp;
1406: {
1407: *instr = ltgetstr(incap, spp);
1408: if (*instr == NULL)
1409: {
1410: /* Use defaults. */
1411: *instr = def_instr;
1412: *outstr = def_outstr;
1413: return;
1414: }
1415:
1416: *outstr = ltgetstr(outcap, spp);
1417: if (*outstr == NULL)
1418: /* No specific out capability; use "me". */
1419: *outstr = ltgetstr("me", spp);
1420: if (*outstr == NULL)
1421: /* Don't even have "me"; use a null string. */
1422: *outstr = "";
1423: }
1424:
1425: #endif /* MSDOS_COMPILER */
1426:
1.1 etheisen 1427:
1428: /*
1429: * Below are the functions which perform all the
1430: * terminal-specific screen manipulation.
1431: */
1432:
1433:
1.11 millert 1434: #if MSDOS_COMPILER
1435:
1436: #if MSDOS_COMPILER==WIN32C
1437: static void
1438: _settextposition(int row, int col)
1439: {
1440: COORD cpos;
1441: CONSOLE_SCREEN_BUFFER_INFO csbi;
1442:
1443: GetConsoleScreenBufferInfo(con_out, &csbi);
1444: cpos.X = csbi.srWindow.Left + (col - 1);
1445: cpos.Y = csbi.srWindow.Top + (row - 1);
1446: SetConsoleCursorPosition(con_out, cpos);
1447: }
1448: #endif
1449:
1450: /*
1451: * Initialize the screen to the correct color at startup.
1452: */
1453: static void
1454: initcolor()
1455: {
1456: SETCOLORS(nm_fg_color, nm_bg_color);
1457: #if 0
1458: /*
1459: * This clears the screen at startup. This is different from
1460: * the behavior of other versions of less. Disable it for now.
1461: */
1462: char *blanks;
1463: int row;
1464: int col;
1465:
1466: /*
1467: * Create a complete, blank screen using "normal" colors.
1468: */
1469: SETCOLORS(nm_fg_color, nm_bg_color);
1470: blanks = (char *) ecalloc(width+1, sizeof(char));
1471: for (col = 0; col < sc_width; col++)
1472: blanks[col] = ' ';
1473: blanks[sc_width] = '\0';
1474: for (row = 0; row < sc_height; row++)
1475: _outtext(blanks);
1476: free(blanks);
1477: #endif
1478: }
1479: #endif
1480:
1481: #if MSDOS_COMPILER==WIN32C
1482:
1483: /*
1484: * Termcap-like init with a private win32 console.
1485: */
1486: static void
1487: win32_init_term()
1488: {
1489: CONSOLE_SCREEN_BUFFER_INFO scr;
1490: COORD size;
1491:
1492: if (con_out_save == INVALID_HANDLE_VALUE)
1493: return;
1494:
1495: GetConsoleScreenBufferInfo(con_out_save, &scr);
1496:
1497: if (con_out_ours == INVALID_HANDLE_VALUE)
1498: {
1499: /*
1500: * Create our own screen buffer, so that we
1501: * may restore the original when done.
1502: */
1503: con_out_ours = CreateConsoleScreenBuffer(
1504: GENERIC_WRITE | GENERIC_READ,
1505: FILE_SHARE_WRITE | FILE_SHARE_READ,
1506: (LPSECURITY_ATTRIBUTES) NULL,
1507: CONSOLE_TEXTMODE_BUFFER,
1508: (LPVOID) NULL);
1509: }
1510:
1511: size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
1512: size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
1513: SetConsoleScreenBufferSize(con_out_ours, size);
1514: SetConsoleActiveScreenBuffer(con_out_ours);
1515: con_out = con_out_ours;
1516: }
1517:
1518: /*
1519: * Restore the startup console.
1520: */
1521: static void
1522: win32_deinit_term()
1523: {
1524: if (con_out_save == INVALID_HANDLE_VALUE)
1525: return;
1526: if (quitting)
1527: (void) CloseHandle(con_out_ours);
1528: SetConsoleActiveScreenBuffer(con_out_save);
1529: con_out = con_out_save;
1530: }
1531:
1532: #endif
1533:
1.1 etheisen 1534: /*
1535: * Initialize terminal
1536: */
1537: public void
1538: init()
1539: {
1.11 millert 1540: #if !MSDOS_COMPILER
1541: if (!no_init)
1542: tputs(sc_init, sc_height, putchr);
1543: if (!no_keypad)
1544: tputs(sc_s_keypad, sc_height, putchr);
1.15 ! shadchin 1545: if (top_scroll)
! 1546: {
! 1547: int i;
! 1548:
! 1549: /*
! 1550: * This is nice to terminals with no alternate screen,
! 1551: * but with saved scrolled-off-the-top lines. This way,
! 1552: * no previous line is lost, but we start with a whole
! 1553: * screen to ourself.
! 1554: */
! 1555: for (i = 1; i < sc_height; i++)
! 1556: putchr('\n');
! 1557: } else
! 1558: line_left();
1.11 millert 1559: #else
1560: #if MSDOS_COMPILER==WIN32C
1561: if (!no_init)
1562: win32_init_term();
1563: #endif
1564: initcolor();
1565: flush();
1566: #endif
1.1 etheisen 1567: init_done = 1;
1568: }
1569:
1570: /*
1571: * Deinitialize terminal
1572: */
1573: public void
1574: deinit()
1575: {
1576: if (!init_done)
1577: return;
1.11 millert 1578: #if !MSDOS_COMPILER
1579: if (!no_keypad)
1580: tputs(sc_e_keypad, sc_height, putchr);
1581: if (!no_init)
1582: tputs(sc_deinit, sc_height, putchr);
1583: #else
1584: /* Restore system colors. */
1585: SETCOLORS(sy_fg_color, sy_bg_color);
1586: #if MSDOS_COMPILER==WIN32C
1587: if (!no_init)
1588: win32_deinit_term();
1589: #else
1590: /* Need clreol to make SETCOLORS take effect. */
1591: clreol();
1592: #endif
1593: #endif
1.1 etheisen 1594: init_done = 0;
1595: }
1596:
1597: /*
1598: * Home cursor (move to upper left corner of screen).
1599: */
1600: public void
1601: home()
1602: {
1.11 millert 1603: #if !MSDOS_COMPILER
1.1 etheisen 1604: tputs(sc_home, 1, putchr);
1.11 millert 1605: #else
1606: flush();
1607: _settextposition(1,1);
1608: #endif
1.1 etheisen 1609: }
1610:
1611: /*
1612: * Add a blank line (called with cursor at home).
1613: * Should scroll the display down.
1614: */
1615: public void
1616: add_line()
1617: {
1.11 millert 1618: #if !MSDOS_COMPILER
1.1 etheisen 1619: tputs(sc_addline, sc_height, putchr);
1.11 millert 1620: #else
1621: flush();
1622: #if MSDOS_COMPILER==MSOFTC
1623: _scrolltextwindow(_GSCROLLDOWN);
1624: _settextposition(1,1);
1625: #else
1626: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
1627: movetext(1,1, sc_width,sc_height-1, 1,2);
1628: gotoxy(1,1);
1629: clreol();
1630: #else
1631: #if MSDOS_COMPILER==WIN32C
1632: {
1633: CHAR_INFO fillchar;
1634: SMALL_RECT rcSrc, rcClip;
1635: COORD new_org;
1636: CONSOLE_SCREEN_BUFFER_INFO csbi;
1637:
1638: GetConsoleScreenBufferInfo(con_out,&csbi);
1639:
1640: /* The clip rectangle is the entire visible screen. */
1641: rcClip.Left = csbi.srWindow.Left;
1642: rcClip.Top = csbi.srWindow.Top;
1643: rcClip.Right = csbi.srWindow.Right;
1644: rcClip.Bottom = csbi.srWindow.Bottom;
1645:
1646: /* The source rectangle is the visible screen minus the last line. */
1647: rcSrc = rcClip;
1648: rcSrc.Bottom--;
1649:
1650: /* Move the top left corner of the source window down one row. */
1651: new_org.X = rcSrc.Left;
1652: new_org.Y = rcSrc.Top + 1;
1653:
1654: /* Fill the right character and attributes. */
1655: fillchar.Char.AsciiChar = ' ';
1656: curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
1657: fillchar.Attributes = curr_attr;
1658: ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
1659: _settextposition(1,1);
1660: }
1661: #endif
1662: #endif
1663: #endif
1664: #endif
1665: }
1666:
1667: #if 0
1668: /*
1669: * Remove the n topmost lines and scroll everything below it in the
1670: * window upward. This is needed to stop leaking the topmost line
1671: * into the scrollback buffer when we go down-one-line (in WIN32).
1672: */
1673: public void
1674: remove_top(n)
1675: int n;
1676: {
1677: #if MSDOS_COMPILER==WIN32C
1678: SMALL_RECT rcSrc, rcClip;
1679: CHAR_INFO fillchar;
1680: COORD new_org;
1681: CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
1682:
1683: if (n >= sc_height - 1)
1684: {
1685: clear();
1686: home();
1687: return;
1688: }
1689:
1690: flush();
1691:
1692: GetConsoleScreenBufferInfo(con_out, &csbi);
1693:
1694: /* Get the extent of all-visible-rows-but-the-last. */
1695: rcSrc.Left = csbi.srWindow.Left;
1696: rcSrc.Top = csbi.srWindow.Top + n;
1697: rcSrc.Right = csbi.srWindow.Right;
1698: rcSrc.Bottom = csbi.srWindow.Bottom;
1699:
1700: /* Get the clip rectangle. */
1701: rcClip.Left = rcSrc.Left;
1702: rcClip.Top = csbi.srWindow.Top;
1703: rcClip.Right = rcSrc.Right;
1704: rcClip.Bottom = rcSrc.Bottom ;
1705:
1706: /* Move the source window up n rows. */
1707: new_org.X = rcSrc.Left;
1708: new_org.Y = rcSrc.Top - n;
1709:
1710: /* Fill the right character and attributes. */
1711: fillchar.Char.AsciiChar = ' ';
1712: curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
1713: fillchar.Attributes = curr_attr;
1714:
1715: ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
1716:
1717: /* Position cursor on first blank line. */
1718: goto_line(sc_height - n - 1);
1719: #endif
1.1 etheisen 1720: }
1.11 millert 1721: #endif
1722:
1723: #if MSDOS_COMPILER==WIN32C
1724: /*
1725: * Clear the screen.
1726: */
1727: static void
1728: win32_clear()
1729: {
1730: /*
1731: * This will clear only the currently visible rows of the NT
1732: * console buffer, which means none of the precious scrollback
1733: * rows are touched making for faster scrolling. Note that, if
1734: * the window has fewer columns than the console buffer (i.e.
1735: * there is a horizontal scrollbar as well), the entire width
1736: * of the visible rows will be cleared.
1737: */
1738: COORD topleft;
1739: DWORD nchars;
1740: DWORD winsz;
1741: CONSOLE_SCREEN_BUFFER_INFO csbi;
1742:
1743: /* get the number of cells in the current buffer */
1744: GetConsoleScreenBufferInfo(con_out, &csbi);
1745: winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
1746: topleft.X = 0;
1747: topleft.Y = csbi.srWindow.Top;
1748:
1749: curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
1750: FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars);
1751: FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars);
1752: }
1753:
1754: /*
1755: * Remove the n topmost lines and scroll everything below it in the
1756: * window upward.
1757: */
1758: public void
1759: win32_scroll_up(n)
1760: int n;
1761: {
1762: SMALL_RECT rcSrc, rcClip;
1763: CHAR_INFO fillchar;
1764: COORD topleft;
1765: COORD new_org;
1766: DWORD nchars;
1767: DWORD size;
1768: CONSOLE_SCREEN_BUFFER_INFO csbi;
1769:
1770: if (n <= 0)
1771: return;
1772:
1773: if (n >= sc_height - 1)
1774: {
1775: win32_clear();
1776: _settextposition(1,1);
1777: return;
1778: }
1779:
1780: /* Get the extent of what will remain visible after scrolling. */
1781: GetConsoleScreenBufferInfo(con_out, &csbi);
1782: rcSrc.Left = csbi.srWindow.Left;
1783: rcSrc.Top = csbi.srWindow.Top + n;
1784: rcSrc.Right = csbi.srWindow.Right;
1785: rcSrc.Bottom = csbi.srWindow.Bottom;
1786:
1787: /* Get the clip rectangle. */
1788: rcClip.Left = rcSrc.Left;
1789: rcClip.Top = csbi.srWindow.Top;
1790: rcClip.Right = rcSrc.Right;
1791: rcClip.Bottom = rcSrc.Bottom ;
1792:
1793: /* Move the source text to the top of the screen. */
1794: new_org.X = rcSrc.Left;
1.15 ! shadchin 1795: new_org.Y = rcClip.Top;
1.11 millert 1796:
1797: /* Fill the right character and attributes. */
1798: fillchar.Char.AsciiChar = ' ';
1799: fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color);
1800:
1801: /* Scroll the window. */
1802: SetConsoleTextAttribute(con_out, fillchar.Attributes);
1803: ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar);
1804:
1805: /* Clear remaining lines at bottom. */
1806: topleft.X = csbi.dwCursorPosition.X;
1807: topleft.Y = rcSrc.Bottom - n;
1808: size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X);
1809: FillConsoleOutputCharacter(con_out, ' ', size, topleft,
1810: &nchars);
1811: FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft,
1812: &nchars);
1813: SetConsoleTextAttribute(con_out, curr_attr);
1814:
1815: /* Move cursor n lines up from where it was. */
1816: csbi.dwCursorPosition.Y -= n;
1817: SetConsoleCursorPosition(con_out, csbi.dwCursorPosition);
1818: }
1819: #endif
1.1 etheisen 1820:
1821: /*
1822: * Move cursor to lower left corner of screen.
1823: */
1824: public void
1825: lower_left()
1826: {
1.11 millert 1827: #if !MSDOS_COMPILER
1.1 etheisen 1828: tputs(sc_lower_left, 1, putchr);
1.11 millert 1829: #else
1830: flush();
1831: _settextposition(sc_height, 1);
1832: #endif
1833: }
1834:
1835: /*
1.15 ! shadchin 1836: * Move cursor to left position of current line.
! 1837: */
! 1838: public void
! 1839: line_left()
! 1840: {
! 1841: #if !MSDOS_COMPILER
! 1842: tputs(sc_return, 1, putchr);
! 1843: #else
! 1844: int row;
! 1845: flush();
! 1846: #if MSDOS_COMPILER==WIN32C
! 1847: {
! 1848: CONSOLE_SCREEN_BUFFER_INFO scr;
! 1849: GetConsoleScreenBufferInfo(con_out, &scr);
! 1850: row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1;
! 1851: }
! 1852: #else
! 1853: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
! 1854: row = wherey();
! 1855: #else
! 1856: {
! 1857: struct rccoord tpos = _gettextposition();
! 1858: row = tpos.row;
! 1859: }
! 1860: #endif
! 1861: #endif
! 1862: _settextposition(row, 1);
! 1863: #endif
! 1864: }
! 1865:
! 1866: /*
1.11 millert 1867: * Check if the console size has changed and reset internals
1868: * (in lieu of SIGWINCH for WIN32).
1869: */
1870: public void
1871: check_winch()
1872: {
1873: #if MSDOS_COMPILER==WIN32C
1874: CONSOLE_SCREEN_BUFFER_INFO scr;
1875: COORD size;
1876:
1877: if (con_out == INVALID_HANDLE_VALUE)
1878: return;
1879:
1880: flush();
1881: GetConsoleScreenBufferInfo(con_out, &scr);
1882: size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1;
1883: size.X = scr.srWindow.Right - scr.srWindow.Left + 1;
1884: if (size.Y != sc_height || size.X != sc_width)
1885: {
1886: sc_height = size.Y;
1887: sc_width = size.X;
1888: if (!no_init && con_out_ours == con_out)
1889: SetConsoleScreenBufferSize(con_out, size);
1890: pos_init();
1891: wscroll = (sc_height + 1) / 2;
1892: screen_trashed = 1;
1893: }
1894: #endif
1.1 etheisen 1895: }
1896:
1897: /*
1898: * Goto a specific line on the screen.
1899: */
1900: public void
1901: goto_line(slinenum)
1902: int slinenum;
1903: {
1.11 millert 1904: #if !MSDOS_COMPILER
1905: tputs(tgoto(sc_move, 0, slinenum), 1, putchr);
1906: #else
1907: flush();
1908: _settextposition(slinenum+1, 1);
1909: #endif
1.1 etheisen 1910: }
1911:
1.11 millert 1912: #if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC
1.1 etheisen 1913: /*
1.11 millert 1914: * Create an alternate screen which is all white.
1915: * This screen is used to create a "flash" effect, by displaying it
1916: * briefly and then switching back to the normal screen.
1917: * {{ Yuck! There must be a better way to get a visual bell. }}
1.1 etheisen 1918: */
1.11 millert 1919: static void
1920: create_flash()
1.1 etheisen 1921: {
1.11 millert 1922: #if MSDOS_COMPILER==MSOFTC
1923: struct videoconfig w;
1924: char *blanks;
1925: int row, col;
1926:
1927: _getvideoconfig(&w);
1928: videopages = w.numvideopages;
1929: if (videopages < 2)
1930: {
1.15 ! shadchin 1931: at_enter(AT_STANDOUT);
! 1932: at_exit();
1.11 millert 1933: } else
1934: {
1935: _setactivepage(1);
1.15 ! shadchin 1936: at_enter(AT_STANDOUT);
1.11 millert 1937: blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
1938: for (col = 0; col < w.numtextcols; col++)
1939: blanks[col] = ' ';
1940: for (row = w.numtextrows; row > 0; row--)
1941: _outmem(blanks, w.numtextcols);
1942: _setactivepage(0);
1943: _setvisualpage(0);
1944: free(blanks);
1.15 ! shadchin 1945: at_exit();
1.11 millert 1946: }
1947: #else
1948: #if MSDOS_COMPILER==BORLANDC
1949: register int n;
1950:
1951: whitescreen = (unsigned short *)
1952: malloc(sc_width * sc_height * sizeof(short));
1953: if (whitescreen == NULL)
1954: return;
1955: for (n = 0; n < sc_width * sc_height; n++)
1956: whitescreen[n] = 0x7020;
1957: #else
1958: #if MSDOS_COMPILER==WIN32C
1959: register int n;
1960:
1961: whitescreen = (WORD *)
1962: malloc(sc_height * sc_width * sizeof(WORD));
1963: if (whitescreen == NULL)
1964: return;
1965: /* Invert the standard colors. */
1966: for (n = 0; n < sc_width * sc_height; n++)
1967: whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color);
1968: #endif
1969: #endif
1970: #endif
1971: flash_created = 1;
1.1 etheisen 1972: }
1.11 millert 1973: #endif /* MSDOS_COMPILER */
1.1 etheisen 1974:
1975: /*
1976: * Output the "visual bell", if there is one.
1977: */
1978: public void
1979: vbell()
1980: {
1.11 millert 1981: #if !MSDOS_COMPILER
1.1 etheisen 1982: if (*sc_visual_bell == '\0')
1983: return;
1984: tputs(sc_visual_bell, sc_height, putchr);
1.11 millert 1985: #else
1986: #if MSDOS_COMPILER==DJGPPC
1987: ScreenVisualBell();
1988: #else
1989: #if MSDOS_COMPILER==MSOFTC
1990: /*
1991: * Create a flash screen on the second video page.
1992: * Switch to that page, then switch back.
1993: */
1994: if (!flash_created)
1995: create_flash();
1996: if (videopages < 2)
1997: return;
1998: _setvisualpage(1);
1999: delay(100);
2000: _setvisualpage(0);
2001: #else
2002: #if MSDOS_COMPILER==BORLANDC
2003: unsigned short *currscreen;
2004:
2005: /*
2006: * Get a copy of the current screen.
2007: * Display the flash screen.
2008: * Then restore the old screen.
2009: */
2010: if (!flash_created)
2011: create_flash();
2012: if (whitescreen == NULL)
2013: return;
2014: currscreen = (unsigned short *)
2015: malloc(sc_width * sc_height * sizeof(short));
2016: if (currscreen == NULL) return;
2017: gettext(1, 1, sc_width, sc_height, currscreen);
2018: puttext(1, 1, sc_width, sc_height, whitescreen);
2019: delay(100);
2020: puttext(1, 1, sc_width, sc_height, currscreen);
2021: free(currscreen);
2022: #else
2023: #if MSDOS_COMPILER==WIN32C
2024: /* paint screen with an inverse color */
2025: clear();
2026:
2027: /* leave it displayed for 100 msec. */
2028: Sleep(100);
2029:
2030: /* restore with a redraw */
2031: repaint();
2032: #endif
2033: #endif
2034: #endif
2035: #endif
2036: #endif
2037: }
2038:
2039: /*
2040: * Make a noise.
2041: */
2042: static void
2043: beep()
2044: {
2045: #if !MSDOS_COMPILER
2046: putchr(CONTROL('G'));
2047: #else
2048: #if MSDOS_COMPILER==WIN32C
2049: MessageBeep(0);
2050: #else
1.14 deraadt 2051: write(STDOUT_FILENO, "\7", 1);
1.11 millert 2052: #endif
2053: #endif
2054: }
2055:
2056: /*
2057: * Ring the terminal bell.
2058: */
2059: public void
2060: bell()
2061: {
2062: if (quiet == VERY_QUIET)
2063: vbell();
2064: else
2065: beep();
1.1 etheisen 2066: }
2067:
2068: /*
2069: * Clear the screen.
2070: */
2071: public void
2072: clear()
2073: {
1.11 millert 2074: #if !MSDOS_COMPILER
1.1 etheisen 2075: tputs(sc_clear, sc_height, putchr);
1.11 millert 2076: #else
2077: flush();
2078: #if MSDOS_COMPILER==WIN32C
2079: win32_clear();
2080: #else
2081: _clearscreen(_GCLEARSCREEN);
2082: #endif
2083: #endif
1.1 etheisen 2084: }
2085:
2086: /*
2087: * Clear from the cursor to the end of the cursor's line.
2088: * {{ This must not move the cursor. }}
2089: */
2090: public void
2091: clear_eol()
2092: {
1.11 millert 2093: #if !MSDOS_COMPILER
1.1 etheisen 2094: tputs(sc_eol_clear, 1, putchr);
1.11 millert 2095: #else
2096: #if MSDOS_COMPILER==MSOFTC
2097: short top, left;
2098: short bot, right;
2099: struct rccoord tpos;
2100:
2101: flush();
2102: /*
2103: * Save current state.
2104: */
2105: tpos = _gettextposition();
2106: _gettextwindow(&top, &left, &bot, &right);
2107: /*
2108: * Set a temporary window to the current line,
2109: * from the cursor's position to the right edge of the screen.
2110: * Then clear that window.
2111: */
2112: _settextwindow(tpos.row, tpos.col, tpos.row, sc_width);
2113: _clearscreen(_GWINDOW);
2114: /*
2115: * Restore state.
2116: */
2117: _settextwindow(top, left, bot, right);
2118: _settextposition(tpos.row, tpos.col);
2119: #else
2120: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
2121: flush();
2122: clreol();
2123: #else
2124: #if MSDOS_COMPILER==WIN32C
2125: DWORD nchars;
2126: COORD cpos;
2127: CONSOLE_SCREEN_BUFFER_INFO scr;
2128:
2129: flush();
2130: memset(&scr, 0, sizeof(scr));
2131: GetConsoleScreenBufferInfo(con_out, &scr);
2132: cpos.X = scr.dwCursorPosition.X;
2133: cpos.Y = scr.dwCursorPosition.Y;
2134: curr_attr = MAKEATTR(nm_fg_color, nm_bg_color);
2135: FillConsoleOutputAttribute(con_out, curr_attr,
2136: scr.dwSize.X - cpos.X, cpos, &nchars);
2137: FillConsoleOutputCharacter(con_out, ' ',
2138: scr.dwSize.X - cpos.X, cpos, &nchars);
2139: #endif
2140: #endif
2141: #endif
2142: #endif
2143: }
2144:
2145: /*
2146: * Clear the current line.
2147: * Clear the screen if there's off-screen memory below the display.
2148: */
2149: static void
2150: clear_eol_bot()
2151: {
2152: #if MSDOS_COMPILER
2153: clear_eol();
2154: #else
2155: if (below_mem)
2156: tputs(sc_eos_clear, 1, putchr);
2157: else
2158: tputs(sc_eol_clear, 1, putchr);
2159: #endif
1.1 etheisen 2160: }
2161:
2162: /*
2163: * Clear the bottom line of the display.
2164: * Leave the cursor at the beginning of the bottom line.
2165: */
2166: public void
2167: clear_bot()
2168: {
1.11 millert 2169: /*
2170: * If we're in a non-normal attribute mode, temporarily exit
2171: * the mode while we do the clear. Some terminals fill the
2172: * cleared area with the current attribute.
2173: */
1.15 ! shadchin 2174: if (oldbot)
! 2175: lower_left();
! 2176: else
! 2177: line_left();
! 2178:
! 2179: if (attrmode == AT_NORMAL)
! 2180: clear_eol_bot();
! 2181: else
1.11 millert 2182: {
1.15 ! shadchin 2183: int saved_attrmode = attrmode;
! 2184:
! 2185: at_exit();
1.11 millert 2186: clear_eol_bot();
1.15 ! shadchin 2187: at_enter(saved_attrmode);
1.11 millert 2188: }
1.1 etheisen 2189: }
2190:
2191: public void
1.15 ! shadchin 2192: at_enter(attr)
! 2193: int attr;
1.1 etheisen 2194: {
1.15 ! shadchin 2195: attr = apply_at_specials(attr);
! 2196:
1.11 millert 2197: #if !MSDOS_COMPILER
1.15 ! shadchin 2198: /* The one with the most priority is last. */
! 2199: if (attr & AT_UNDERLINE)
! 2200: tputs(sc_u_in, 1, putchr);
! 2201: if (attr & AT_BOLD)
! 2202: tputs(sc_b_in, 1, putchr);
! 2203: if (attr & AT_BLINK)
! 2204: tputs(sc_bl_in, 1, putchr);
! 2205: if (attr & AT_STANDOUT)
! 2206: tputs(sc_s_in, 1, putchr);
1.11 millert 2207: #else
2208: flush();
1.15 ! shadchin 2209: /* The one with the most priority is first. */
! 2210: if (attr & AT_STANDOUT)
! 2211: {
! 2212: SETCOLORS(so_fg_color, so_bg_color);
! 2213: } else if (attr & AT_BLINK)
! 2214: {
! 2215: SETCOLORS(bl_fg_color, bl_bg_color);
! 2216: }
! 2217: else if (attr & AT_BOLD)
! 2218: {
! 2219: SETCOLORS(bo_fg_color, bo_bg_color);
! 2220: }
! 2221: else if (attr & AT_UNDERLINE)
! 2222: {
! 2223: SETCOLORS(ul_fg_color, ul_bg_color);
! 2224: }
1.11 millert 2225: #endif
1.15 ! shadchin 2226:
! 2227: attrmode = attr;
1.1 etheisen 2228: }
2229:
2230: public void
1.15 ! shadchin 2231: at_exit()
1.1 etheisen 2232: {
1.11 millert 2233: #if !MSDOS_COMPILER
1.15 ! shadchin 2234: /* Undo things in the reverse order we did them. */
! 2235: if (attrmode & AT_STANDOUT)
! 2236: tputs(sc_s_out, 1, putchr);
! 2237: if (attrmode & AT_BLINK)
! 2238: tputs(sc_bl_out, 1, putchr);
! 2239: if (attrmode & AT_BOLD)
! 2240: tputs(sc_b_out, 1, putchr);
! 2241: if (attrmode & AT_UNDERLINE)
! 2242: tputs(sc_u_out, 1, putchr);
1.11 millert 2243: #else
2244: flush();
2245: SETCOLORS(nm_fg_color, nm_bg_color);
2246: #endif
1.15 ! shadchin 2247:
1.11 millert 2248: attrmode = AT_NORMAL;
1.1 etheisen 2249: }
2250:
2251: public void
1.15 ! shadchin 2252: at_switch(attr)
! 2253: int attr;
1.1 etheisen 2254: {
1.15 ! shadchin 2255: int new_attrmode = apply_at_specials(attr);
! 2256: int ignore_modes = AT_ANSI;
1.1 etheisen 2257:
1.15 ! shadchin 2258: if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes))
! 2259: {
! 2260: at_exit();
! 2261: at_enter(attr);
! 2262: }
1.1 etheisen 2263: }
2264:
1.15 ! shadchin 2265: public int
! 2266: is_at_equiv(attr1, attr2)
! 2267: int attr1;
! 2268: int attr2;
1.1 etheisen 2269: {
1.15 ! shadchin 2270: attr1 = apply_at_specials(attr1);
! 2271: attr2 = apply_at_specials(attr2);
1.1 etheisen 2272:
1.15 ! shadchin 2273: return (attr1 == attr2);
1.1 etheisen 2274: }
2275:
1.15 ! shadchin 2276: public int
! 2277: apply_at_specials(attr)
! 2278: int attr;
1.1 etheisen 2279: {
1.15 ! shadchin 2280: if (attr & AT_BINARY)
! 2281: attr |= binattr;
! 2282: if (attr & AT_HILITE)
! 2283: attr |= AT_STANDOUT;
! 2284: attr &= ~(AT_BINARY|AT_HILITE);
1.1 etheisen 2285:
1.15 ! shadchin 2286: return attr;
1.1 etheisen 2287: }
2288:
1.11 millert 2289: #if 0 /* No longer used */
1.1 etheisen 2290: /*
2291: * Erase the character to the left of the cursor
2292: * and move the cursor left.
2293: */
2294: public void
2295: backspace()
2296: {
1.11 millert 2297: #if !MSDOS_COMPILER
1.1 etheisen 2298: /*
1.11 millert 2299: * Erase the previous character by overstriking with a space.
1.1 etheisen 2300: */
2301: tputs(sc_backspace, 1, putchr);
2302: putchr(' ');
2303: tputs(sc_backspace, 1, putchr);
1.11 millert 2304: #else
2305: #if MSDOS_COMPILER==MSOFTC
2306: struct rccoord tpos;
2307:
2308: flush();
2309: tpos = _gettextposition();
2310: if (tpos.col <= 1)
2311: return;
2312: _settextposition(tpos.row, tpos.col-1);
2313: _outtext(" ");
2314: _settextposition(tpos.row, tpos.col-1);
2315: #else
2316: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
2317: cputs("\b");
2318: #else
2319: #if MSDOS_COMPILER==WIN32C
2320: COORD cpos;
2321: DWORD cChars;
2322: CONSOLE_SCREEN_BUFFER_INFO scr;
2323:
2324: flush();
2325: GetConsoleScreenBufferInfo(con_out, &scr);
2326: cpos = scr.dwCursorPosition;
2327: if (cpos.X <= 0)
2328: return;
2329: cpos.X--;
2330: SetConsoleCursorPosition(con_out, cpos);
2331: FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars);
2332: SetConsoleCursorPosition(con_out, cpos);
2333: #endif
2334: #endif
2335: #endif
2336: #endif
1.1 etheisen 2337: }
1.11 millert 2338: #endif /* 0 */
1.1 etheisen 2339:
2340: /*
2341: * Output a plain backspace, without erasing the previous char.
2342: */
2343: public void
2344: putbs()
2345: {
1.11 millert 2346: #if !MSDOS_COMPILER
1.1 etheisen 2347: tputs(sc_backspace, 1, putchr);
1.11 millert 2348: #else
2349: int row, col;
2350:
2351: flush();
2352: {
2353: #if MSDOS_COMPILER==MSOFTC
2354: struct rccoord tpos;
2355: tpos = _gettextposition();
2356: row = tpos.row;
2357: col = tpos.col;
2358: #else
2359: #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
2360: row = wherey();
2361: col = wherex();
2362: #else
2363: #if MSDOS_COMPILER==WIN32C
2364: CONSOLE_SCREEN_BUFFER_INFO scr;
2365: GetConsoleScreenBufferInfo(con_out, &scr);
2366: row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1;
2367: col = scr.dwCursorPosition.X - scr.srWindow.Left + 1;
2368: #endif
2369: #endif
2370: #endif
2371: }
2372: if (col <= 1)
2373: return;
2374: _settextposition(row, col-1);
2375: #endif /* MSDOS_COMPILER */
1.1 etheisen 2376: }
1.11 millert 2377:
2378: #if MSDOS_COMPILER==WIN32C
2379: /*
2380: * Determine whether an input character is waiting to be read.
2381: */
2382: static int
2383: win32_kbhit(tty)
2384: HANDLE tty;
2385: {
2386: INPUT_RECORD ip;
2387: DWORD read;
2388:
2389: if (keyCount > 0)
2390: return (TRUE);
2391:
2392: currentKey.ascii = 0;
2393: currentKey.scan = 0;
2394:
2395: /*
2396: * Wait for a real key-down event, but
2397: * ignore SHIFT and CONTROL key events.
2398: */
2399: do
2400: {
2401: PeekConsoleInput(tty, &ip, 1, &read);
2402: if (read == 0)
2403: return (FALSE);
2404: ReadConsoleInput(tty, &ip, 1, &read);
2405: } while (ip.EventType != KEY_EVENT ||
2406: ip.Event.KeyEvent.bKeyDown != TRUE ||
2407: ip.Event.KeyEvent.wVirtualScanCode == 0 ||
2408: ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
2409: ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL ||
2410: ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU);
2411:
2412: currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar;
2413: currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode;
2414: keyCount = ip.Event.KeyEvent.wRepeatCount;
2415:
2416: if (ip.Event.KeyEvent.dwControlKeyState &
2417: (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
2418: {
2419: switch (currentKey.scan)
2420: {
2421: case PCK_ALT_E: /* letter 'E' */
2422: currentKey.ascii = 0;
2423: break;
2424: }
2425: } else if (ip.Event.KeyEvent.dwControlKeyState &
2426: (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
2427: {
2428: switch (currentKey.scan)
2429: {
2430: case PCK_RIGHT: /* right arrow */
2431: currentKey.scan = PCK_CTL_RIGHT;
2432: break;
2433: case PCK_LEFT: /* left arrow */
2434: currentKey.scan = PCK_CTL_LEFT;
2435: break;
2436: case PCK_DELETE: /* delete */
2437: currentKey.scan = PCK_CTL_DELETE;
2438: break;
2439: }
2440: }
2441: return (TRUE);
2442: }
2443:
2444: /*
2445: * Read a character from the keyboard.
2446: */
2447: public char
2448: WIN32getch(tty)
2449: int tty;
2450: {
2451: int ascii;
2452:
2453: if (pending_scancode)
2454: {
2455: pending_scancode = 0;
2456: return ((char)(currentKey.scan & 0x00FF));
2457: }
2458:
2459: while (win32_kbhit((HANDLE)tty) == FALSE)
2460: {
2461: Sleep(20);
2462: if (ABORT_SIGS())
2463: return ('\003');
2464: continue;
2465: }
2466: keyCount --;
2467: ascii = currentKey.ascii;
2468: /*
2469: * On PC's, the extended keys return a 2 byte sequence beginning
2470: * with '00', so if the ascii code is 00, the next byte will be
2471: * the lsb of the scan code.
2472: */
2473: pending_scancode = (ascii == 0x00);
2474: return ((char)ascii);
1.15 ! shadchin 2475: }
! 2476: #endif
! 2477:
! 2478: #if MSDOS_COMPILER
! 2479: /*
! 2480: */
! 2481: public void
! 2482: WIN32setcolors(fg, bg)
! 2483: int fg;
! 2484: int bg;
! 2485: {
! 2486: SETCOLORS(fg, bg);
! 2487: }
! 2488:
! 2489: /*
! 2490: */
! 2491: public void
! 2492: WIN32textout(text, len)
! 2493: char *text;
! 2494: int len;
! 2495: {
! 2496: #if MSDOS_COMPILER==WIN32C
! 2497: DWORD written;
! 2498: WriteConsole(con_out, text, len, &written, NULL);
! 2499: #else
! 2500: char c = text[len];
! 2501: text[len] = '\0';
! 2502: cputs(text);
! 2503: text[len] = c;
! 2504: #endif
1.11 millert 2505: }
2506: #endif