1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1995, by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 /*
28 * newterm.c
29 *
30 * XCurses Library
31 *
32 * Copyright 1990, 1995 by Mortice Kern Systems Inc. All rights reserved.
33 *
34 */
35
36 #ifdef M_RCSID
37 #ifndef lint
38 static char const rcsID[] = "$Header: /rd/src/libc/xcurses/rcs/newterm.c 1.15 1995/07/25 19:54:00 ant Exp $";
39 #endif
40 #endif
41
42 #include <private.h>
43 #include <m_wio.h>
44 #include <errno.h>
45 #include <signal.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 int LINES, COLS;
50 int COLORS, COLOR_PAIRS;
51
52 WINDOW *curscr;
53 WINDOW *stdscr;
54 SCREEN *__m_screen;
55
56 static short assume_one_line = FALSE;
57
58 /*
59 * Assume terminal has only one screen line by restricting those
60 * capabilities that assume more than one line. This function must
61 * be called before initscr() or newterm().
62 *
63 * This flag will reset after initscr() or newterm() so that subsequent
64 * calls to newterm(), without a preceding call to filter(), will load
65 * an unmodified terminal. THIS IS NOT HISTORICAL PRACTICE, BUT DEEMED
66 * USEFUL.
67 */
68 void
filter(void)69 filter(void)
70 {
71 #ifdef M_CURSES_TRACE
72 __m_trace("filter(void)");
73 #endif
74 assume_one_line = TRUE;
75 __m_return_void("filter");
76 }
77
78 /*f
79 * SIGTSTP Handler.
80 */
81 void
tstp(signo)82 tstp(signo)
83 int signo;
84 {
85 #ifdef SIGTSTP
86 /* Only permit SIGTSTP if the curent process is the process
87 * group leader. If the process is not the current group
88 * leader, then suspending the current process will suspend
89 * other members of the process group, such as the parent
90 * process.
91 */
92 if (getpid() == getpgrp()) {
93 (void) endwin();
94
95 #ifdef SIG_UNBLOCK
96 {
97 sigset_t unblock;
98
99 (void) sigemptyset(&unblock);
100 (void) sigaddset(&unblock, SIGTSTP);
101 (void) sigprocmask(SIG_UNBLOCK, &unblock, (sigset_t *) 0);
102 }
103 #endif /* SIG_UNBLOCK */
104 (void) signal(SIGTSTP, SIG_DFL);
105 (void) kill(0, SIGTSTP);
106 } else {
107 (void) beep();
108 }
109
110 (void) signal(SIGTSTP, tstp);
111 (void) wrefresh(curscr);
112 #else /* no SIGTSTP */
113 (void) beep();
114 #endif /* SIGTSTP */
115 }
116
117 int __m_slk_format = -1;
118
119 /*
120 * Do real soft label key initialisation once setupterm() have been called
121 * to load the current terminal. Determine whether the terminal supplies
122 * soft label keys, or whether we have to fake it by using the last line
123 * of a terminal screen.
124 */
125 int
__m_slk_init(SCREEN * sp,int style)126 __m_slk_init(SCREEN *sp, int style)
127 {
128 int code;
129
130 #ifdef M_CURSES_TRACE
131 __m_trace("__m_slk_init(%d)", style );
132 #endif
133
134 code = ERR;
135
136 /* Does the terminal have a method to program the soft label key? */
137 if (plab_norm != (char *) 0 || pkey_plab != (char *) 0) {
138 code = OK;
139 goto done;
140 }
141
142 /* We have to fake it. */
143 if (lines < 2)
144 goto done;
145
146 sp->_slk._w = subwin(sp->_newscr, 1, 0, --lines, 0);
147 if (sp->_slk._w == (WINDOW *) 0)
148 goto done;
149
150 code = OK;
151 done:
152 return __m_return_code("__m_slk_init", code);
153 }
154
155 /*
156 * The XCurses specification is unclear how ripoffline() would
157 * affect newterm(). We assume that it can't be used with newterm()
158 * and that it only affects initscr(), which is responsible for
159 * creating stdscr.
160 */
161 static t_rip rip = { 0 };
162
163 /*
164 * If line is positive (1), one line is removed from the beginning of
165 * stdscr; else if line is negative (-1), one line is removed from the end.
166 */
167 int
ripoffline(int line,int (* init)(WINDOW *,int))168 ripoffline(int line, int (*init)(WINDOW *, int))
169 {
170 int i;
171
172 #ifdef M_CURSES_TRACE
173 __m_trace("ripoffline(%d, %p)", line, init);
174 #endif
175
176 i = rip.top - rip.bottom;
177
178 if (line != 0 && i + 1 < M_CURSES_MAX_RIPOFFLINE) {
179 rip.line[i].init = init;
180 if (line < 0)
181 rip.line[i].dy = --rip.bottom;
182 else
183 rip.line[i].dy = ++rip.top;
184 }
185
186 return __m_return_code("ripoffline", OK);
187 }
188
189 /*f
190 * Create a new terminal screen. Used if a program is going to be sending
191 * output to more than one terminal. It returns a SCREEN* for the terminal.
192 * The parameters are a terminal name, output FILE*, and input FILE*. If
193 * the terminal name is null then $TERM is used. The program must also
194 * call endwin() for each terminal being used before exiting from curses.
195 * If newterm() is called more than once for the same terminal, the first
196 * terminal referred to must be the last one for which endwin() is called.
197 */
198 SCREEN *
newterm(term,out_fp,in_fp)199 newterm(term, out_fp, in_fp)
200 char *term;
201 FILE *out_fp, *in_fp;
202 {
203 WINDOW *w;
204 t_wide_io *wio;
205 SCREEN *sp, *osp;
206 int i, n, y, errret;
207
208 #ifdef M_CURSES_TRACE
209 __m_trace(
210 "newterm(%s, %p, %p)",
211 term == (char *) 0 ? "NULL" : term, out_fp, in_fp
212 );
213 #endif
214
215 /* Input stream should be unbuffered so that m_tfgetc() works
216 * correctly on BSD and SUN systems.
217 */
218 (void) SETVBUF(in_fp, (char *) 0, _IONBF, BUFSIZ);
219 #if 0
220 /*
221 * Not sure whether we really want to concern ourselves with the output
222 * buffer scheme. Might be best to leave it upto the application to
223 * deal with buffer schemes and when to perform flushes.
224 *
225 * MKS Vi uses MKS Curses and so must support the ability to switch in
226 * and out of Curses mode when switching from Vi to Ex and back.
227 * Problem is that in Vi mode you would prefer full buffered output to
228 * give updates a smoother appearance and Ex mode you require line
229 * buffered in order to see prompts and messages.
230 */
231 (void) SETVBUF(out_fp, (char *) 0, _IOLBF, BUFSIZ);
232 #endif
233 errno = 0;
234
235 if (__m_setupterm(term, fileno(in_fp), fileno(out_fp), &errret)==ERR) {
236 switch (errret) {
237 case -1:
238 errno = ENOMEM;
239 break;
240 case 2:
241 errno = ENAMETOOLONG;
242 break;
243 case 0:
244 default:
245 errno = ENOENT;
246 break;
247 }
248 goto error1;
249 }
250
251 if (__m_doupdate_init())
252 goto error1;
253
254 if ((sp = (SCREEN *) calloc(1, sizeof *sp)) == (SCREEN *) 0)
255 goto error1;
256
257 sp->_if = in_fp;
258 sp->_of = out_fp;
259 sp->_term = cur_term;
260
261 sp->_unget._size = __m_decode_init((t_decode **) &sp->_decode);
262
263 /* Maximum length of a multbyte key sequence, including
264 * multibyte characters and terminal function keys.
265 */
266 if (sp->_unget._size < MB_LEN_MAX)
267 sp->_unget._size = MB_LEN_MAX;
268
269 sp->_unget._stack = calloc(
270 (size_t) sp->_unget._size, sizeof *sp->_unget._stack
271 );
272 if (sp->_unget._stack == (void *) 0)
273 goto error2;
274
275 if ((wio = (t_wide_io *) calloc(1, sizeof *wio)) == (t_wide_io *) 0)
276 goto error2;
277
278 /* Setup wide input for XCurses. */
279 wio->get = (int (*)(void *)) wgetch;
280 wio->unget = __xc_ungetc;
281 wio->reset = __xc_clearerr;
282 wio->iserror = __xc_ferror;
283 wio->iseof = __xc_feof;
284 sp->_in = wio;
285
286 if (assume_one_line) {
287 /* Assume only one line. */
288 lines = 1;
289
290 /* Disable capabilities that assume more than one line. */
291 clear_screen =
292 clr_eos =
293 cursor_up =
294 cursor_down =
295 cursor_home =
296 cursor_to_ll =
297 cursor_address =
298 row_address =
299 parm_up_cursor =
300 parm_down_cursor = (char *) 0;
301
302 /* Re-evaluate the cursor motion costs. */
303 __m_mvcur_cost();
304
305 /* Reset flag for subsequent calls to newterm(). */
306 assume_one_line = FALSE;
307 }
308
309 if ((sp->_curscr = newwin(lines, columns, 0, 0)) == (WINDOW *) 0)
310 goto error2;
311
312 if ((sp->_newscr = newwin(lines, columns, 0, 0)) == (WINDOW *) 0)
313 goto error2;
314
315 sp->_hash = (unsigned long *) calloc(lines, sizeof *sp->_hash);
316 if (sp->_hash == (unsigned long *) 0)
317 goto error2;
318
319 if (0 <= __m_slk_format && __m_slk_init(sp, __m_slk_format) == ERR)
320 goto error2;
321
322 /* doupdate() will perform the final screen preparations like
323 * enter_ca_mode, reset_prog_mode() (to assert the termios
324 * changes), etc.
325 */
326 sp->_flags |= S_ENDWIN;
327
328 #ifdef SIGTSTP
329 (void) signal(SIGTSTP, tstp);
330 #endif
331 /* Assert that __m_screen is set to the new terminal. */
332 osp = set_term(sp);
333
334 /* Disable echo in tty driver, Curses does software echo. */
335 cur_term->_prog.c_lflag &= ~ECHO;
336
337 /* Enable mappnig of cr -> nl on input and nl -> crlf on output. */
338 cur_term->_prog.c_iflag |= ICRNL;
339 cur_term->_prog.c_oflag |= OPOST;
340 #ifdef ONLCR
341 cur_term->_prog.c_oflag |= ONLCR;
342 #endif
343 cur_term->_flags |= __TERM_NL_IS_CRLF;
344
345 #ifdef TAB0
346 /* Use real tabs. */
347 cur_term->_prog.c_oflag &= ~(TAB1|TAB2|TAB3);
348 #endif
349
350 (void) __m_tty_set(&cur_term->_prog);
351 (void) __m_set_echo(1);
352 (void) typeahead(fileno(in_fp));
353
354 if (stdscr == (WINDOW *) 0) {
355 n = rip.top - rip.bottom;
356 stdscr = newwin(lines - n, 0, rip.top, 0);
357 if (stdscr == (WINDOW *) 0)
358 goto error3;
359
360 /* Create and initialise ripped off line windows.
361 * It is the application's responsiblity to free the
362 * windows when the application terminates.
363 */
364 for (i = 0; i < n; ++i) {
365 y = rip.line[i].dy;
366 if (y < 0)
367 y += lines;
368
369 w = newwin(1, 0, y, 0);
370 if (rip.line[i].init != (int (*)(WINDOW *, int)) 0)
371 (void) (*rip.line[i].init)(w, columns);
372 }
373 }
374
375 return __m_return_pointer("newterm", sp);
376 error3:
377 (void) set_term(osp);
378 error2:
379 delscreen(sp);
380 error1:
381 return __m_return_pointer("newterm", (SCREEN *) 0);
382 }
383
384 /*f
385 * Free storage associated with a screen structure.
386 * NOTE endwin() does not do this.
387 */
388 void
delscreen(sp)389 delscreen(sp)
390 SCREEN *sp;
391 {
392 #ifdef M_CURSES_TRACE
393 __m_trace("delscreen(%p)", sp);
394 #endif
395
396 if (sp != (SCREEN *) 0) {
397 if (sp->_slk._w != (WINDOW *) 0)
398 (void) delwin(sp->_slk._w);
399
400 (void) delwin(sp->_newscr);
401 (void) delwin(sp->_curscr);
402 (void) del_curterm(sp->_term);
403
404 __m_decode_free((t_decode **) &sp->_decode);
405
406 if (sp->_hash != (unsigned long *) 0)
407 free(sp->_hash);
408
409 if (sp->_unget._stack != (int *) 0)
410 free(sp->_unget._stack);
411
412 if (sp->_in != (void *) 0)
413 free(sp->_in);
414
415 free(sp);
416 }
417
418 __m_return_void("delscreen");
419 }
420
421 /*f
422 * Switch current terminal for Curses layer.
423 */
424 SCREEN *
set_term(screen)425 set_term(screen)
426 SCREEN *screen;
427 {
428 SCREEN *osp = __m_screen;
429
430 #ifdef M_CURSES_TRACE
431 __m_trace("set_term(%p)", screen);
432 #endif
433 if (screen != (SCREEN *) 0) {
434 (void) set_curterm(screen->_term);
435 curscr = screen->_curscr;
436 __m_screen = screen;
437
438 LINES = lines;
439 COLS = columns;
440 COLORS = max_colors;
441 COLOR_PAIRS = max_pairs;
442 }
443
444 return __m_return_pointer("set_term", osp);
445 }
446
447 int
typeahead(fd)448 typeahead(fd)
449 int fd;
450 {
451 #ifdef M_CURSES_TRACE
452 __m_trace("typeahead(%d)", fd);
453 #endif
454
455 __m_screen->_kfd = fd;
456 __m_screen->_flags &= ~S_ISATTY;
457
458 if (fd != -1 && isatty(fd))
459 __m_screen->_flags |= S_ISATTY;
460
461 return __m_return_code("typeahead", OK);
462 }
463
464 int
__m_set_echo(bf)465 __m_set_echo(bf)
466 int bf;
467 {
468 int old;
469
470 old = (__m_screen->_flags & S_ECHO) == S_ECHO;
471
472 __m_screen->_flags &= ~S_ECHO;
473 if (bf)
474 __m_screen->_flags |= S_ECHO;
475
476 return old;
477 }
478
479