|
|
1.1 root 1: /*
2: * Routines which deal with the characteristics of the terminal.
3: * Uses termcap to be as terminal-independent as possible.
4: *
5: * {{ Someday this should be rewritten to use curses. }}
6: */
7:
8: #include "less.h"
9: #if XENIX
10: #include <sys/types.h>
11: #include <sys/ioctl.h>
12: #endif
13:
14: #if TERMIO
15: #include <termio.h>
16: #else
17: #include <sgtty.h>
18: #endif
19:
20: /*
21: * Strings passed to tputs() to do various terminal functions.
22: */
23: static char
24: *sc_pad, /* Pad string */
25: *sc_home, /* Cursor home */
26: *sc_addline, /* Add line, scroll down following lines */
27: *sc_lower_left, /* Cursor to last line, first column */
28: *sc_move, /* General cursor positioning */
29: *sc_clear, /* Clear screen */
30: *sc_eol_clear, /* Clear to end of line */
31: *sc_s_in, /* Enter standout (highlighted) mode */
32: *sc_s_out, /* Exit standout mode */
33: *sc_u_in, /* Enter underline mode */
34: *sc_u_out, /* Exit underline mode */
35: *sc_visual_bell, /* Visual bell (flash screen) sequence */
36: *sc_backspace, /* Backspace cursor */
37: *sc_init, /* Startup terminal initialization */
38: *sc_deinit; /* Exit terminal de-intialization */
39: static int dumb;
40: static int hard;
41:
42: public int auto_wrap; /* Terminal does \r\n when write past margin */
43: public int ignaw; /* Terminal ignores \n immediately after wrap */
44: public int erase_char, kill_char; /* The user's erase and line-kill chars */
45: public int sc_width, sc_height; /* Height & width of screen */
46: public int ul_width, ue_width; /* Printing width of underline sequences */
47: public int so_width, se_width; /* Printing width of standout sequences */
48:
49: /*
50: * These two variables are sometimes defined in,
51: * and needed by, the termcap library.
52: * It may be necessary on some systems to declare them extern here.
53: */
54: /*extern*/ short ospeed; /* Terminal output baud rate */
55: /*extern*/ char PC; /* Pad character */
56:
57: extern int quiet; /* If VERY_QUIET, use visual bell for bell */
58: extern int know_dumb; /* Don't complain about a dumb terminal */
59: extern int back_scroll;
60: char *tgetstr();
61: char *tgoto();
62:
63: /*
64: * Change terminal to "raw mode", or restore to "normal" mode.
65: * "Raw mode" means
66: * 1. An outstanding read will complete on receipt of a single keystroke.
67: * 2. Input is not echoed.
68: * 3. On output, \n is mapped to \r\n.
69: * 4. \t is NOT be expanded into spaces.
70: * 5. Signal-causing characters such as ctrl-C (interrupt),
71: * etc. are NOT disabled.
72: * It doesn't matter whether an input \n is mapped to \r, or vice versa.
73: */
74: public void
75: raw_mode(on)
76: int on;
77: {
78: #if TERMIO
79: struct termio s;
80: static struct termio save_term;
81:
82: if (on)
83: {
84: /*
85: * Get terminal modes.
86: */
87: ioctl(2, TCGETA, &s);
88:
89: /*
90: * Save modes and set certain variables dependent on modes.
91: */
92: save_term = s;
93: ospeed = s.c_cflag & CBAUD;
94: erase_char = s.c_cc[VERASE];
95: kill_char = s.c_cc[VKILL];
96:
97: /*
98: * Set the modes to the way we want them.
99: */
100: s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
101: s.c_oflag |= (OPOST|ONLCR|TAB3);
102: s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
103: s.c_cc[VMIN] = 1;
104: s.c_cc[VTIME] = 0;
105: } else
106: {
107: /*
108: * Restore saved modes.
109: */
110: s = save_term;
111: }
112: ioctl(2, TCSETAW, &s);
113: #else
114: struct sgttyb s;
115: static struct sgttyb save_term;
116:
117: if (on)
118: {
119: /*
120: * Get terminal modes.
121: */
122: ioctl(2, TIOCGETP, &s);
123:
124: /*
125: * Save modes and set certain variables dependent on modes.
126: */
127: save_term = s;
128: ospeed = s.sg_ospeed;
129: erase_char = s.sg_erase;
130: kill_char = s.sg_kill;
131:
132: /*
133: * Set the modes to the way we want them.
134: */
135: s.sg_flags |= CBREAK;
136: s.sg_flags &= ~(ECHO|XTABS);
137: } else
138: {
139: /*
140: * Restore saved modes.
141: */
142: s = save_term;
143: }
144: ioctl(2, TIOCSETN, &s);
145: #endif
146: }
147:
148: static int couldnt = 0;
149:
150: static void
151: cannot(s)
152: char *s;
153: {
154: if (know_dumb)
155: /*
156: * He knows he has a dumb terminal, so don't tell him.
157: */
158: return;
159:
160: printf("WARNING: terminal cannot \"%s\"\n", s);
161: couldnt = 1;
162: }
163:
164: /*
165: * Get terminal capabilities via termcap.
166: */
167: public void
168: get_term()
169: {
170: char termbuf[1024];
171: char *sp;
172: static char sbuf[150];
173:
174: char *getenv();
175:
176: /*
177: * Find out what kind of terminal this is.
178: */
179: if (tgetent(termbuf, getenv("TERM")) <= 0)
180: dumb = 1;
181:
182: /*
183: * Get size of the screen.
184: */
185: if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
186: {
187: /* Oh no, this is a hardcopy terminal. */
188: hard = 1;
189: sc_height = 24;
190: }
191: if (dumb || (sc_width = tgetnum("co")) < 0)
192: sc_width = 80;
193:
194: auto_wrap = tgetflag("am");
195: ignaw = tgetflag("xn");
196:
197: /*
198: * Assumes termcap variable "sg" is the printing width of
199: * the standout sequence, the end standout sequence,
200: * the underline sequence, and the end underline sequence.
201: */
202: if ((ul_width = tgetnum("sg")) < 0)
203: ul_width = 0;
204: so_width = se_width = ue_width = ul_width;
205:
206: /*
207: * Get various string-valued capabilities.
208: */
209: sp = sbuf;
210:
211: sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
212: if (sc_pad != NULL)
213: PC = *sc_pad;
214:
215: sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
216: if (sc_init == NULL)
217: sc_init = "";
218:
219: sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
220: if (sc_deinit == NULL)
221: sc_deinit = "";
222:
223: sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
224: if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
225: {
226: cannot("clear to end of line");
227: sc_eol_clear = "";
228: }
229:
230: sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
231: if (hard || sc_clear == NULL || *sc_clear == '\0')
232: {
233: cannot("clear screen");
234: sc_clear = "\n\n";
235: }
236:
237: sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
238: if (hard || sc_move == NULL || *sc_move == '\0')
239: {
240: /*
241: * This is not an error here, because we don't
242: * always need sc_move.
243: * We need it only if we don't have home or lower-left.
244: */
245: sc_move = "";
246: }
247:
248: sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
249: if (hard || sc_s_in == NULL)
250: sc_s_in = "";
251:
252: sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
253: if (hard || sc_s_out == NULL)
254: sc_s_out = "";
255:
256: sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
257: if (hard || sc_u_in == NULL)
258: sc_u_in = sc_s_in;
259:
260: sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
261: if (hard || sc_u_out == NULL)
262: sc_u_out = sc_s_out;
263:
264: sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
265: if (hard || sc_visual_bell == NULL)
266: sc_visual_bell = "";
267:
268: sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
269: if (hard || sc_home == NULL || *sc_home == '\0')
270: {
271: if (*sc_move == '\0')
272: {
273: cannot("home cursor");
274: /*
275: * This last resort for sc_home is supposed to
276: * be an up-arrow suggesting moving to the
277: * top of the "virtual screen". (The one in
278: * your imagination as you try to use this on
279: * a hard copy terminal.)
280: */
281: sc_home = "|\b^";
282: } else
283: {
284: /*
285: * No "home" string,
286: * but we can use "move(0,0)".
287: */
288: strcpy(sp, tgoto(sc_move, 0, 0));
289: sc_home = sp;
290: sp += strlen(sp) + 1;
291: }
292: }
293:
294: sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
295: if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
296: {
297: if (*sc_move == '\0')
298: {
299: cannot("move cursor to lower left of screen");
300: sc_lower_left = "\r";
301: } else
302: {
303: /*
304: * No "lower-left" string,
305: * but we can use "move(0,last-line)".
306: */
307: strcpy(sp, tgoto(sc_move, 0, sc_height-1));
308: sc_lower_left = sp;
309: sp += strlen(sp) + 1;
310: }
311: }
312:
313: /*
314: * To add a line at top of screen and scroll the display down,
315: * we use "al" (add line) or "sr" (scroll reverse).
316: */
317: if (dumb)
318: sc_addline = NULL;
319: else if ((sc_addline = tgetstr("al", &sp)) == NULL ||
320: *sc_addline == '\0')
321: sc_addline = tgetstr("sr", &sp);
322:
323: if (hard || sc_addline == NULL || *sc_addline == '\0')
324: {
325: cannot("scroll backwards");
326: sc_addline = "";
327: /* Force repaint on any backward movement */
328: back_scroll = 0;
329: }
330:
331: if (dumb || tgetflag("bs"))
332: sc_backspace = "\b";
333: else
334: {
335: sc_backspace = tgetstr("bc", &sp);
336: if (sc_backspace == NULL || *sc_backspace == '\0')
337: sc_backspace = "\b";
338: }
339:
340: if (couldnt)
341: /* Give him time to read all the "cannot" messages. */
342: error("");
343: }
344:
345:
346: /*
347: * Below are the functions which perform all the
348: * terminal-specific screen manipulation.
349: */
350:
351:
352: /*
353: * Initialize terminal
354: */
355: public void
356: init()
357: {
358: tputs(sc_init, sc_height, putc);
359: }
360:
361: /*
362: * Deinitialize terminal
363: */
364: public void
365: deinit()
366: {
367: tputs(sc_deinit, sc_height, putc);
368: }
369:
370: /*
371: * Home cursor (move to upper left corner of screen).
372: */
373: public void
374: home()
375: {
376: tputs(sc_home, 1, putc);
377: }
378:
379: /*
380: * Add a blank line (called with cursor at home).
381: * Should scroll the display down.
382: */
383: public void
384: add_line()
385: {
386: tputs(sc_addline, sc_height, putc);
387: }
388:
389: /*
390: * Move cursor to lower left corner of screen.
391: */
392: public void
393: lower_left()
394: {
395: tputs(sc_lower_left, 1, putc);
396: }
397:
398: /*
399: * Ring the terminal bell.
400: */
401: public void
402: bell()
403: {
404: if (quiet == VERY_QUIET)
405: vbell();
406: else
407: putc('\7');
408: }
409:
410: /*
411: * Output the "visual bell", if there is one.
412: */
413: public void
414: vbell()
415: {
416: if (*sc_visual_bell == '\0')
417: return;
418: tputs(sc_visual_bell, sc_height, putc);
419: }
420:
421: /*
422: * Clear the screen.
423: */
424: public void
425: clear()
426: {
427: tputs(sc_clear, sc_height, putc);
428: }
429:
430: /*
431: * Clear from the cursor to the end of the cursor's line.
432: * {{ This must not move the cursor. }}
433: */
434: public void
435: clear_eol()
436: {
437: tputs(sc_eol_clear, 1, putc);
438: }
439:
440: /*
441: * Begin "standout" (bold, underline, or whatever).
442: */
443: public void
444: so_enter()
445: {
446: tputs(sc_s_in, 1, putc);
447: }
448:
449: /*
450: * End "standout".
451: */
452: public void
453: so_exit()
454: {
455: tputs(sc_s_out, 1, putc);
456: }
457:
458: /*
459: * Begin "underline" (hopefully real underlining,
460: * otherwise whatever the terminal provides).
461: */
462: public void
463: ul_enter()
464: {
465: tputs(sc_u_in, 1, putc);
466: }
467:
468: /*
469: * End "underline".
470: */
471: public void
472: ul_exit()
473: {
474: tputs(sc_u_out, 1, putc);
475: }
476:
477: /*
478: * Erase the character to the left of the cursor
479: * and move the cursor left.
480: */
481: public void
482: backspace()
483: {
484: /*
485: * Try to erase the previous character by overstriking with a space.
486: */
487: tputs(sc_backspace, 1, putc);
488: putc(' ');
489: tputs(sc_backspace, 1, putc);
490: }
491:
492: /*
493: * Output a plain backspace, without erasing the previous char.
494: */
495: public void
496: putbs()
497: {
498: tputs(sc_backspace, 1, putc);
499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.