1 |
|
|
/* $OpenBSD: cl_screen.c,v 1.28 2017/04/18 01:45:33 deraadt Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1993, 1994 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* Copyright (c) 1993, 1994, 1995, 1996 |
7 |
|
|
* Keith Bostic. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* See the LICENSE file for redistribution information. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
#include "config.h" |
13 |
|
|
|
14 |
|
|
#include <sys/types.h> |
15 |
|
|
#include <sys/queue.h> |
16 |
|
|
|
17 |
|
|
#include <bitstring.h> |
18 |
|
|
#include <curses.h> |
19 |
|
|
#include <errno.h> |
20 |
|
|
#include <signal.h> |
21 |
|
|
#include <stdio.h> |
22 |
|
|
#include <stdlib.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
#include <term.h> |
25 |
|
|
#include <termios.h> |
26 |
|
|
#include <unistd.h> |
27 |
|
|
|
28 |
|
|
#include "../common/common.h" |
29 |
|
|
#include "cl.h" |
30 |
|
|
|
31 |
|
|
static int cl_ex_end(GS *); |
32 |
|
|
static int cl_ex_init(SCR *); |
33 |
|
|
static void cl_freecap(CL_PRIVATE *); |
34 |
|
|
static int cl_vi_end(GS *); |
35 |
|
|
static int cl_vi_init(SCR *); |
36 |
|
|
static int cl_putenv(char *, char *, u_long); |
37 |
|
|
|
38 |
|
|
/* |
39 |
|
|
* cl_screen -- |
40 |
|
|
* Switch screen types. |
41 |
|
|
* |
42 |
|
|
* PUBLIC: int cl_screen(SCR *, u_int32_t); |
43 |
|
|
*/ |
44 |
|
|
int |
45 |
|
|
cl_screen(SCR *sp, u_int32_t flags) |
46 |
|
|
{ |
47 |
|
|
CL_PRIVATE *clp; |
48 |
|
|
GS *gp; |
49 |
|
|
|
50 |
|
|
gp = sp->gp; |
51 |
|
|
clp = CLP(sp); |
52 |
|
|
|
53 |
|
|
/* See if the current information is incorrect. */ |
54 |
|
|
if (F_ISSET(gp, G_SRESTART)) { |
55 |
|
|
if ((!F_ISSET(sp, SC_SCR_EX | SC_SCR_VI) || |
56 |
|
|
resizeterm(O_VAL(sp, O_LINES), O_VAL(sp, O_COLUMNS))) && |
57 |
|
|
cl_quit(gp)) |
58 |
|
|
return (1); |
59 |
|
|
F_CLR(gp, G_SRESTART); |
60 |
|
|
} |
61 |
|
|
|
62 |
|
|
/* See if we're already in the right mode. */ |
63 |
|
|
if ((LF_ISSET(SC_EX) && F_ISSET(sp, SC_SCR_EX)) || |
64 |
|
|
(LF_ISSET(SC_VI) && F_ISSET(sp, SC_SCR_VI))) |
65 |
|
|
return (0); |
66 |
|
|
|
67 |
|
|
/* |
68 |
|
|
* Fake leaving ex mode. |
69 |
|
|
* |
70 |
|
|
* We don't actually exit ex or vi mode unless forced (e.g. by a window |
71 |
|
|
* size change). This is because many curses implementations can't be |
72 |
|
|
* called twice in a single program. Plus, it's faster. If the editor |
73 |
|
|
* "leaves" vi to enter ex, when it exits ex we'll just fall back into |
74 |
|
|
* vi. |
75 |
|
|
*/ |
76 |
|
|
if (F_ISSET(sp, SC_SCR_EX)) |
77 |
|
|
F_CLR(sp, SC_SCR_EX); |
78 |
|
|
|
79 |
|
|
/* |
80 |
|
|
* Fake leaving vi mode. |
81 |
|
|
* |
82 |
|
|
* Clear out the rest of the screen if we're in the middle of a split |
83 |
|
|
* screen. Move to the last line in the current screen -- this makes |
84 |
|
|
* terminal scrolling happen naturally. Note: *don't* move past the |
85 |
|
|
* end of the screen, as there are ex commands (e.g., :read ! cat file) |
86 |
|
|
* that don't want to. Don't clear the info line, its contents may be |
87 |
|
|
* valid, e.g. :file|append. |
88 |
|
|
*/ |
89 |
|
|
if (F_ISSET(sp, SC_SCR_VI)) { |
90 |
|
|
F_CLR(sp, SC_SCR_VI); |
91 |
|
|
|
92 |
|
|
if (TAILQ_NEXT(sp, q)) { |
93 |
|
|
(void)move(RLNO(sp, sp->rows), 0); |
94 |
|
|
clrtobot(); |
95 |
|
|
} |
96 |
|
|
(void)move(RLNO(sp, sp->rows) - 1, 0); |
97 |
|
|
refresh(); |
98 |
|
|
} |
99 |
|
|
|
100 |
|
|
/* Enter the requested mode. */ |
101 |
|
|
if (LF_ISSET(SC_EX)) { |
102 |
|
|
if (cl_ex_init(sp)) |
103 |
|
|
return (1); |
104 |
|
|
F_SET(clp, CL_IN_EX | CL_SCR_EX_INIT); |
105 |
|
|
|
106 |
|
|
/* |
107 |
|
|
* If doing an ex screen for ex mode, move to the last line |
108 |
|
|
* on the screen. |
109 |
|
|
*/ |
110 |
|
|
if (F_ISSET(sp, SC_EX) && clp->cup != NULL) |
111 |
|
|
tputs(tgoto(clp->cup, |
112 |
|
|
0, O_VAL(sp, O_LINES) - 1), 1, cl_putchar); |
113 |
|
|
} else { |
114 |
|
|
if (cl_vi_init(sp)) |
115 |
|
|
return (1); |
116 |
|
|
F_CLR(clp, CL_IN_EX); |
117 |
|
|
F_SET(clp, CL_SCR_VI_INIT); |
118 |
|
|
} |
119 |
|
|
return (0); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
/* |
123 |
|
|
* cl_quit -- |
124 |
|
|
* Shutdown the screens. |
125 |
|
|
* |
126 |
|
|
* PUBLIC: int cl_quit(GS *); |
127 |
|
|
*/ |
128 |
|
|
int |
129 |
|
|
cl_quit(GS *gp) |
130 |
|
|
{ |
131 |
|
|
CL_PRIVATE *clp; |
132 |
|
|
int rval; |
133 |
|
|
|
134 |
|
|
rval = 0; |
135 |
|
|
clp = GCLP(gp); |
136 |
|
|
|
137 |
|
|
/* |
138 |
|
|
* If we weren't really running, ignore it. This happens if the |
139 |
|
|
* screen changes size before we've called curses. |
140 |
|
|
*/ |
141 |
|
|
if (!F_ISSET(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT)) |
142 |
|
|
return (0); |
143 |
|
|
|
144 |
|
|
/* Clean up the terminal mappings. */ |
145 |
|
|
if (cl_term_end(gp)) |
146 |
|
|
rval = 1; |
147 |
|
|
|
148 |
|
|
/* Really leave vi mode. */ |
149 |
|
|
if (F_ISSET(clp, CL_STDIN_TTY) && |
150 |
|
|
F_ISSET(clp, CL_SCR_VI_INIT) && cl_vi_end(gp)) |
151 |
|
|
rval = 1; |
152 |
|
|
|
153 |
|
|
/* Really leave ex mode. */ |
154 |
|
|
if (F_ISSET(clp, CL_STDIN_TTY) && |
155 |
|
|
F_ISSET(clp, CL_SCR_EX_INIT) && cl_ex_end(gp)) |
156 |
|
|
rval = 1; |
157 |
|
|
|
158 |
|
|
/* |
159 |
|
|
* If we were running ex when we quit, or we're using an implementation |
160 |
|
|
* of curses where endwin() doesn't get this right, restore the original |
161 |
|
|
* terminal modes. |
162 |
|
|
* |
163 |
|
|
* XXX |
164 |
|
|
* We always do this because it's too hard to figure out what curses |
165 |
|
|
* implementations get it wrong. It may discard type-ahead characters |
166 |
|
|
* from the tty queue. |
167 |
|
|
*/ |
168 |
|
|
if (F_ISSET(clp, CL_STDIN_TTY)) |
169 |
|
|
(void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); |
170 |
|
|
|
171 |
|
|
F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); |
172 |
|
|
return (rval); |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
/* |
176 |
|
|
* cl_vi_init -- |
177 |
|
|
* Initialize the curses vi screen. |
178 |
|
|
*/ |
179 |
|
|
static int |
180 |
|
|
cl_vi_init(SCR *sp) |
181 |
|
|
{ |
182 |
|
|
CL_PRIVATE *clp; |
183 |
|
|
char *o_cols, *o_lines, *o_term, *ttype; |
184 |
|
|
|
185 |
|
|
clp = CLP(sp); |
186 |
|
|
|
187 |
|
|
/* If already initialized, just set the terminal modes. */ |
188 |
|
|
if (F_ISSET(clp, CL_SCR_VI_INIT)) |
189 |
|
|
goto fast; |
190 |
|
|
|
191 |
|
|
/* Curses vi always reads from (and writes to) a terminal. */ |
192 |
|
|
if (!F_ISSET(clp, CL_STDIN_TTY) || !isatty(STDOUT_FILENO)) { |
193 |
|
|
msgq(sp, M_ERR, |
194 |
|
|
"Vi's standard input and output must be a terminal"); |
195 |
|
|
return (1); |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
/* We'll need a terminal type. */ |
199 |
|
|
if (opts_empty(sp, O_TERM, 0)) |
200 |
|
|
return (1); |
201 |
|
|
ttype = O_STR(sp, O_TERM); |
202 |
|
|
|
203 |
|
|
/* |
204 |
|
|
* XXX |
205 |
|
|
* Changing the row/column and terminal values is done by putting them |
206 |
|
|
* into the environment, which is then read by curses. What this loses |
207 |
|
|
* in ugliness, it makes up for in stupidity. We can't simply put the |
208 |
|
|
* values into the environment ourselves, because in the presence of a |
209 |
|
|
* kernel mechanism for returning the window size, entering values into |
210 |
|
|
* the environment will screw up future screen resizing events, e.g. if |
211 |
|
|
* the user enters a :shell command and then resizes their window. So, |
212 |
|
|
* if they weren't already in the environment, we make sure to delete |
213 |
|
|
* them immediately after setting them. |
214 |
|
|
* |
215 |
|
|
* XXX |
216 |
|
|
* Putting the TERM variable into the environment is necessary, even |
217 |
|
|
* though we're using newterm() here. We may be using initscr() as |
218 |
|
|
* the underlying function. |
219 |
|
|
*/ |
220 |
|
|
o_term = getenv("TERM"); |
221 |
|
|
cl_putenv("TERM", ttype, 0); |
222 |
|
|
o_lines = getenv("LINES"); |
223 |
|
|
cl_putenv("LINES", NULL, (u_long)O_VAL(sp, O_LINES)); |
224 |
|
|
o_cols = getenv("COLUMNS"); |
225 |
|
|
cl_putenv("COLUMNS", NULL, (u_long)O_VAL(sp, O_COLUMNS)); |
226 |
|
|
|
227 |
|
|
/* |
228 |
|
|
* The terminal is aways initialized, either in `main`, or by a |
229 |
|
|
* previous call to newterm(3). |
230 |
|
|
*/ |
231 |
|
|
(void)del_curterm(cur_term); |
232 |
|
|
|
233 |
|
|
/* |
234 |
|
|
* We don't care about the SCREEN reference returned by newterm, we |
235 |
|
|
* never have more than one SCREEN at a time. |
236 |
|
|
*/ |
237 |
|
|
errno = 0; |
238 |
|
|
if (newterm(ttype, stdout, stdin) == NULL) { |
239 |
|
|
if (errno) |
240 |
|
|
msgq(sp, M_SYSERR, "%s", ttype); |
241 |
|
|
else |
242 |
|
|
msgq(sp, M_ERR, "%s: unknown terminal type", ttype); |
243 |
|
|
return (1); |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
if (o_term == NULL) |
247 |
|
|
unsetenv("TERM"); |
248 |
|
|
if (o_lines == NULL) |
249 |
|
|
unsetenv("LINES"); |
250 |
|
|
if (o_cols == NULL) |
251 |
|
|
unsetenv("COLUMNS"); |
252 |
|
|
|
253 |
|
|
/* |
254 |
|
|
* XXX |
255 |
|
|
* Someone got let out alone without adult supervision -- the SunOS |
256 |
|
|
* newterm resets the signal handlers. There's a race, but it's not |
257 |
|
|
* worth closing. |
258 |
|
|
*/ |
259 |
|
|
(void)sig_init(sp->gp, sp); |
260 |
|
|
|
261 |
|
|
/* |
262 |
|
|
* We use raw mode. What we want is 8-bit clean, however, signals |
263 |
|
|
* and flow control should continue to work. Admittedly, it sounds |
264 |
|
|
* like cbreak, but it isn't. Using cbreak() can get you additional |
265 |
|
|
* things like IEXTEN, which turns on flags like DISCARD and LNEXT. |
266 |
|
|
* |
267 |
|
|
* !!! |
268 |
|
|
* If raw isn't turning off echo and newlines, something's wrong. |
269 |
|
|
* However, it shouldn't hurt. |
270 |
|
|
*/ |
271 |
|
|
noecho(); /* No character echo. */ |
272 |
|
|
nonl(); /* No CR/NL translation. */ |
273 |
|
|
raw(); /* 8-bit clean. */ |
274 |
|
|
idlok(stdscr, 1); /* Use hardware insert/delete line. */ |
275 |
|
|
|
276 |
|
|
/* Put the cursor keys into application mode. */ |
277 |
|
|
(void)keypad(stdscr, TRUE); |
278 |
|
|
|
279 |
|
|
/* |
280 |
|
|
* XXX |
281 |
|
|
* The screen TI sequence just got sent. See the comment in |
282 |
|
|
* cl_funcs.c:cl_attr(). |
283 |
|
|
*/ |
284 |
|
|
clp->ti_te = TI_SENT; |
285 |
|
|
|
286 |
|
|
/* |
287 |
|
|
* XXX |
288 |
|
|
* Historic implementations of curses handled SIGTSTP signals |
289 |
|
|
* in one of three ways. They either: |
290 |
|
|
* |
291 |
|
|
* 1: Set their own handler, regardless. |
292 |
|
|
* 2: Did not set a handler if a handler was already installed. |
293 |
|
|
* 3: Set their own handler, but then called any previously set |
294 |
|
|
* handler after completing their own cleanup. |
295 |
|
|
* |
296 |
|
|
* We don't try and figure out which behavior is in place, we force |
297 |
|
|
* it to SIG_DFL after initializing the curses interface, which means |
298 |
|
|
* that curses isn't going to take the signal. Since curses isn't |
299 |
|
|
* reentrant (i.e., the whole curses SIGTSTP interface is a fantasy), |
300 |
|
|
* we're doing The Right Thing. |
301 |
|
|
*/ |
302 |
|
|
(void)signal(SIGTSTP, SIG_DFL); |
303 |
|
|
|
304 |
|
|
/* |
305 |
|
|
* If flow control was on, turn it back on. Turn signals on. ISIG |
306 |
|
|
* turns on VINTR, VQUIT, VDSUSP and VSUSP. The main curses code |
307 |
|
|
* already installed a handler for VINTR. We're going to disable the |
308 |
|
|
* other three. |
309 |
|
|
* |
310 |
|
|
* XXX |
311 |
|
|
* We want to use ^Y as a vi scrolling command. If the user has the |
312 |
|
|
* DSUSP character set to ^Y (common practice) clean it up. As it's |
313 |
|
|
* equally possible that the user has VDSUSP set to 'a', we disable |
314 |
|
|
* it regardless. It doesn't make much sense to suspend vi at read, |
315 |
|
|
* so I don't think anyone will care. Alternatively, we could look |
316 |
|
|
* it up in the table of legal command characters and turn it off if |
317 |
|
|
* it matches one. |
318 |
|
|
* |
319 |
|
|
* XXX |
320 |
|
|
* We don't check to see if the user had signals enabled originally. |
321 |
|
|
* If they didn't, it's unclear what we're supposed to do here, but |
322 |
|
|
* it's also pretty unlikely. |
323 |
|
|
*/ |
324 |
|
|
if (tcgetattr(STDIN_FILENO, &clp->vi_enter)) { |
325 |
|
|
msgq(sp, M_SYSERR, "tcgetattr"); |
326 |
|
|
goto err; |
327 |
|
|
} |
328 |
|
|
if (clp->orig.c_iflag & IXON) |
329 |
|
|
clp->vi_enter.c_iflag |= IXON; |
330 |
|
|
if (clp->orig.c_iflag & IXOFF) |
331 |
|
|
clp->vi_enter.c_iflag |= IXOFF; |
332 |
|
|
|
333 |
|
|
clp->vi_enter.c_lflag |= ISIG; |
334 |
|
|
clp->vi_enter.c_cc[VDSUSP] = _POSIX_VDISABLE; |
335 |
|
|
clp->vi_enter.c_cc[VQUIT] = _POSIX_VDISABLE; |
336 |
|
|
clp->vi_enter.c_cc[VSUSP] = _POSIX_VDISABLE; |
337 |
|
|
|
338 |
|
|
/* |
339 |
|
|
* XXX |
340 |
|
|
* OSF/1 doesn't turn off the <discard>, <literal-next> or <status> |
341 |
|
|
* characters when curses switches into raw mode. It should be OK |
342 |
|
|
* to do it explicitly for everyone. |
343 |
|
|
*/ |
344 |
|
|
clp->vi_enter.c_cc[VDISCARD] = _POSIX_VDISABLE; |
345 |
|
|
clp->vi_enter.c_cc[VLNEXT] = _POSIX_VDISABLE; |
346 |
|
|
clp->vi_enter.c_cc[VSTATUS] = _POSIX_VDISABLE; |
347 |
|
|
|
348 |
|
|
/* Initialize terminal based information. */ |
349 |
|
|
if (cl_term_init(sp)) |
350 |
|
|
goto err; |
351 |
|
|
|
352 |
|
|
fast: /* Set the terminal modes. */ |
353 |
|
|
if (tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &clp->vi_enter)) { |
354 |
|
|
if (errno == EINTR) |
355 |
|
|
goto fast; |
356 |
|
|
msgq(sp, M_SYSERR, "tcsetattr"); |
357 |
|
|
err: (void)cl_vi_end(sp->gp); |
358 |
|
|
return (1); |
359 |
|
|
} |
360 |
|
|
return (0); |
361 |
|
|
} |
362 |
|
|
|
363 |
|
|
/* |
364 |
|
|
* cl_vi_end -- |
365 |
|
|
* Shutdown the vi screen. |
366 |
|
|
*/ |
367 |
|
|
static int |
368 |
|
|
cl_vi_end(GS *gp) |
369 |
|
|
{ |
370 |
|
|
CL_PRIVATE *clp; |
371 |
|
|
|
372 |
|
|
clp = GCLP(gp); |
373 |
|
|
|
374 |
|
|
/* Restore the cursor keys to normal mode. */ |
375 |
|
|
(void)keypad(stdscr, FALSE); |
376 |
|
|
|
377 |
|
|
/* |
378 |
|
|
* If we were running vi when we quit, scroll the screen up a single |
379 |
|
|
* line so we don't lose any information. |
380 |
|
|
* |
381 |
|
|
* Move to the bottom of the window (some endwin implementations don't |
382 |
|
|
* do this for you). |
383 |
|
|
*/ |
384 |
|
|
if (!F_ISSET(clp, CL_IN_EX)) { |
385 |
|
|
(void)move(0, 0); |
386 |
|
|
(void)deleteln(); |
387 |
|
|
(void)move(LINES - 1, 0); |
388 |
|
|
(void)refresh(); |
389 |
|
|
} |
390 |
|
|
|
391 |
|
|
cl_freecap(clp); |
392 |
|
|
|
393 |
|
|
/* End curses window. */ |
394 |
|
|
(void)endwin(); |
395 |
|
|
|
396 |
|
|
/* Free the SCREEN created by newterm(3). */ |
397 |
|
|
delscreen(set_term(NULL)); |
398 |
|
|
|
399 |
|
|
/* |
400 |
|
|
* XXX |
401 |
|
|
* The screen TE sequence just got sent. See the comment in |
402 |
|
|
* cl_funcs.c:cl_attr(). |
403 |
|
|
*/ |
404 |
|
|
clp->ti_te = TE_SENT; |
405 |
|
|
|
406 |
|
|
return (0); |
407 |
|
|
} |
408 |
|
|
|
409 |
|
|
/* |
410 |
|
|
* cl_ex_init -- |
411 |
|
|
* Initialize the ex screen. |
412 |
|
|
*/ |
413 |
|
|
static int |
414 |
|
|
cl_ex_init(SCR *sp) |
415 |
|
|
{ |
416 |
|
|
CL_PRIVATE *clp; |
417 |
|
|
|
418 |
|
|
clp = CLP(sp); |
419 |
|
|
|
420 |
|
|
/* If already initialized, just set the terminal modes. */ |
421 |
|
|
if (F_ISSET(clp, CL_SCR_EX_INIT)) |
422 |
|
|
goto fast; |
423 |
|
|
|
424 |
|
|
/* If not reading from a file, we're done. */ |
425 |
|
|
if (!F_ISSET(clp, CL_STDIN_TTY)) |
426 |
|
|
return (0); |
427 |
|
|
|
428 |
|
|
/* Get the ex termcap/terminfo strings. */ |
429 |
|
|
(void)cl_getcap(sp, "cup", &clp->cup); |
430 |
|
|
(void)cl_getcap(sp, "smso", &clp->smso); |
431 |
|
|
(void)cl_getcap(sp, "rmso", &clp->rmso); |
432 |
|
|
(void)cl_getcap(sp, "el", &clp->el); |
433 |
|
|
(void)cl_getcap(sp, "cuu1", &clp->cuu1); |
434 |
|
|
|
435 |
|
|
/* Enter_standout_mode and exit_standout_mode are paired. */ |
436 |
|
|
if (clp->smso == NULL || clp->rmso == NULL) { |
437 |
|
|
free(clp->smso); |
438 |
|
|
clp->smso = NULL; |
439 |
|
|
free(clp->rmso); |
440 |
|
|
clp->rmso = NULL; |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
/* |
444 |
|
|
* Turn on canonical mode, with normal input and output processing. |
445 |
|
|
* Start with the original terminal settings as the user probably |
446 |
|
|
* had them (including any local extensions) set correctly for the |
447 |
|
|
* current terminal. |
448 |
|
|
* |
449 |
|
|
* !!! |
450 |
|
|
* We can't get everything that we need portably; for example, ONLCR, |
451 |
|
|
* mapping <newline> to <carriage-return> on output isn't required |
452 |
|
|
* by POSIX 1003.1b-1993. If this turns out to be a problem, then |
453 |
|
|
* we'll either have to play some games on the mapping, or we'll have |
454 |
|
|
* to make all ex printf's output \r\n instead of \n. |
455 |
|
|
*/ |
456 |
|
|
clp->ex_enter = clp->orig; |
457 |
|
|
clp->ex_enter.c_lflag |= |
458 |
|
|
ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ICANON | IEXTEN | ISIG; |
459 |
|
|
clp->ex_enter.c_iflag |= ICRNL; |
460 |
|
|
clp->ex_enter.c_oflag |= ONLCR | OPOST; |
461 |
|
|
|
462 |
|
|
fast: if (tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->ex_enter)) { |
463 |
|
|
if (errno == EINTR) |
464 |
|
|
goto fast; |
465 |
|
|
msgq(sp, M_SYSERR, "tcsetattr"); |
466 |
|
|
return (1); |
467 |
|
|
} |
468 |
|
|
return (0); |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
/* |
472 |
|
|
* cl_ex_end -- |
473 |
|
|
* Shutdown the ex screen. |
474 |
|
|
*/ |
475 |
|
|
static int |
476 |
|
|
cl_ex_end(GS *gp) |
477 |
|
|
{ |
478 |
|
|
CL_PRIVATE *clp; |
479 |
|
|
|
480 |
|
|
clp = GCLP(gp); |
481 |
|
|
|
482 |
|
|
cl_freecap(clp); |
483 |
|
|
|
484 |
|
|
return (0); |
485 |
|
|
} |
486 |
|
|
|
487 |
|
|
/* |
488 |
|
|
* cl_getcap -- |
489 |
|
|
* Retrieve termcap/terminfo strings. |
490 |
|
|
* |
491 |
|
|
* PUBLIC: int cl_getcap(SCR *, char *, char **); |
492 |
|
|
*/ |
493 |
|
|
int |
494 |
|
|
cl_getcap(SCR *sp, char *name, char **elementp) |
495 |
|
|
{ |
496 |
|
|
size_t len; |
497 |
|
|
char *t; |
498 |
|
|
|
499 |
|
|
if ((t = tigetstr(name)) != NULL && |
500 |
|
|
t != (char *)-1 && (len = strlen(t)) != 0) { |
501 |
|
|
MALLOC_RET(sp, *elementp, len + 1); |
502 |
|
|
memmove(*elementp, t, len + 1); |
503 |
|
|
} |
504 |
|
|
return (0); |
505 |
|
|
} |
506 |
|
|
|
507 |
|
|
/* |
508 |
|
|
* cl_freecap -- |
509 |
|
|
* Free any allocated termcap/terminfo strings. |
510 |
|
|
*/ |
511 |
|
|
static void |
512 |
|
|
cl_freecap(CL_PRIVATE *clp) |
513 |
|
|
{ |
514 |
|
|
free(clp->el); |
515 |
|
|
clp->el = NULL; |
516 |
|
|
free(clp->cup); |
517 |
|
|
clp->cup = NULL; |
518 |
|
|
free(clp->cuu1); |
519 |
|
|
clp->cuu1 = NULL; |
520 |
|
|
free(clp->rmso); |
521 |
|
|
clp->rmso = NULL; |
522 |
|
|
free(clp->smso); |
523 |
|
|
clp->smso = NULL; |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
/* |
527 |
|
|
* cl_putenv -- |
528 |
|
|
* Put a value into the environment. |
529 |
|
|
*/ |
530 |
|
|
static int |
531 |
|
|
cl_putenv(char *name, char *str, u_long value) |
532 |
|
|
{ |
533 |
|
|
char buf[40]; |
534 |
|
|
|
535 |
|
|
if (str == NULL) { |
536 |
|
|
(void)snprintf(buf, sizeof(buf), "%lu", value); |
537 |
|
|
return (setenv(name, buf, 1)); |
538 |
|
|
} else |
539 |
|
|
return (setenv(name, str, 1)); |
540 |
|
|
} |