1 |
|
|
/* |
2 |
|
|
* Copyright (C) 1984-2012 Mark Nudelman |
3 |
|
|
* Modified for use with illumos by Garrett D'Amore. |
4 |
|
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
5 |
|
|
* |
6 |
|
|
* You may distribute under the terms of either the GNU General Public |
7 |
|
|
* License or the Less License, as specified in the README file. |
8 |
|
|
* |
9 |
|
|
* For more information, see the README file. |
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 <sys/ioctl.h> |
18 |
|
|
|
19 |
|
|
#include <err.h> |
20 |
|
|
#include <term.h> |
21 |
|
|
#include <termios.h> |
22 |
|
|
|
23 |
|
|
#include "cmd.h" |
24 |
|
|
#include "less.h" |
25 |
|
|
|
26 |
|
|
#define DEFAULT_TERM "unknown" |
27 |
|
|
|
28 |
|
|
/* |
29 |
|
|
* Strings passed to tputs() to do various terminal functions. |
30 |
|
|
*/ |
31 |
|
|
static char |
32 |
|
|
*sc_home, /* Cursor home */ |
33 |
|
|
*sc_addline, /* Add line, scroll down following lines */ |
34 |
|
|
*sc_lower_left, /* Cursor to last line, first column */ |
35 |
|
|
*sc_return, /* Cursor to beginning of current line */ |
36 |
|
|
*sc_move, /* General cursor positioning */ |
37 |
|
|
*sc_clear, /* Clear screen */ |
38 |
|
|
*sc_eol_clear, /* Clear to end of line */ |
39 |
|
|
*sc_eos_clear, /* Clear to end of screen */ |
40 |
|
|
*sc_s_in, /* Enter standout (highlighted) mode */ |
41 |
|
|
*sc_s_out, /* Exit standout mode */ |
42 |
|
|
*sc_u_in, /* Enter underline mode */ |
43 |
|
|
*sc_u_out, /* Exit underline mode */ |
44 |
|
|
*sc_b_in, /* Enter bold mode */ |
45 |
|
|
*sc_b_out, /* Exit bold mode */ |
46 |
|
|
*sc_bl_in, /* Enter blink mode */ |
47 |
|
|
*sc_bl_out, /* Exit blink mode */ |
48 |
|
|
*sc_visual_bell, /* Visual bell (flash screen) sequence */ |
49 |
|
|
*sc_backspace, /* Backspace cursor */ |
50 |
|
|
*sc_s_keypad, /* Start keypad mode */ |
51 |
|
|
*sc_e_keypad, /* End keypad mode */ |
52 |
|
|
*sc_init, /* Startup terminal initialization */ |
53 |
|
|
*sc_deinit; /* Exit terminal de-initialization */ |
54 |
|
|
|
55 |
|
|
static int init_done = 0; |
56 |
|
|
|
57 |
|
|
int auto_wrap; /* Terminal does \r\n when write past margin */ |
58 |
|
|
int ignaw; /* Terminal ignores \n immediately after wrap */ |
59 |
|
|
int erase_char; /* The user's erase char */ |
60 |
|
|
int erase2_char; /* The user's other erase char */ |
61 |
|
|
int kill_char; /* The user's line-kill char */ |
62 |
|
|
int werase_char; /* The user's word-erase char */ |
63 |
|
|
int sc_width, sc_height; /* Height & width of screen */ |
64 |
|
|
int bo_s_width, bo_e_width; /* Printing width of boldface seq */ |
65 |
|
|
int ul_s_width, ul_e_width; /* Printing width of underline seq */ |
66 |
|
|
int so_s_width, so_e_width; /* Printing width of standout seq */ |
67 |
|
|
int bl_s_width, bl_e_width; /* Printing width of blink seq */ |
68 |
|
|
int can_goto_line; /* Can move cursor to any line */ |
69 |
|
|
int missing_cap = 0; /* Some capability is missing */ |
70 |
|
|
static int above_mem; /* Memory retained above screen */ |
71 |
|
|
static int below_mem; /* Memory retained below screen */ |
72 |
|
|
|
73 |
|
|
static int attrmode = AT_NORMAL; |
74 |
|
|
extern int binattr; |
75 |
|
|
|
76 |
|
|
static char *cheaper(char *, char *, char *); |
77 |
|
|
static void tmodes(char *, char *, char **, char **, char *, char *); |
78 |
|
|
|
79 |
|
|
extern int quiet; /* If VERY_QUIET, use visual bell for bell */ |
80 |
|
|
extern int no_back_scroll; |
81 |
|
|
extern int swindow; |
82 |
|
|
extern int no_init; |
83 |
|
|
extern int no_keypad; |
84 |
|
|
extern volatile sig_atomic_t sigs; |
85 |
|
|
extern int wscroll; |
86 |
|
|
extern int screen_trashed; |
87 |
|
|
extern int tty; |
88 |
|
|
extern int top_scroll; |
89 |
|
|
extern int oldbot; |
90 |
|
|
extern int hilite_search; |
91 |
|
|
|
92 |
|
|
/* |
93 |
|
|
* Change terminal to "raw mode", or restore to "normal" mode. |
94 |
|
|
* "Raw mode" means |
95 |
|
|
* 1. An outstanding read will complete on receipt of a single keystroke. |
96 |
|
|
* 2. Input is not echoed. |
97 |
|
|
* 3. On output, \n is mapped to \r\n. |
98 |
|
|
* 4. \t is NOT expanded into spaces. |
99 |
|
|
* 5. Signal-causing characters such as ctrl-C (interrupt), |
100 |
|
|
* etc. are NOT disabled. |
101 |
|
|
* It doesn't matter whether an input \n is mapped to \r, or vice versa. |
102 |
|
|
*/ |
103 |
|
|
void |
104 |
|
|
raw_mode(int on) |
105 |
|
|
{ |
106 |
|
|
static int curr_on = 0; |
107 |
|
32 |
struct termios s; |
108 |
|
|
static struct termios save_term; |
109 |
|
|
static int saved_term = 0; |
110 |
|
|
|
111 |
✗✓ |
16 |
if (on == curr_on) |
112 |
|
|
return; |
113 |
|
16 |
erase2_char = '\b'; /* in case OS doesn't know about erase2 */ |
114 |
|
|
|
115 |
✓✓ |
16 |
if (on) { |
116 |
|
|
/* |
117 |
|
|
* Get terminal modes. |
118 |
|
|
*/ |
119 |
|
8 |
(void) tcgetattr(tty, &s); |
120 |
|
|
|
121 |
|
|
/* |
122 |
|
|
* Save modes and set certain variables dependent on modes. |
123 |
|
|
*/ |
124 |
✓✗ |
8 |
if (!saved_term) { |
125 |
|
8 |
save_term = s; |
126 |
|
8 |
saved_term = 1; |
127 |
|
8 |
} |
128 |
|
|
|
129 |
|
8 |
erase_char = s.c_cc[VERASE]; |
130 |
|
|
#ifdef VERASE2 |
131 |
|
|
erase2_char = s.c_cc[VERASE2]; |
132 |
|
|
#endif |
133 |
|
8 |
kill_char = s.c_cc[VKILL]; |
134 |
|
|
#ifdef VWERASE |
135 |
|
8 |
werase_char = s.c_cc[VWERASE]; |
136 |
|
|
#endif |
137 |
|
|
|
138 |
|
|
/* |
139 |
|
|
* Set the modes to the way we want them. |
140 |
|
|
*/ |
141 |
|
8 |
s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL); |
142 |
|
|
|
143 |
|
|
#ifndef TAB3 |
144 |
|
|
#define TAB3 0 /* Its a lie, but TAB3 isn't defined by POSIX. */ |
145 |
|
|
#endif |
146 |
|
8 |
s.c_oflag |= (TAB3 | OPOST | ONLCR); |
147 |
|
8 |
s.c_oflag &= ~(OCRNL | ONOCR | ONLRET); |
148 |
|
8 |
s.c_cc[VMIN] = 1; |
149 |
|
8 |
s.c_cc[VTIME] = 0; |
150 |
|
|
#ifdef VLNEXT |
151 |
|
8 |
s.c_cc[VLNEXT] = 0; |
152 |
|
|
#endif |
153 |
|
|
#ifdef VDSUSP |
154 |
|
8 |
s.c_cc[VDSUSP] = 0; |
155 |
|
|
#endif |
156 |
|
8 |
} else { |
157 |
|
|
/* |
158 |
|
|
* Restore saved modes. |
159 |
|
|
*/ |
160 |
|
8 |
s = save_term; |
161 |
|
|
} |
162 |
|
16 |
(void) tcsetattr(tty, TCSASOFT | TCSADRAIN, &s); |
163 |
|
16 |
curr_on = on; |
164 |
|
32 |
} |
165 |
|
|
|
166 |
|
|
/* |
167 |
|
|
* Some glue to prevent calling termcap functions if tgetent() failed. |
168 |
|
|
*/ |
169 |
|
|
static int hardcopy; |
170 |
|
|
|
171 |
|
|
/* |
172 |
|
|
* Get size of the output screen. |
173 |
|
|
*/ |
174 |
|
|
static void |
175 |
|
|
scrsize(void) |
176 |
|
|
{ |
177 |
|
|
int sys_height = 0, sys_width = 0, n; |
178 |
|
16 |
struct winsize w; |
179 |
|
|
char *s; |
180 |
|
|
|
181 |
|
|
#define DEF_SC_WIDTH 80 |
182 |
|
|
#define DEF_SC_HEIGHT 24 |
183 |
|
|
|
184 |
✓✗ |
8 |
if (ioctl(2, TIOCGWINSZ, &w) == 0) { |
185 |
✓✗ |
8 |
if (w.ws_row > 0) |
186 |
|
8 |
sys_height = w.ws_row; |
187 |
✓✗ |
8 |
if (w.ws_col > 0) |
188 |
|
8 |
sys_width = w.ws_col; |
189 |
|
|
} |
190 |
|
|
|
191 |
✓✗ |
8 |
if (sys_height > 0) |
192 |
|
8 |
sc_height = sys_height; |
193 |
|
|
else if ((s = lgetenv("LINES")) != NULL) |
194 |
|
|
sc_height = atoi(s); |
195 |
|
|
else if (!hardcopy && (n = lines) > 0) |
196 |
|
|
sc_height = n; |
197 |
✗✓ |
8 |
if (sc_height <= 0) |
198 |
|
|
sc_height = DEF_SC_HEIGHT; |
199 |
|
|
|
200 |
✓✗ |
8 |
if (sys_width > 0) |
201 |
|
8 |
sc_width = sys_width; |
202 |
|
|
else if ((s = lgetenv("COLUMNS")) != NULL) |
203 |
|
|
sc_width = atoi(s); |
204 |
|
|
else if (!hardcopy && (n = columns) > 0) |
205 |
|
|
sc_width = n; |
206 |
✗✓ |
8 |
if (sc_width <= 0) |
207 |
|
|
sc_width = DEF_SC_WIDTH; |
208 |
|
8 |
} |
209 |
|
|
|
210 |
|
|
/* |
211 |
|
|
* Return the characters actually input by a "special" key. |
212 |
|
|
*/ |
213 |
|
|
char * |
214 |
|
|
special_key_str(int key) |
215 |
|
|
{ |
216 |
|
|
char *s; |
217 |
|
|
static char ctrlk[] = { CONTROL('K'), 0 }; |
218 |
|
|
|
219 |
✗✓ |
416 |
if (hardcopy) |
220 |
|
|
return (NULL); |
221 |
|
|
|
222 |
✓✓✓✓ ✓✓✓✓ ✓✓✓ |
208 |
switch (key) { |
223 |
|
|
case SK_RIGHT_ARROW: |
224 |
|
24 |
s = key_right; |
225 |
|
24 |
break; |
226 |
|
|
case SK_LEFT_ARROW: |
227 |
|
24 |
s = key_left; |
228 |
|
24 |
break; |
229 |
|
|
case SK_UP_ARROW: |
230 |
|
16 |
s = key_up; |
231 |
|
16 |
break; |
232 |
|
|
case SK_DOWN_ARROW: |
233 |
|
16 |
s = key_down; |
234 |
|
16 |
break; |
235 |
|
|
case SK_PAGE_UP: |
236 |
|
8 |
s = key_ppage; |
237 |
|
8 |
break; |
238 |
|
|
case SK_PAGE_DOWN: |
239 |
|
8 |
s = key_npage; |
240 |
|
8 |
break; |
241 |
|
|
case SK_HOME: |
242 |
|
16 |
s = key_home; |
243 |
|
16 |
break; |
244 |
|
|
case SK_END: |
245 |
|
16 |
s = key_end; |
246 |
|
16 |
break; |
247 |
|
|
case SK_DELETE: |
248 |
|
16 |
s = key_dc; |
249 |
|
16 |
if (s == NULL) { |
250 |
|
|
s = "\177\0"; |
251 |
|
|
} |
252 |
|
16 |
break; |
253 |
|
|
case SK_CONTROL_K: |
254 |
|
|
s = ctrlk; |
255 |
|
8 |
break; |
256 |
|
|
default: |
257 |
|
56 |
return (NULL); |
258 |
|
|
} |
259 |
|
152 |
return (s); |
260 |
|
208 |
} |
261 |
|
|
|
262 |
|
|
/* |
263 |
|
|
* Get terminal capabilities via termcap. |
264 |
|
|
*/ |
265 |
|
|
void |
266 |
|
|
get_term(void) |
267 |
|
|
{ |
268 |
|
|
char *t1, *t2; |
269 |
|
|
char *term; |
270 |
|
16 |
int err; |
271 |
|
|
|
272 |
|
|
/* |
273 |
|
|
* Find out what kind of terminal this is. |
274 |
|
|
*/ |
275 |
|
8 |
if ((term = lgetenv("TERM")) == NULL) |
276 |
|
|
term = DEFAULT_TERM; |
277 |
|
8 |
hardcopy = 0; |
278 |
|
|
|
279 |
✗✓ |
8 |
if (setupterm(term, 1, &err) < 0) { |
280 |
|
|
if (err == 1) |
281 |
|
|
hardcopy = 1; |
282 |
|
|
else |
283 |
|
|
errx(1, "%s: unknown terminal type", term); |
284 |
|
|
} |
285 |
✗✓ |
8 |
if (hard_copy == 1) |
286 |
|
|
hardcopy = 1; |
287 |
|
|
|
288 |
|
|
/* |
289 |
|
|
* Get size of the screen. |
290 |
|
|
*/ |
291 |
|
8 |
scrsize(); |
292 |
|
8 |
pos_init(); |
293 |
|
|
|
294 |
✓✗ |
24 |
auto_wrap = hardcopy ? 0 : auto_right_margin; |
295 |
✓✗ |
24 |
ignaw = hardcopy ? 0 : eat_newline_glitch; |
296 |
✓✗ |
24 |
above_mem = hardcopy ? 0 : memory_above; |
297 |
✓✗ |
24 |
below_mem = hardcopy ? 0 : memory_below; |
298 |
|
|
|
299 |
|
|
/* |
300 |
|
|
* Assumes termcap variable "sg" is the printing width of: |
301 |
|
|
* the standout sequence, the end standout sequence, |
302 |
|
|
* the underline sequence, the end underline sequence, |
303 |
|
|
* the boldface sequence, and the end boldface sequence. |
304 |
|
|
*/ |
305 |
✓✗✓✗
|
16 |
if (hardcopy || (so_s_width = magic_cookie_glitch) < 0) |
306 |
|
8 |
so_s_width = 0; |
307 |
|
8 |
so_e_width = so_s_width; |
308 |
|
|
|
309 |
|
8 |
bo_s_width = bo_e_width = so_s_width; |
310 |
|
8 |
ul_s_width = ul_e_width = so_s_width; |
311 |
|
8 |
bl_s_width = bl_e_width = so_s_width; |
312 |
|
|
|
313 |
✗✓ |
8 |
if (so_s_width > 0 || so_e_width > 0) |
314 |
|
|
/* |
315 |
|
|
* Disable highlighting by default on magic cookie terminals. |
316 |
|
|
* Turning on highlighting might change the displayed width |
317 |
|
|
* of a line, causing the display to get messed up. |
318 |
|
|
* The user can turn it back on with -g, |
319 |
|
|
* but she won't like the results. |
320 |
|
|
*/ |
321 |
|
|
hilite_search = 0; |
322 |
|
|
|
323 |
|
|
/* |
324 |
|
|
* Get various string-valued capabilities. |
325 |
|
|
*/ |
326 |
|
|
|
327 |
|
8 |
sc_s_keypad = keypad_xmit; |
328 |
|
8 |
if (hardcopy || sc_s_keypad == NULL) |
329 |
|
|
sc_s_keypad = ""; |
330 |
|
8 |
sc_e_keypad = keypad_local; |
331 |
|
8 |
if (hardcopy || sc_e_keypad == NULL) |
332 |
|
|
sc_e_keypad = ""; |
333 |
|
|
|
334 |
|
8 |
sc_init = enter_ca_mode; |
335 |
|
8 |
if (hardcopy || sc_init == NULL) |
336 |
|
|
sc_init = ""; |
337 |
|
|
|
338 |
|
8 |
sc_deinit = exit_ca_mode; |
339 |
|
8 |
if (hardcopy || sc_deinit == NULL) |
340 |
|
|
sc_deinit = ""; |
341 |
|
|
|
342 |
|
8 |
sc_eol_clear = clr_eol; |
343 |
✓✗✗✓
|
16 |
if (hardcopy || sc_eol_clear == NULL || *sc_eol_clear == '\0') { |
344 |
|
|
missing_cap = 1; |
345 |
|
|
sc_eol_clear = ""; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
8 |
sc_eos_clear = clr_eos; |
349 |
✗✓✗✗
|
8 |
if (below_mem && |
350 |
|
|
(hardcopy || sc_eos_clear == NULL || *sc_eos_clear == '\0')) { |
351 |
|
|
missing_cap = 1; |
352 |
|
|
sc_eos_clear = ""; |
353 |
|
|
} |
354 |
|
|
|
355 |
|
8 |
sc_clear = clear_screen; |
356 |
✓✗✗✓
|
16 |
if (hardcopy || sc_clear == NULL || *sc_clear == '\0') { |
357 |
|
|
missing_cap = 1; |
358 |
|
|
sc_clear = "\n\n"; |
359 |
|
|
} |
360 |
|
|
|
361 |
|
8 |
sc_move = cursor_address; |
362 |
✓✗✗✓
|
16 |
if (hardcopy || sc_move == NULL || *sc_move == '\0') { |
363 |
|
|
/* |
364 |
|
|
* This is not an error here, because we don't |
365 |
|
|
* always need sc_move. |
366 |
|
|
* We need it only if we don't have home or lower-left. |
367 |
|
|
*/ |
368 |
|
|
sc_move = ""; |
369 |
|
|
can_goto_line = 0; |
370 |
|
|
} else { |
371 |
|
|
can_goto_line = 1; |
372 |
|
|
} |
373 |
|
|
|
374 |
|
8 |
tmodes(enter_standout_mode, exit_standout_mode, &sc_s_in, &sc_s_out, |
375 |
|
|
"", ""); |
376 |
|
16 |
tmodes(enter_underline_mode, exit_underline_mode, &sc_u_in, &sc_u_out, |
377 |
|
8 |
sc_s_in, sc_s_out); |
378 |
|
16 |
tmodes(enter_bold_mode, exit_attribute_mode, &sc_b_in, &sc_b_out, |
379 |
|
8 |
sc_s_in, sc_s_out); |
380 |
|
16 |
tmodes(enter_blink_mode, exit_attribute_mode, &sc_bl_in, &sc_bl_out, |
381 |
|
8 |
sc_s_in, sc_s_out); |
382 |
|
|
|
383 |
|
8 |
sc_visual_bell = flash_screen; |
384 |
|
8 |
if (hardcopy || sc_visual_bell == NULL) |
385 |
|
|
sc_visual_bell = ""; |
386 |
|
|
|
387 |
|
8 |
sc_backspace = "\b"; |
388 |
|
|
|
389 |
|
|
/* |
390 |
|
|
* Choose between using "ho" and "cm" ("home" and "cursor move") |
391 |
|
|
* to move the cursor to the upper left corner of the screen. |
392 |
|
|
*/ |
393 |
|
8 |
t1 = cursor_home; |
394 |
|
8 |
if (hardcopy || t1 == NULL) |
395 |
|
|
t1 = ""; |
396 |
✗✓ |
8 |
if (*sc_move == '\0') { |
397 |
|
|
t2 = ""; |
398 |
|
|
} else { |
399 |
|
8 |
t2 = estrdup(tparm(sc_move, 0, 0, 0, 0, 0, 0, 0, 0, 0)); |
400 |
|
|
} |
401 |
|
8 |
sc_home = cheaper(t1, t2, "|\b^"); |
402 |
|
|
|
403 |
|
|
/* |
404 |
|
|
* Choose between using "ll" and "cm" ("lower left" and "cursor move") |
405 |
|
|
* to move the cursor to the lower left corner of the screen. |
406 |
|
|
*/ |
407 |
|
8 |
t1 = cursor_to_ll; |
408 |
|
8 |
if (hardcopy || t1 == NULL) |
409 |
|
|
t1 = ""; |
410 |
✗✓ |
8 |
if (*sc_move == '\0') { |
411 |
|
|
t2 = ""; |
412 |
|
|
} else { |
413 |
|
8 |
t2 = estrdup(tparm(sc_move, sc_height-1, |
414 |
|
|
0, 0, 0, 0, 0, 0, 0, 0)); |
415 |
|
|
} |
416 |
|
8 |
sc_lower_left = cheaper(t1, t2, "\r"); |
417 |
|
|
|
418 |
|
|
/* |
419 |
|
|
* Get carriage return string. |
420 |
|
|
*/ |
421 |
|
8 |
sc_return = carriage_return; |
422 |
|
8 |
if (hardcopy || sc_return == NULL) |
423 |
|
|
sc_return = "\r"; |
424 |
|
|
|
425 |
|
|
/* |
426 |
|
|
* Choose between using insert_line or scroll_reverse |
427 |
|
|
* to add a line at the top of the screen. |
428 |
|
|
*/ |
429 |
|
8 |
t1 = insert_line; |
430 |
|
8 |
if (hardcopy || t1 == NULL) |
431 |
|
|
t1 = ""; |
432 |
|
8 |
t2 = scroll_reverse; |
433 |
|
8 |
if (hardcopy || t2 == NULL) |
434 |
|
|
t2 = ""; |
435 |
✓✗ |
8 |
if (above_mem) |
436 |
|
|
sc_addline = t1; |
437 |
|
|
else |
438 |
|
8 |
sc_addline = cheaper(t1, t2, ""); |
439 |
✗✓ |
8 |
if (*sc_addline == '\0') { |
440 |
|
|
/* |
441 |
|
|
* Force repaint on any backward movement. |
442 |
|
|
*/ |
443 |
|
|
no_back_scroll = 1; |
444 |
|
|
} |
445 |
|
8 |
} |
446 |
|
|
|
447 |
|
|
/* |
448 |
|
|
* Return the cost of displaying a termcap string. |
449 |
|
|
* We use the trick of calling tputs, but as a char printing function |
450 |
|
|
* we give it inc_costcount, which just increments "costcount". |
451 |
|
|
* This tells us how many chars would be printed by using this string. |
452 |
|
|
* {{ Couldn't we just use strlen? }} |
453 |
|
|
*/ |
454 |
|
|
static int costcount; |
455 |
|
|
|
456 |
|
|
static int |
457 |
|
|
inc_costcount(int c) |
458 |
|
|
{ |
459 |
|
224 |
costcount++; |
460 |
|
112 |
return (c); |
461 |
|
|
} |
462 |
|
|
|
463 |
|
|
static int |
464 |
|
|
cost(char *t) |
465 |
|
|
{ |
466 |
|
64 |
costcount = 0; |
467 |
|
32 |
(void) tputs(t, sc_height, inc_costcount); |
468 |
|
32 |
return (costcount); |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
/* |
472 |
|
|
* Return the "best" of the two given termcap strings. |
473 |
|
|
* The best, if both exist, is the one with the lower |
474 |
|
|
* cost (see cost() function). |
475 |
|
|
*/ |
476 |
|
|
static char * |
477 |
|
|
cheaper(char *t1, char *t2, char *def) |
478 |
|
|
{ |
479 |
✓✓✗✓
|
56 |
if (*t1 == '\0' && *t2 == '\0') { |
480 |
|
|
missing_cap = 1; |
481 |
|
|
return (def); |
482 |
|
|
} |
483 |
✓✓ |
24 |
if (*t1 == '\0') |
484 |
|
8 |
return (t2); |
485 |
✗✓ |
16 |
if (*t2 == '\0') |
486 |
|
|
return (t1); |
487 |
✓✓ |
16 |
if (cost(t1) < cost(t2)) |
488 |
|
8 |
return (t1); |
489 |
|
8 |
return (t2); |
490 |
|
24 |
} |
491 |
|
|
|
492 |
|
|
static void |
493 |
|
|
tmodes(char *incap, char *outcap, char **instr, char **outstr, |
494 |
|
|
char *def_instr, char *def_outstr) |
495 |
|
|
{ |
496 |
✗✓ |
64 |
if (hardcopy) { |
497 |
|
|
*instr = ""; |
498 |
|
|
*outstr = ""; |
499 |
|
|
return; |
500 |
|
|
} |
501 |
|
|
|
502 |
|
32 |
*instr = incap; |
503 |
|
32 |
*outstr = outcap; |
504 |
|
|
|
505 |
✗✓ |
32 |
if (*instr == NULL) { |
506 |
|
|
/* Use defaults. */ |
507 |
|
|
*instr = def_instr; |
508 |
|
|
*outstr = def_outstr; |
509 |
|
|
return; |
510 |
|
|
} |
511 |
|
|
|
512 |
✗✓ |
32 |
if (*outstr == NULL) |
513 |
|
|
/* No specific out capability; use exit_attribute_mode. */ |
514 |
|
|
*outstr = exit_attribute_mode; |
515 |
✗✓ |
32 |
if (*outstr == NULL) |
516 |
|
|
/* Don't even have that, use an empty string */ |
517 |
|
|
*outstr = ""; |
518 |
|
32 |
} |
519 |
|
|
|
520 |
|
|
/* |
521 |
|
|
* Below are the functions which perform all the |
522 |
|
|
* terminal-specific screen manipulation. |
523 |
|
|
*/ |
524 |
|
|
|
525 |
|
|
/* |
526 |
|
|
* Initialize terminal |
527 |
|
|
*/ |
528 |
|
|
void |
529 |
|
|
init(void) |
530 |
|
|
{ |
531 |
✓✗ |
16 |
if (!no_init) |
532 |
|
8 |
(void) tputs(sc_init, sc_height, putchr); |
533 |
✓✗ |
8 |
if (!no_keypad) |
534 |
|
8 |
(void) tputs(sc_s_keypad, sc_height, putchr); |
535 |
✓✗ |
8 |
if (top_scroll) { |
536 |
|
|
int i; |
537 |
|
|
|
538 |
|
|
/* |
539 |
|
|
* This is nice to terminals with no alternate screen, |
540 |
|
|
* but with saved scrolled-off-the-top lines. This way, |
541 |
|
|
* no previous line is lost, but we start with a whole |
542 |
|
|
* screen to ourself. |
543 |
|
|
*/ |
544 |
✓✓ |
528 |
for (i = 1; i < sc_height; i++) |
545 |
|
256 |
(void) putchr('\n'); |
546 |
|
8 |
} else |
547 |
|
|
line_left(); |
548 |
|
8 |
init_done = 1; |
549 |
|
8 |
} |
550 |
|
|
|
551 |
|
|
/* |
552 |
|
|
* Deinitialize terminal |
553 |
|
|
*/ |
554 |
|
|
void |
555 |
|
|
deinit(void) |
556 |
|
|
{ |
557 |
✓✗ |
16 |
if (!init_done) |
558 |
|
|
return; |
559 |
✓✗ |
8 |
if (!no_keypad) |
560 |
|
8 |
(void) tputs(sc_e_keypad, sc_height, putchr); |
561 |
✓✗ |
8 |
if (!no_init) |
562 |
|
8 |
(void) tputs(sc_deinit, sc_height, putchr); |
563 |
|
8 |
init_done = 0; |
564 |
|
16 |
} |
565 |
|
|
|
566 |
|
|
/* |
567 |
|
|
* Home cursor (move to upper left corner of screen). |
568 |
|
|
*/ |
569 |
|
|
void |
570 |
|
|
home(void) |
571 |
|
|
{ |
572 |
|
66 |
(void) tputs(sc_home, 1, putchr); |
573 |
|
33 |
} |
574 |
|
|
|
575 |
|
|
/* |
576 |
|
|
* Add a blank line (called with cursor at home). |
577 |
|
|
* Should scroll the display down. |
578 |
|
|
*/ |
579 |
|
|
void |
580 |
|
|
add_line(void) |
581 |
|
|
{ |
582 |
|
|
(void) tputs(sc_addline, sc_height, putchr); |
583 |
|
|
} |
584 |
|
|
|
585 |
|
|
/* |
586 |
|
|
* Move cursor to lower left corner of screen. |
587 |
|
|
*/ |
588 |
|
|
void |
589 |
|
|
lower_left(void) |
590 |
|
|
{ |
591 |
|
18 |
(void) tputs(sc_lower_left, 1, putchr); |
592 |
|
9 |
} |
593 |
|
|
|
594 |
|
|
/* |
595 |
|
|
* Move cursor to left position of current line. |
596 |
|
|
*/ |
597 |
|
|
void |
598 |
|
|
line_left(void) |
599 |
|
|
{ |
600 |
|
198 |
(void) tputs(sc_return, 1, putchr); |
601 |
|
99 |
} |
602 |
|
|
|
603 |
|
|
/* |
604 |
|
|
* Goto a specific line on the screen. |
605 |
|
|
*/ |
606 |
|
|
void |
607 |
|
|
goto_line(int slinenum) |
608 |
|
|
{ |
609 |
|
384 |
(void) tputs(tparm(sc_move, slinenum, 0, 0, 0, 0, 0, 0, 0, 0), 1, |
610 |
|
|
putchr); |
611 |
|
192 |
} |
612 |
|
|
|
613 |
|
|
/* |
614 |
|
|
* Output the "visual bell", if there is one. |
615 |
|
|
*/ |
616 |
|
|
void |
617 |
|
|
vbell(void) |
618 |
|
|
{ |
619 |
|
|
if (*sc_visual_bell == '\0') |
620 |
|
|
return; |
621 |
|
|
(void) tputs(sc_visual_bell, sc_height, putchr); |
622 |
|
|
} |
623 |
|
|
|
624 |
|
|
/* |
625 |
|
|
* Make a noise. |
626 |
|
|
*/ |
627 |
|
|
static void |
628 |
|
|
beep(void) |
629 |
|
|
{ |
630 |
|
32 |
(void) putchr(CONTROL('G')); |
631 |
|
16 |
} |
632 |
|
|
|
633 |
|
|
/* |
634 |
|
|
* Ring the terminal bell. |
635 |
|
|
*/ |
636 |
|
|
void |
637 |
|
|
ring_bell(void) |
638 |
|
|
{ |
639 |
✗✓ |
32 |
if (quiet == VERY_QUIET) |
640 |
|
|
vbell(); |
641 |
|
|
else |
642 |
|
16 |
beep(); |
643 |
|
16 |
} |
644 |
|
|
|
645 |
|
|
/* |
646 |
|
|
* Clear the screen. |
647 |
|
|
*/ |
648 |
|
|
void |
649 |
|
|
do_clear(void) |
650 |
|
|
{ |
651 |
|
66 |
(void) tputs(sc_clear, sc_height, putchr); |
652 |
|
33 |
} |
653 |
|
|
|
654 |
|
|
/* |
655 |
|
|
* Clear from the cursor to the end of the cursor's line. |
656 |
|
|
* {{ This must not move the cursor. }} |
657 |
|
|
*/ |
658 |
|
|
void |
659 |
|
|
clear_eol(void) |
660 |
|
|
{ |
661 |
|
368 |
(void) tputs(sc_eol_clear, 1, putchr); |
662 |
|
184 |
} |
663 |
|
|
|
664 |
|
|
/* |
665 |
|
|
* Clear the current line. |
666 |
|
|
* Clear the screen if there's off-screen memory below the display. |
667 |
|
|
*/ |
668 |
|
|
static void |
669 |
|
|
clear_eol_bot(void) |
670 |
|
|
{ |
671 |
✗✓ |
198 |
if (below_mem) |
672 |
|
|
(void) tputs(sc_eos_clear, 1, putchr); |
673 |
|
|
else |
674 |
|
99 |
(void) tputs(sc_eol_clear, 1, putchr); |
675 |
|
99 |
} |
676 |
|
|
|
677 |
|
|
/* |
678 |
|
|
* Clear the bottom line of the display. |
679 |
|
|
* Leave the cursor at the beginning of the bottom line. |
680 |
|
|
*/ |
681 |
|
|
void |
682 |
|
|
clear_bot(void) |
683 |
|
|
{ |
684 |
|
|
/* |
685 |
|
|
* If we're in a non-normal attribute mode, temporarily exit |
686 |
|
|
* the mode while we do the clear. Some terminals fill the |
687 |
|
|
* cleared area with the current attribute. |
688 |
|
|
*/ |
689 |
✗✓ |
198 |
if (oldbot) |
690 |
|
|
lower_left(); |
691 |
|
|
else |
692 |
|
99 |
line_left(); |
693 |
|
|
|
694 |
✓✗ |
99 |
if (attrmode == AT_NORMAL) |
695 |
|
99 |
clear_eol_bot(); |
696 |
|
|
else |
697 |
|
|
{ |
698 |
|
|
int saved_attrmode = attrmode; |
699 |
|
|
|
700 |
|
|
at_exit(); |
701 |
|
|
clear_eol_bot(); |
702 |
|
|
at_enter(saved_attrmode); |
703 |
|
|
} |
704 |
|
99 |
} |
705 |
|
|
|
706 |
|
|
void |
707 |
|
|
at_enter(int attr) |
708 |
|
|
{ |
709 |
|
260 |
attr = apply_at_specials(attr); |
710 |
|
|
|
711 |
|
|
/* The one with the most priority is last. */ |
712 |
✗✓ |
130 |
if (attr & AT_UNDERLINE) |
713 |
|
|
(void) tputs(sc_u_in, 1, putchr); |
714 |
✓✓ |
130 |
if (attr & AT_BOLD) |
715 |
|
28 |
(void) tputs(sc_b_in, 1, putchr); |
716 |
✗✓ |
130 |
if (attr & AT_BLINK) |
717 |
|
|
(void) tputs(sc_bl_in, 1, putchr); |
718 |
✓✓ |
130 |
if (attr & AT_STANDOUT) |
719 |
|
50 |
(void) tputs(sc_s_in, 1, putchr); |
720 |
|
|
|
721 |
|
130 |
attrmode = attr; |
722 |
|
130 |
} |
723 |
|
|
|
724 |
|
|
void |
725 |
|
|
at_exit(void) |
726 |
|
|
{ |
727 |
|
|
/* Undo things in the reverse order we did them. */ |
728 |
✓✓ |
2194 |
if (attrmode & AT_STANDOUT) |
729 |
|
50 |
(void) tputs(sc_s_out, 1, putchr); |
730 |
✗✓ |
1097 |
if (attrmode & AT_BLINK) |
731 |
|
|
(void) tputs(sc_bl_out, 1, putchr); |
732 |
✓✓ |
1097 |
if (attrmode & AT_BOLD) |
733 |
|
28 |
(void) tputs(sc_b_out, 1, putchr); |
734 |
✗✓ |
1097 |
if (attrmode & AT_UNDERLINE) |
735 |
|
|
(void) tputs(sc_u_out, 1, putchr); |
736 |
|
|
|
737 |
|
1097 |
attrmode = AT_NORMAL; |
738 |
|
1097 |
} |
739 |
|
|
|
740 |
|
|
void |
741 |
|
|
at_switch(int attr) |
742 |
|
|
{ |
743 |
|
61036 |
int new_attrmode = apply_at_specials(attr); |
744 |
|
|
int ignore_modes = AT_ANSI; |
745 |
|
|
|
746 |
✓✓ |
30518 |
if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) { |
747 |
|
104 |
at_exit(); |
748 |
|
104 |
at_enter(attr); |
749 |
|
104 |
} |
750 |
|
30518 |
} |
751 |
|
|
|
752 |
|
|
int |
753 |
|
|
is_at_equiv(int attr1, int attr2) |
754 |
|
|
{ |
755 |
|
80328 |
attr1 = apply_at_specials(attr1); |
756 |
|
40164 |
attr2 = apply_at_specials(attr2); |
757 |
|
|
|
758 |
|
40164 |
return (attr1 == attr2); |
759 |
|
|
} |
760 |
|
|
|
761 |
|
|
int |
762 |
|
|
apply_at_specials(int attr) |
763 |
|
|
{ |
764 |
✗✓ |
376636 |
if (attr & AT_BINARY) |
765 |
|
|
attr |= binattr; |
766 |
✓✓ |
188318 |
if (attr & AT_HILITE) |
767 |
|
720 |
attr |= AT_STANDOUT; |
768 |
|
188318 |
attr &= ~(AT_BINARY|AT_HILITE); |
769 |
|
|
|
770 |
|
188318 |
return (attr); |
771 |
|
|
} |
772 |
|
|
|
773 |
|
|
/* |
774 |
|
|
* Output a plain backspace, without erasing the previous char. |
775 |
|
|
*/ |
776 |
|
|
void |
777 |
|
|
putbs(void) |
778 |
|
|
{ |
779 |
|
434 |
(void) tputs(sc_backspace, 1, putchr); |
780 |
|
217 |
} |