ncurses 6.1 - patch 20181215
[ncurses.git] / ncurses / base / lib_set_term.c
1 /****************************************************************************
2  * Copyright (c) 1998-2017,2018 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
31  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32  *     and: Thomas E. Dickey                        1996-on                 *
33  *     and: Juergen Pfeifer                         2009                    *
34  ****************************************************************************/
35
36 /*
37 **      lib_set_term.c
38 **
39 **      The routine set_term().
40 **
41 */
42
43 #include <curses.priv.h>
44 #include <tic.h>
45
46 #undef CUR
47 #define CUR SP_TERMTYPE
48
49 MODULE_ID("$Id: lib_set_term.c,v 1.168 2018/12/15 23:49:43 tom Exp $")
50
51 #ifdef USE_TERM_DRIVER
52 #define MaxColors      InfoOf(sp).maxcolors
53 #define NumLabels      InfoOf(sp).numlabels
54 #else
55 #define MaxColors      max_colors
56 #define NumLabels      num_labels
57 #endif
58
59 NCURSES_EXPORT(SCREEN *)
60 set_term(SCREEN *screenp)
61 {
62     SCREEN *oldSP;
63     SCREEN *newSP;
64
65     T((T_CALLED("set_term(%p)"), (void *) screenp));
66
67     _nc_lock_global(curses);
68
69     oldSP = CURRENT_SCREEN;
70     _nc_set_screen(screenp);
71     newSP = screenp;
72
73     if (newSP != 0) {
74         TINFO_SET_CURTERM(newSP, newSP->_term);
75 #if !USE_REENTRANT
76         curscr = CurScreen(newSP);
77         newscr = NewScreen(newSP);
78         stdscr = StdScreen(newSP);
79         COLORS = newSP->_color_count;
80         COLOR_PAIRS = newSP->_pair_count;
81 #endif
82     } else {
83         TINFO_SET_CURTERM(oldSP, 0);
84 #if !USE_REENTRANT
85         curscr = 0;
86         newscr = 0;
87         stdscr = 0;
88         COLORS = 0;
89         COLOR_PAIRS = 0;
90 #endif
91     }
92
93     _nc_unlock_global(curses);
94
95     T((T_RETURN("%p"), (void *) oldSP));
96     return (oldSP);
97 }
98
99 static void
100 _nc_free_keytry(TRIES * kt)
101 {
102     if (kt != 0) {
103         _nc_free_keytry(kt->child);
104         _nc_free_keytry(kt->sibling);
105         free(kt);
106     }
107 }
108
109 static bool
110 delink_screen(SCREEN *sp)
111 {
112     SCREEN *last = 0;
113     SCREEN *temp;
114     bool result = FALSE;
115
116     for (each_screen(temp)) {
117         if (temp == sp) {
118             if (last)
119                 last->_next_screen = sp->_next_screen;
120             else
121                 _nc_screen_chain = sp->_next_screen;
122             result = TRUE;
123             break;
124         }
125         last = temp;
126     }
127     return result;
128 }
129
130 /*
131  * Free the storage associated with the given SCREEN sp.
132  */
133 NCURSES_EXPORT(void)
134 delscreen(SCREEN *sp)
135 {
136
137     T((T_CALLED("delscreen(%p)"), (void *) sp));
138
139     _nc_lock_global(curses);
140     if (delink_screen(sp)) {
141 #ifdef USE_SP_RIPOFF
142         ripoff_t *rop;
143         if (safe_ripoff_sp && safe_ripoff_sp != safe_ripoff_stack) {
144             for (rop = safe_ripoff_stack;
145                  rop != safe_ripoff_sp && (rop - safe_ripoff_stack) < N_RIPS;
146                  rop++) {
147                 if (rop->win) {
148                     (void) delwin(rop->win);
149                     rop->win = 0;
150                 }
151             }
152         }
153 #endif
154
155         (void) _nc_freewin(CurScreen(sp));
156         (void) _nc_freewin(NewScreen(sp));
157         (void) _nc_freewin(StdScreen(sp));
158
159         if (sp->_slk != 0) {
160
161             if (sp->_slk->ent != 0) {
162                 int i;
163
164                 for (i = 0; i < sp->_slk->labcnt; ++i) {
165                     FreeIfNeeded(sp->_slk->ent[i].ent_text);
166                     FreeIfNeeded(sp->_slk->ent[i].form_text);
167                 }
168                 free(sp->_slk->ent);
169             }
170             free(sp->_slk);
171             sp->_slk = 0;
172         }
173
174         _nc_free_keytry(sp->_keytry);
175         sp->_keytry = 0;
176
177         _nc_free_keytry(sp->_key_ok);
178         sp->_key_ok = 0;
179
180         FreeIfNeeded(sp->_current_attr);
181
182         FreeIfNeeded(sp->_color_table);
183         FreeIfNeeded(sp->_color_pairs);
184
185         FreeIfNeeded(sp->_oldnum_list);
186         FreeIfNeeded(sp->oldhash);
187         FreeIfNeeded(sp->newhash);
188         FreeIfNeeded(sp->hashtab);
189
190         FreeIfNeeded(sp->_acs_map);
191         FreeIfNeeded(sp->_screen_acs_map);
192
193         NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
194         NCURSES_SP_NAME(del_curterm) (NCURSES_SP_ARGx sp->_term);
195         FreeIfNeeded(sp->out_buffer);
196         if (_nc_find_prescr() == sp) {
197             _nc_forget_prescr();
198         }
199         free(sp);
200
201         /*
202          * If this was the current screen, reset everything that the
203          * application might try to use (except cur_term, which may have
204          * multiple references in different screens).
205          */
206         if (sp == CURRENT_SCREEN) {
207 #if !USE_REENTRANT
208             curscr = 0;
209             newscr = 0;
210             stdscr = 0;
211             COLORS = 0;
212             COLOR_PAIRS = 0;
213 #endif
214             _nc_set_screen(0);
215 #if USE_WIDEC_SUPPORT
216             if (SP == 0) {
217                 FreeIfNeeded(_nc_wacs);
218                 _nc_wacs = 0;
219             }
220 #endif
221         }
222     }
223     _nc_unlock_global(curses);
224
225     returnVoid;
226 }
227
228 static bool
229 no_mouse_event(SCREEN *sp GCC_UNUSED)
230 {
231     return FALSE;
232 }
233
234 static bool
235 no_mouse_inline(SCREEN *sp GCC_UNUSED)
236 {
237     return FALSE;
238 }
239
240 static bool
241 no_mouse_parse(SCREEN *sp GCC_UNUSED, int code GCC_UNUSED)
242 {
243     return TRUE;
244 }
245
246 static void
247 no_mouse_resume(SCREEN *sp GCC_UNUSED)
248 {
249 }
250
251 static void
252 no_mouse_wrap(SCREEN *sp GCC_UNUSED)
253 {
254 }
255
256 #if NCURSES_EXT_FUNCS && USE_COLORFGBG
257 static const char *
258 extract_fgbg(const char *src, int *result)
259 {
260     const char *dst = 0;
261     char *tmp = 0;
262     long value = strtol(src, &tmp, 0);
263
264     if ((dst = tmp) == 0) {
265         dst = src;
266     } else if (value >= 0) {
267         *result = (int) value;
268     }
269     while (*dst != 0 && *dst != ';')
270         dst++;
271     if (*dst == ';')
272         dst++;
273     return dst;
274 }
275 #endif
276
277 #define ReturnScreenError() do { _nc_set_screen(0); \
278                             returnCode(ERR); } while (0)
279
280 /* OS-independent screen initializations */
281 NCURSES_EXPORT(int)
282 NCURSES_SP_NAME(_nc_setupscreen) (
283 #if NCURSES_SP_FUNCS
284                                      SCREEN **spp,
285 #endif
286                                      int slines,
287                                      int scolumns,
288                                      FILE *output,
289                                      int filtered,
290                                      int slk_format)
291 {
292 #ifndef USE_TERM_DRIVER
293     static const TTY null_TTY;  /* all zeros iff uninitialized */
294 #endif
295     char *env;
296     int bottom_stolen = 0;
297     SCREEN *sp;
298 #ifndef USE_TERM_DRIVER
299     bool support_cookies = USE_XMC_SUPPORT;
300 #endif
301
302     T((T_CALLED("_nc_setupscreen(%d, %d, %p, %d, %d)"),
303        slines, scolumns, (void *) output, filtered, slk_format));
304
305     assert(CURRENT_SCREEN == 0);        /* has been reset in newterm() ! */
306
307 #if NCURSES_SP_FUNCS
308     assert(spp != 0);
309     sp = *spp;
310
311     if (!sp) {
312         sp = _nc_alloc_screen_sp();
313         T(("_nc_alloc_screen_sp %p", (void *) sp));
314         *spp = sp;
315     }
316     if (!sp
317         || ((sp->_acs_map = typeCalloc(chtype, ACS_LEN)) == 0)
318         || ((sp->_screen_acs_map = typeCalloc(bool, ACS_LEN)) == 0)) {
319         ReturnScreenError();
320     }
321
322     T(("created SP %p", (void *) sp));
323     sp->_next_screen = _nc_screen_chain;
324     _nc_screen_chain = sp;
325
326     if ((sp->_current_attr = typeCalloc(NCURSES_CH_T, 1)) == 0) {
327         ReturnScreenError();
328     }
329 #else
330     if (!_nc_alloc_screen()
331         || ((SP->_acs_map = typeCalloc(chtype, ACS_LEN)) == 0)
332         || ((SP->_screen_acs_map = typeCalloc(bool, ACS_LEN)) == 0)) {
333         returnCode(ERR);
334     }
335
336     T(("created SP %p", (void *) SP));
337
338     sp = SP;                    /* fixup so SET_LINES and SET_COLS works */
339     sp->_next_screen = _nc_screen_chain;
340     _nc_screen_chain = sp;
341
342     if ((sp->_current_attr = typeCalloc(NCURSES_CH_T, 1)) == 0)
343         returnCode(ERR);
344 #endif
345
346     /*
347      * We should always check the screensize, just in case.
348      */
349     _nc_set_screen(sp);
350     sp->_term = cur_term;
351 #ifdef USE_TERM_DRIVER
352     TCBOf(sp)->csp = sp;
353     _nc_get_screensize(sp, sp->_term, &slines, &scolumns);
354 #else
355     _nc_get_screensize(sp, &slines, &scolumns);
356 #endif
357     SET_LINES(slines);
358     SET_COLS(scolumns);
359
360     T((T_CREATE("screen %s %dx%d"),
361        NCURSES_SP_NAME(termname) (NCURSES_SP_ARG), slines, scolumns));
362
363     sp->_filtered = filtered;
364
365     /* implement filter mode */
366     if (filtered) {
367         slines = 1;
368         SET_LINES(slines);
369 #ifdef USE_TERM_DRIVER
370         CallDriver(sp, td_setfilter);
371 #else
372         /* *INDENT-EQLS* */
373         clear_screen     = ABSENT_STRING;
374         cursor_address   = ABSENT_STRING;
375         cursor_down      = ABSENT_STRING;
376         cursor_up        = ABSENT_STRING;
377         parm_down_cursor = ABSENT_STRING;
378         parm_up_cursor   = ABSENT_STRING;
379         row_address      = ABSENT_STRING;
380         cursor_home      = carriage_return;
381
382         if (back_color_erase)
383             clr_eos = ABSENT_STRING;
384
385 #endif
386         T(("filter screensize %dx%d", slines, scolumns));
387     }
388 #ifdef __DJGPP__
389     T(("setting output mode to binary"));
390     fflush(output);
391     setmode(output, O_BINARY);
392 #endif
393     NCURSES_SP_NAME(_nc_set_buffer) (NCURSES_SP_ARGx output, TRUE);
394     sp->_lines = (NCURSES_SIZE_T) slines;
395     sp->_lines_avail = (NCURSES_SIZE_T) slines;
396     sp->_columns = (NCURSES_SIZE_T) scolumns;
397
398     fflush(output);
399     sp->_ofd = output ? fileno(output) : -1;
400     sp->_ofp = output;
401     sp->out_limit = (size_t) ((2 + slines) * (6 + scolumns));
402     if ((sp->out_buffer = malloc(sp->out_limit)) == 0)
403         sp->out_limit = 0;
404     sp->out_inuse = 0;
405
406     SP_PRE_INIT(sp);
407     SetNoPadding(sp);
408
409 #if NCURSES_EXT_FUNCS
410     sp->_default_color = FALSE;
411     sp->_has_sgr_39_49 = FALSE;
412
413     /*
414      * Set our assumption of the terminal's default foreground and background
415      * colors.  The curs_color man-page states that we can assume that the
416      * background is black.  The origin of this assumption appears to be
417      * terminals that displayed colored text, but no colored backgrounds, e.g.,
418      * the first colored terminals around 1980.  More recent ones with better
419      * technology can display not only colored backgrounds, but all
420      * combinations.  So a terminal might be something other than "white" on
421      * black (green/black looks monochrome too), but black on white or even
422      * on ivory.
423      *
424      * White-on-black is the simplest thing to use for monochrome.  Almost
425      * all applications that use color paint both text and background, so
426      * the distinction is moot.  But a few do not - which is why we leave this
427      * configurable (a better solution is to use assume_default_colors() for
428      * the rare applications that do require that sort of appearance, since
429      * is appears that more users expect to be able to make a white-on-black
430      * or black-on-white display under control of the application than not).
431      */
432 #ifdef USE_ASSUMED_COLOR
433     sp->_default_fg = COLOR_WHITE;
434     sp->_default_bg = COLOR_BLACK;
435 #else
436     sp->_default_fg = COLOR_DEFAULT;
437     sp->_default_bg = COLOR_DEFAULT;
438 #endif
439
440     /*
441      * Allow those assumed/default color assumptions to be overridden at
442      * runtime:
443      */
444     if ((env = getenv("NCURSES_ASSUMED_COLORS")) != 0) {
445         int fg, bg;
446         char sep1, sep2;
447         int count = sscanf(env, "%d%c%d%c", &fg, &sep1, &bg, &sep2);
448         if (count >= 1) {
449             sp->_default_fg = ((fg >= 0 && fg < MaxColors) ? fg : COLOR_DEFAULT);
450             if (count >= 3) {
451                 sp->_default_bg = ((bg >= 0 && bg < MaxColors) ? bg : COLOR_DEFAULT);
452             }
453             TR(TRACE_CHARPUT | TRACE_MOVE,
454                ("from environment assumed fg=%d, bg=%d",
455                 sp->_default_fg,
456                 sp->_default_bg));
457         }
458     }
459 #if USE_COLORFGBG
460     /*
461      * If rxvt's $COLORFGBG variable is set, use it to specify the assumed
462      * default colors.  Note that rxvt (mis)uses bold colors, equating a bold
463      * color to that value plus 8.  We'll only use the non-bold color for now -
464      * decide later if it is worth having default attributes as well.
465      */
466     if (getenv("COLORFGBG") != 0) {
467         const char *p = getenv("COLORFGBG");
468         TR(TRACE_CHARPUT | TRACE_MOVE, ("decoding COLORFGBG %s", p));
469         p = extract_fgbg(p, &(sp->_default_fg));
470         p = extract_fgbg(p, &(sp->_default_bg));
471         if (*p)                 /* assume rxvt was compiled with xpm support */
472             p = extract_fgbg(p, &(sp->_default_bg));
473         TR(TRACE_CHARPUT | TRACE_MOVE, ("decoded fg=%d, bg=%d",
474                                         sp->_default_fg, sp->_default_bg));
475         if (sp->_default_fg >= MaxColors) {
476             if (set_a_foreground != ABSENT_STRING
477                 && !strcmp(set_a_foreground, "\033[3%p1%dm")) {
478                 set_a_foreground = strdup("\033[3%?%p1%{8}%>%t9%e%p1%d%;m");
479             } else {
480                 sp->_default_fg %= MaxColors;
481             }
482         }
483         if (sp->_default_bg >= MaxColors) {
484             if (set_a_background != ABSENT_STRING
485                 && !strcmp(set_a_background, "\033[4%p1%dm")) {
486                 set_a_background = strdup("\033[4%?%p1%{8}%>%t9%e%p1%d%;m");
487             } else {
488                 sp->_default_bg %= MaxColors;
489             }
490         }
491     }
492 #endif
493 #endif /* NCURSES_EXT_FUNCS */
494
495     sp->_maxclick = DEFAULT_MAXCLICK;
496     sp->_mouse_event = no_mouse_event;
497     sp->_mouse_inline = no_mouse_inline;
498     sp->_mouse_parse = no_mouse_parse;
499     sp->_mouse_resume = no_mouse_resume;
500     sp->_mouse_wrap = no_mouse_wrap;
501     sp->_mouse_fd = -1;
502
503     /*
504      * If we've no magic cookie support, we suppress attributes that xmc would
505      * affect, i.e., the attributes that affect the rendition of a space.
506      */
507     sp->_ok_attributes = NCURSES_SP_NAME(termattrs) (NCURSES_SP_ARG);
508     if (NCURSES_SP_NAME(has_colors) (NCURSES_SP_ARG)) {
509         sp->_ok_attributes |= A_COLOR;
510     }
511 #ifdef USE_TERM_DRIVER
512     _nc_cookie_init(sp);
513 #else
514 #if USE_XMC_SUPPORT
515     /*
516      * If we have no magic-cookie support compiled-in, or if it is suppressed
517      * in the environment, reset the support-flag.
518      */
519     if (magic_cookie_glitch >= 0) {
520         if (getenv("NCURSES_NO_MAGIC_COOKIE") != 0) {
521             support_cookies = FALSE;
522         }
523     }
524 #endif
525
526     if (!support_cookies && magic_cookie_glitch >= 0) {
527         T(("will disable attributes to work w/o magic cookies"));
528     }
529
530     if (magic_cookie_glitch > 0) {      /* tvi, wyse */
531
532         sp->_xmc_triggers = sp->_ok_attributes & XMC_CONFLICT;
533 #if 0
534         /*
535          * We "should" treat colors as an attribute.  The wyse350 (and its
536          * clones) appear to be the only ones that have both colors and magic
537          * cookies.
538          */
539         if (has_colors()) {
540             sp->_xmc_triggers |= A_COLOR;
541         }
542 #endif
543         sp->_xmc_suppress = sp->_xmc_triggers & (chtype) ~(A_BOLD);
544
545         T(("magic cookie attributes %s", _traceattr(sp->_xmc_suppress)));
546         /*
547          * Supporting line-drawing may be possible.  But make the regular
548          * video attributes work first.
549          */
550         acs_chars = ABSENT_STRING;
551         ena_acs = ABSENT_STRING;
552         enter_alt_charset_mode = ABSENT_STRING;
553         exit_alt_charset_mode = ABSENT_STRING;
554 #if USE_XMC_SUPPORT
555         /*
556          * To keep the cookie support simple, suppress all of the optimization
557          * hooks except for clear_screen and the cursor addressing.
558          */
559         if (support_cookies) {
560             clr_eol = ABSENT_STRING;
561             clr_eos = ABSENT_STRING;
562             set_attributes = ABSENT_STRING;
563         }
564 #endif
565     } else if (magic_cookie_glitch == 0) {      /* hpterm */
566     }
567
568     /*
569      * If magic cookies are not supported, cancel the strings that set
570      * video attributes.
571      */
572     if (!support_cookies && magic_cookie_glitch >= 0) {
573         magic_cookie_glitch = ABSENT_NUMERIC;
574         set_attributes = ABSENT_STRING;
575         enter_blink_mode = ABSENT_STRING;
576         enter_bold_mode = ABSENT_STRING;
577         enter_dim_mode = ABSENT_STRING;
578         enter_reverse_mode = ABSENT_STRING;
579         enter_standout_mode = ABSENT_STRING;
580         enter_underline_mode = ABSENT_STRING;
581     }
582
583     /* initialize normal acs before wide, since we use mapping in the latter */
584 #if !USE_WIDEC_SUPPORT
585     if (_nc_unicode_locale() && _nc_locale_breaks_acs(sp->_term)) {
586         acs_chars = NULL;
587         ena_acs = NULL;
588         enter_alt_charset_mode = NULL;
589         exit_alt_charset_mode = NULL;
590         set_attributes = NULL;
591     }
592 #endif
593 #endif
594
595     NCURSES_SP_NAME(_nc_init_acs) (NCURSES_SP_ARG);
596 #if USE_WIDEC_SUPPORT
597     sp->_screen_unicode = _nc_unicode_locale();
598     if (_nc_wacs == 0) {
599         _nc_init_wacs();
600     }
601     if (_nc_wacs == 0) {
602         ReturnScreenError();
603     }
604
605     sp->_screen_acs_fix = (sp->_screen_unicode
606                            && _nc_locale_breaks_acs(sp->_term));
607 #endif
608     env = _nc_get_locale();
609     sp->_legacy_coding = ((env == 0)
610                           || !strcmp(env, "C")
611                           || !strcmp(env, "POSIX"));
612     T(("legacy-coding %d", sp->_legacy_coding));
613
614     sp->_nc_sp_idcok = TRUE;
615     sp->_nc_sp_idlok = FALSE;
616
617     sp->oldhash = 0;
618     sp->newhash = 0;
619
620     T(("creating newscr"));
621     NewScreen(sp) = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx slines, scolumns,
622                                              0, 0);
623     if (NewScreen(sp) == 0) {
624         ReturnScreenError();
625     }
626     T(("creating curscr"));
627     CurScreen(sp) = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx slines, scolumns,
628                                              0, 0);
629     if (CurScreen(sp) == 0) {
630         ReturnScreenError();
631     }
632 #if !USE_REENTRANT
633     newscr = NewScreen(sp);
634     curscr = CurScreen(sp);
635 #endif
636 #if USE_SIZECHANGE
637     sp->_resize = NCURSES_SP_NAME(resizeterm);
638     sp->_ungetch = safe_ungetch;
639 #endif
640
641     NewScreen(sp)->_clear = TRUE;
642     CurScreen(sp)->_clear = FALSE;
643
644     /*
645      * Get the current tty-modes. setupterm() may already have done this,
646      * unless we use the term-driver.
647      */
648 #ifndef USE_TERM_DRIVER
649     if (cur_term != 0 &&
650         !memcmp(&cur_term->Ottyb, &null_TTY, sizeof(TTY)))
651 #endif
652     {
653         NCURSES_SP_NAME(def_shell_mode) (NCURSES_SP_ARG);
654         NCURSES_SP_NAME(def_prog_mode) (NCURSES_SP_ARG);
655     }
656
657     if (safe_ripoff_sp && safe_ripoff_sp != safe_ripoff_stack) {
658         ripoff_t *rop;
659
660         for (rop = safe_ripoff_stack;
661              rop != safe_ripoff_sp && (rop - safe_ripoff_stack) < N_RIPS;
662              rop++) {
663
664             /* If we must simulate soft labels, grab off the line to be used.
665                We assume that we must simulate, if it is none of the standard
666                formats (4-4 or 3-2-3) for which there may be some hardware
667                support. */
668             if (rop->hook == _nc_slk_initialize) {
669                 if (!(NumLabels <= 0 || !SLK_STDFMT(slk_format))) {
670                     continue;
671                 }
672             }
673             if (rop->hook) {
674                 int count;
675                 WINDOW *w;
676
677                 count = (rop->line < 0) ? -rop->line : rop->line;
678                 T(("ripping off %i lines at %s", count,
679                    ((rop->line < 0)
680                     ? "bottom"
681                     : "top")));
682
683                 w = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
684                                              count, scolumns,
685                                              ((rop->line < 0)
686                                               ? sp->_lines_avail - count
687                                               : 0),
688                                              0);
689                 if (w) {
690                     rop->win = w;
691                     rop->hook(w, scolumns);
692                 } else {
693                     ReturnScreenError();
694                 }
695                 if (rop->line < 0) {
696                     bottom_stolen += count;
697                 } else {
698                     sp->_topstolen = (NCURSES_SIZE_T) (sp->_topstolen + count);
699                 }
700                 sp->_lines_avail = (NCURSES_SIZE_T) (sp->_lines_avail - count);
701             }
702         }
703         /* reset the stack */
704         safe_ripoff_sp = safe_ripoff_stack;
705     }
706
707     T(("creating stdscr"));
708     assert((sp->_lines_avail + sp->_topstolen + bottom_stolen) == slines);
709     if ((StdScreen(sp) = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
710                                                   sp->_lines_avail,
711                                                   scolumns, 0, 0)) == 0) {
712         ReturnScreenError();
713     }
714     SET_LINES(sp->_lines_avail);
715 #if !USE_REENTRANT
716     stdscr = StdScreen(sp);
717 #endif
718     sp->_prescreen = FALSE;
719     returnCode(OK);
720 }
721
722 #if NCURSES_SP_FUNCS
723 NCURSES_EXPORT(int)
724 _nc_setupscreen(int slines GCC_UNUSED,
725                 int scolumns GCC_UNUSED,
726                 FILE *output,
727                 int filtered,
728                 int slk_format)
729 {
730     SCREEN *sp = 0;
731     int rc = NCURSES_SP_NAME(_nc_setupscreen) (&sp,
732                                                slines,
733                                                scolumns,
734                                                output,
735                                                filtered,
736                                                slk_format);
737     if (rc != OK)
738         _nc_set_screen(0);
739     return rc;
740 }
741 #endif
742
743 /*
744  * The internal implementation interprets line as the number of lines to rip
745  * off from the top or bottom.
746  */
747 NCURSES_EXPORT(int)
748 NCURSES_SP_NAME(_nc_ripoffline) (NCURSES_SP_DCLx
749                                  int line,
750                                  int (*init) (WINDOW *, int))
751 {
752     int code = ERR;
753     TR_FUNC_BFR(1);
754
755     START_TRACE();
756     T((T_CALLED("ripoffline(%p,%d,%s)"),
757        (void *) SP_PARM, line,
758        TR_FUNC_ARG(0, init)));
759
760 #if NCURSES_SP_FUNCS
761     if (SP_PARM != 0 && SP_PARM->_prescreen)
762 #endif
763     {
764         if (line == 0) {
765             code = OK;
766         } else {
767             if (safe_ripoff_sp == 0) {
768                 safe_ripoff_sp = safe_ripoff_stack;
769             }
770             if (safe_ripoff_sp < safe_ripoff_stack + N_RIPS) {
771                 safe_ripoff_sp->line = line;
772                 safe_ripoff_sp->hook = init;
773                 (safe_ripoff_sp)++;
774                 T(("ripped-off %d:%d chunks",
775                    (int) (safe_ripoff_sp - safe_ripoff_stack), N_RIPS));
776                 code = OK;
777             }
778         }
779     }
780
781     returnCode(code);
782 }
783
784 #if NCURSES_SP_FUNCS
785 NCURSES_EXPORT(int)
786 _nc_ripoffline(int line, int (*init) (WINDOW *, int))
787 {
788     int rc;
789     _nc_lock_global(prescreen);
790     START_TRACE();
791     rc = NCURSES_SP_NAME(_nc_ripoffline) (CURRENT_SCREEN_PRE, line, init);
792     _nc_unlock_global(prescreen);
793     return rc;
794 }
795 #endif
796
797 NCURSES_EXPORT(int)
798 NCURSES_SP_NAME(ripoffline) (NCURSES_SP_DCLx
799                              int line,
800                              int (*init) (WINDOW *, int))
801 {
802     START_TRACE();
803     return NCURSES_SP_NAME(_nc_ripoffline) (NCURSES_SP_ARGx
804                                             (line < 0) ? -1 : 1,
805                                             init);
806 }
807
808 #if NCURSES_SP_FUNCS
809 NCURSES_EXPORT(int)
810 ripoffline(int line, int (*init) (WINDOW *, int))
811 {
812     int rc;
813     _nc_lock_global(prescreen);
814     START_TRACE();
815     rc = NCURSES_SP_NAME(ripoffline) (CURRENT_SCREEN_PRE, line, init);
816     _nc_unlock_global(prescreen);
817     return rc;
818 }
819 #endif