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