ncurses 6.0 - patch 20170415
[ncurses.git] / ncurses / base / lib_set_term.c
1 /****************************************************************************
2  * Copyright (c) 1998-2016,2017 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.162 2017/04/15 21:44:03 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->oldhash);
186         FreeIfNeeded(sp->newhash);
187         FreeIfNeeded(sp->hashtab);
188
189         FreeIfNeeded(sp->_acs_map);
190         FreeIfNeeded(sp->_screen_acs_map);
191
192         NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
193         NCURSES_SP_NAME(del_curterm) (NCURSES_SP_ARGx sp->_term);
194         FreeIfNeeded(sp->out_buffer);
195         if (_nc_prescreen.allocated == sp)
196             _nc_prescreen.allocated = 0;
197         free(sp);
198
199         /*
200          * If this was the current screen, reset everything that the
201          * application might try to use (except cur_term, which may have
202          * multiple references in different screens).
203          */
204         if (sp == CURRENT_SCREEN) {
205 #if !USE_REENTRANT
206             curscr = 0;
207             newscr = 0;
208             stdscr = 0;
209             COLORS = 0;
210             COLOR_PAIRS = 0;
211 #endif
212             _nc_set_screen(0);
213 #if USE_WIDEC_SUPPORT
214             if (SP == 0) {
215                 FreeIfNeeded(_nc_wacs);
216                 _nc_wacs = 0;
217             }
218 #endif
219         }
220     }
221     _nc_unlock_global(curses);
222
223     returnVoid;
224 }
225
226 static bool
227 no_mouse_event(SCREEN *sp GCC_UNUSED)
228 {
229     return FALSE;
230 }
231
232 static bool
233 no_mouse_inline(SCREEN *sp GCC_UNUSED)
234 {
235     return FALSE;
236 }
237
238 static bool
239 no_mouse_parse(SCREEN *sp GCC_UNUSED, int code GCC_UNUSED)
240 {
241     return TRUE;
242 }
243
244 static void
245 no_mouse_resume(SCREEN *sp GCC_UNUSED)
246 {
247 }
248
249 static void
250 no_mouse_wrap(SCREEN *sp GCC_UNUSED)
251 {
252 }
253
254 #if NCURSES_EXT_FUNCS && USE_COLORFGBG
255 static const char *
256 extract_fgbg(const char *src, int *result)
257 {
258     const char *dst = 0;
259     char *tmp = 0;
260     long value = strtol(src, &tmp, 0);
261
262     if ((dst = tmp) == 0) {
263         dst = src;
264     } else if (value >= 0) {
265         *result = (int) value;
266     }
267     while (*dst != 0 && *dst != ';')
268         dst++;
269     if (*dst == ';')
270         dst++;
271     return dst;
272 }
273 #endif
274
275 #define ReturnScreenError() do { _nc_set_screen(0); \
276                             returnCode(ERR); } while (0)
277
278 /* OS-independent screen initializations */
279 NCURSES_EXPORT(int)
280 NCURSES_SP_NAME(_nc_setupscreen) (
281 #if NCURSES_SP_FUNCS
282                                      SCREEN **spp,
283 #endif
284                                      int slines,
285                                      int scolumns,
286                                      FILE *output,
287                                      int filtered,
288                                      int slk_format)
289 {
290 #ifndef USE_TERM_DRIVER
291     static const TTY null_TTY;  /* all zeros iff uninitialized */
292 #endif
293     char *env;
294     int bottom_stolen = 0;
295     SCREEN *sp;
296 #ifndef USE_TERM_DRIVER
297     bool support_cookies = USE_XMC_SUPPORT;
298 #endif
299
300     T((T_CALLED("_nc_setupscreen(%d, %d, %p, %d, %d)"),
301        slines, scolumns, (void *) output, filtered, slk_format));
302
303     assert(CURRENT_SCREEN == 0);        /* has been reset in newterm() ! */
304
305 #if NCURSES_SP_FUNCS
306     assert(spp != 0);
307     sp = *spp;
308
309     if (!sp) {
310         sp = _nc_alloc_screen_sp();
311         T(("_nc_alloc_screen_sp %p", (void *) sp));
312         *spp = sp;
313     }
314     if (!sp
315         || ((sp->_acs_map = typeCalloc(chtype, ACS_LEN)) == 0)
316         || ((sp->_screen_acs_map = typeCalloc(bool, ACS_LEN)) == 0)) {
317         ReturnScreenError();
318     }
319
320     T(("created SP %p", (void *) sp));
321     sp->_next_screen = _nc_screen_chain;
322     _nc_screen_chain = sp;
323
324     if ((sp->_current_attr = typeCalloc(NCURSES_CH_T, 1)) == 0) {
325         ReturnScreenError();
326     }
327 #else
328     if (!_nc_alloc_screen()
329         || ((SP->_acs_map = typeCalloc(chtype, ACS_LEN)) == 0)
330         || ((SP->_screen_acs_map = typeCalloc(bool, ACS_LEN)) == 0)) {
331         returnCode(ERR);
332     }
333
334     T(("created SP %p", (void *) SP));
335
336     sp = SP;                    /* fixup so SET_LINES and SET_COLS works */
337     sp->_next_screen = _nc_screen_chain;
338     _nc_screen_chain = sp;
339
340     if ((sp->_current_attr = typeCalloc(NCURSES_CH_T, 1)) == 0)
341         returnCode(ERR);
342 #endif
343
344     /*
345      * We should always check the screensize, just in case.
346      */
347     _nc_set_screen(sp);
348     sp->_term = cur_term;
349 #ifdef USE_TERM_DRIVER
350     TCBOf(sp)->csp = sp;
351     _nc_get_screensize(sp, sp->_term, &slines, &scolumns);
352 #else
353     _nc_get_screensize(sp, &slines, &scolumns);
354 #endif
355     SET_LINES(slines);
356     SET_COLS(scolumns);
357
358     T((T_CREATE("screen %s %dx%d"),
359        NCURSES_SP_NAME(termname) (NCURSES_SP_ARG), slines, scolumns));
360
361     sp->_filtered = filtered;
362
363     /* implement filter mode */
364     if (filtered) {
365         slines = 1;
366         SET_LINES(slines);
367 #ifdef USE_TERM_DRIVER
368         CallDriver(sp, td_setfilter);
369 #else
370         clear_screen = 0;
371         cursor_down = parm_down_cursor = 0;
372         cursor_address = 0;
373         cursor_up = parm_up_cursor = 0;
374         row_address = 0;
375
376         cursor_home = carriage_return;
377 #endif
378         T(("filter screensize %dx%d", slines, scolumns));
379     }
380 #ifdef __DJGPP__
381     T(("setting output mode to binary"));
382     fflush(output);
383     setmode(output, O_BINARY);
384 #endif
385     NCURSES_SP_NAME(_nc_set_buffer) (NCURSES_SP_ARGx output, TRUE);
386     sp->_lines = (NCURSES_SIZE_T) slines;
387     sp->_lines_avail = (NCURSES_SIZE_T) slines;
388     sp->_columns = (NCURSES_SIZE_T) scolumns;
389
390     fflush(output);
391     sp->_ofd = output ? fileno(output) : -1;
392     sp->_ofp = output;
393     sp->out_limit = (size_t) ((2 + slines) * (6 + scolumns));
394     if ((sp->out_buffer = malloc(sp->out_limit)) == 0)
395         sp->out_limit = 0;
396     sp->out_inuse = 0;
397
398     SP_PRE_INIT(sp);
399     SetNoPadding(sp);
400
401 #if NCURSES_EXT_FUNCS
402     sp->_default_color = FALSE;
403     sp->_has_sgr_39_49 = FALSE;
404
405     /*
406      * Set our assumption of the terminal's default foreground and background
407      * colors.  The curs_color man-page states that we can assume that the
408      * background is black.  The origin of this assumption appears to be
409      * terminals that displayed colored text, but no colored backgrounds, e.g.,
410      * the first colored terminals around 1980.  More recent ones with better
411      * technology can display not only colored backgrounds, but all
412      * combinations.  So a terminal might be something other than "white" on
413      * black (green/black looks monochrome too), but black on white or even
414      * on ivory.
415      *
416      * White-on-black is the simplest thing to use for monochrome.  Almost
417      * all applications that use color paint both text and background, so
418      * the distinction is moot.  But a few do not - which is why we leave this
419      * configurable (a better solution is to use assume_default_colors() for
420      * the rare applications that do require that sort of appearance, since
421      * is appears that more users expect to be able to make a white-on-black
422      * or black-on-white display under control of the application than not).
423      */
424 #ifdef USE_ASSUMED_COLOR
425     sp->_default_fg = COLOR_WHITE;
426     sp->_default_bg = COLOR_BLACK;
427 #else
428     sp->_default_fg = COLOR_DEFAULT;
429     sp->_default_bg = COLOR_DEFAULT;
430 #endif
431
432     /*
433      * Allow those assumed/default color assumptions to be overridden at
434      * runtime:
435      */
436     if ((env = getenv("NCURSES_ASSUMED_COLORS")) != 0) {
437         int fg, bg;
438         char sep1, sep2;
439         int count = sscanf(env, "%d%c%d%c", &fg, &sep1, &bg, &sep2);
440         if (count >= 1) {
441             sp->_default_fg = ((fg >= 0 && fg < MaxColors) ? fg : COLOR_DEFAULT);
442             if (count >= 3) {
443                 sp->_default_bg = ((bg >= 0 && bg < MaxColors) ? bg : COLOR_DEFAULT);
444             }
445             TR(TRACE_CHARPUT | TRACE_MOVE,
446                ("from environment assumed fg=%d, bg=%d",
447                 sp->_default_fg,
448                 sp->_default_bg));
449         }
450     }
451 #if USE_COLORFGBG
452     /*
453      * If rxvt's $COLORFGBG variable is set, use it to specify the assumed
454      * default colors.  Note that rxvt (mis)uses bold colors, equating a bold
455      * color to that value plus 8.  We'll only use the non-bold color for now -
456      * decide later if it is worth having default attributes as well.
457      */
458     if (getenv("COLORFGBG") != 0) {
459         const char *p = getenv("COLORFGBG");
460         TR(TRACE_CHARPUT | TRACE_MOVE, ("decoding COLORFGBG %s", p));
461         p = extract_fgbg(p, &(sp->_default_fg));
462         p = extract_fgbg(p, &(sp->_default_bg));
463         if (*p)                 /* assume rxvt was compiled with xpm support */
464             p = extract_fgbg(p, &(sp->_default_bg));
465         TR(TRACE_CHARPUT | TRACE_MOVE, ("decoded fg=%d, bg=%d",
466                                         sp->_default_fg, sp->_default_bg));
467         if (sp->_default_fg >= MaxColors) {
468             if (set_a_foreground != ABSENT_STRING
469                 && !strcmp(set_a_foreground, "\033[3%p1%dm")) {
470                 set_a_foreground = strdup("\033[3%?%p1%{8}%>%t9%e%p1%d%;m");
471             } else {
472                 sp->_default_fg %= MaxColors;
473             }
474         }
475         if (sp->_default_bg >= MaxColors) {
476             if (set_a_background != ABSENT_STRING
477                 && !strcmp(set_a_background, "\033[4%p1%dm")) {
478                 set_a_background = strdup("\033[4%?%p1%{8}%>%t9%e%p1%d%;m");
479             } else {
480                 sp->_default_bg %= MaxColors;
481             }
482         }
483     }
484 #endif
485 #endif /* NCURSES_EXT_FUNCS */
486
487     sp->_maxclick = DEFAULT_MAXCLICK;
488     sp->_mouse_event = no_mouse_event;
489     sp->_mouse_inline = no_mouse_inline;
490     sp->_mouse_parse = no_mouse_parse;
491     sp->_mouse_resume = no_mouse_resume;
492     sp->_mouse_wrap = no_mouse_wrap;
493     sp->_mouse_fd = -1;
494
495     /*
496      * If we've no magic cookie support, we suppress attributes that xmc would
497      * affect, i.e., the attributes that affect the rendition of a space.
498      */
499     sp->_ok_attributes = NCURSES_SP_NAME(termattrs) (NCURSES_SP_ARG);
500     if (NCURSES_SP_NAME(has_colors) (NCURSES_SP_ARG)) {
501         sp->_ok_attributes |= A_COLOR;
502     }
503 #ifdef USE_TERM_DRIVER
504     _nc_cookie_init(sp);
505 #else
506 #if USE_XMC_SUPPORT
507     /*
508      * If we have no magic-cookie support compiled-in, or if it is suppressed
509      * in the environment, reset the support-flag.
510      */
511     if (magic_cookie_glitch >= 0) {
512         if (getenv("NCURSES_NO_MAGIC_COOKIE") != 0) {
513             support_cookies = FALSE;
514         }
515     }
516 #endif
517
518     if (!support_cookies && magic_cookie_glitch >= 0) {
519         T(("will disable attributes to work w/o magic cookies"));
520     }
521
522     if (magic_cookie_glitch > 0) {      /* tvi, wyse */
523
524         sp->_xmc_triggers = sp->_ok_attributes & XMC_CONFLICT;
525 #if 0
526         /*
527          * We "should" treat colors as an attribute.  The wyse350 (and its
528          * clones) appear to be the only ones that have both colors and magic
529          * cookies.
530          */
531         if (has_colors()) {
532             sp->_xmc_triggers |= A_COLOR;
533         }
534 #endif
535         sp->_xmc_suppress = sp->_xmc_triggers & (chtype) ~(A_BOLD);
536
537         T(("magic cookie attributes %s", _traceattr(sp->_xmc_suppress)));
538         /*
539          * Supporting line-drawing may be possible.  But make the regular
540          * video attributes work first.
541          */
542         acs_chars = ABSENT_STRING;
543         ena_acs = ABSENT_STRING;
544         enter_alt_charset_mode = ABSENT_STRING;
545         exit_alt_charset_mode = ABSENT_STRING;
546 #if USE_XMC_SUPPORT
547         /*
548          * To keep the cookie support simple, suppress all of the optimization
549          * hooks except for clear_screen and the cursor addressing.
550          */
551         if (support_cookies) {
552             clr_eol = ABSENT_STRING;
553             clr_eos = ABSENT_STRING;
554             set_attributes = ABSENT_STRING;
555         }
556 #endif
557     } else if (magic_cookie_glitch == 0) {      /* hpterm */
558     }
559
560     /*
561      * If magic cookies are not supported, cancel the strings that set
562      * video attributes.
563      */
564     if (!support_cookies && magic_cookie_glitch >= 0) {
565         magic_cookie_glitch = ABSENT_NUMERIC;
566         set_attributes = ABSENT_STRING;
567         enter_blink_mode = ABSENT_STRING;
568         enter_bold_mode = ABSENT_STRING;
569         enter_dim_mode = ABSENT_STRING;
570         enter_reverse_mode = ABSENT_STRING;
571         enter_standout_mode = ABSENT_STRING;
572         enter_underline_mode = ABSENT_STRING;
573     }
574
575     /* initialize normal acs before wide, since we use mapping in the latter */
576 #if !USE_WIDEC_SUPPORT
577     if (_nc_unicode_locale() && _nc_locale_breaks_acs(sp->_term)) {
578         acs_chars = NULL;
579         ena_acs = NULL;
580         enter_alt_charset_mode = NULL;
581         exit_alt_charset_mode = NULL;
582         set_attributes = NULL;
583     }
584 #endif
585 #endif
586
587     NCURSES_SP_NAME(_nc_init_acs) (NCURSES_SP_ARG);
588 #if USE_WIDEC_SUPPORT
589     sp->_screen_unicode = _nc_unicode_locale();
590     if (_nc_wacs == 0) {
591         _nc_init_wacs();
592     }
593     if (_nc_wacs == 0) {
594         ReturnScreenError();
595     }
596
597     sp->_screen_acs_fix = (sp->_screen_unicode
598                            && _nc_locale_breaks_acs(sp->_term));
599 #endif
600     env = _nc_get_locale();
601     sp->_legacy_coding = ((env == 0)
602                           || !strcmp(env, "C")
603                           || !strcmp(env, "POSIX"));
604     T(("legacy-coding %d", sp->_legacy_coding));
605
606     sp->_nc_sp_idcok = TRUE;
607     sp->_nc_sp_idlok = FALSE;
608
609     sp->oldhash = 0;
610     sp->newhash = 0;
611
612     T(("creating newscr"));
613     NewScreen(sp) = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx slines, scolumns,
614                                              0, 0);
615     if (NewScreen(sp) == 0) {
616         ReturnScreenError();
617     }
618     T(("creating curscr"));
619     CurScreen(sp) = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx slines, scolumns,
620                                              0, 0);
621     if (CurScreen(sp) == 0) {
622         ReturnScreenError();
623     }
624 #if !USE_REENTRANT
625     newscr = NewScreen(sp);
626     curscr = CurScreen(sp);
627 #endif
628 #if USE_SIZECHANGE
629     sp->_resize = NCURSES_SP_NAME(resizeterm);
630     sp->_ungetch = safe_ungetch;
631 #endif
632
633     NewScreen(sp)->_clear = TRUE;
634     CurScreen(sp)->_clear = FALSE;
635
636     /*
637      * Get the current tty-modes. setupterm() may already have done this,
638      * unless we use the term-driver.
639      */
640 #ifndef USE_TERM_DRIVER
641     if (cur_term != 0 &&
642         !memcmp(&cur_term->Ottyb, &null_TTY, sizeof(TTY)))
643 #endif
644     {
645         NCURSES_SP_NAME(def_shell_mode) (NCURSES_SP_ARG);
646         NCURSES_SP_NAME(def_prog_mode) (NCURSES_SP_ARG);
647     }
648
649     if (safe_ripoff_sp && safe_ripoff_sp != safe_ripoff_stack) {
650         ripoff_t *rop;
651
652         for (rop = safe_ripoff_stack;
653              rop != safe_ripoff_sp && (rop - safe_ripoff_stack) < N_RIPS;
654              rop++) {
655
656             /* If we must simulate soft labels, grab off the line to be used.
657                We assume that we must simulate, if it is none of the standard
658                formats (4-4 or 3-2-3) for which there may be some hardware
659                support. */
660             if (rop->hook == _nc_slk_initialize) {
661                 if (!(NumLabels <= 0 || !SLK_STDFMT(slk_format))) {
662                     continue;
663                 }
664             }
665             if (rop->hook) {
666                 int count;
667                 WINDOW *w;
668
669                 count = (rop->line < 0) ? -rop->line : rop->line;
670                 T(("ripping off %i lines at %s", count,
671                    ((rop->line < 0)
672                     ? "bottom"
673                     : "top")));
674
675                 w = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
676                                              count, scolumns,
677                                              ((rop->line < 0)
678                                               ? sp->_lines_avail - count
679                                               : 0),
680                                              0);
681                 if (w) {
682                     rop->win = w;
683                     rop->hook(w, scolumns);
684                 } else {
685                     ReturnScreenError();
686                 }
687                 if (rop->line < 0) {
688                     bottom_stolen += count;
689                 } else {
690                     sp->_topstolen = (NCURSES_SIZE_T) (sp->_topstolen + count);
691                 }
692                 sp->_lines_avail = (NCURSES_SIZE_T) (sp->_lines_avail - count);
693             }
694         }
695         /* reset the stack */
696         safe_ripoff_sp = safe_ripoff_stack;
697     }
698
699     T(("creating stdscr"));
700     assert((sp->_lines_avail + sp->_topstolen + bottom_stolen) == slines);
701     if ((StdScreen(sp) = NCURSES_SP_NAME(newwin) (NCURSES_SP_ARGx
702                                                   sp->_lines_avail,
703                                                   scolumns, 0, 0)) == 0) {
704         ReturnScreenError();
705     }
706     SET_LINES(sp->_lines_avail);
707 #if !USE_REENTRANT
708     stdscr = StdScreen(sp);
709 #endif
710     sp->_prescreen = FALSE;
711     returnCode(OK);
712 }
713
714 #if NCURSES_SP_FUNCS
715 NCURSES_EXPORT(int)
716 _nc_setupscreen(int slines GCC_UNUSED,
717                 int scolumns GCC_UNUSED,
718                 FILE *output,
719                 int filtered,
720                 int slk_format)
721 {
722     SCREEN *sp = 0;
723     int rc = NCURSES_SP_NAME(_nc_setupscreen) (&sp,
724                                                slines,
725                                                scolumns,
726                                                output,
727                                                filtered,
728                                                slk_format);
729     if (rc != OK)
730         _nc_set_screen(0);
731     return rc;
732 }
733 #endif
734
735 /*
736  * The internal implementation interprets line as the number of lines to rip
737  * off from the top or bottom.
738  */
739 NCURSES_EXPORT(int)
740 NCURSES_SP_NAME(_nc_ripoffline) (NCURSES_SP_DCLx
741                                  int line,
742                                  int (*init) (WINDOW *, int))
743 {
744     int code = ERR;
745
746     START_TRACE();
747     T((T_CALLED("ripoffline(%p,%d,%p)"), (void *) SP_PARM, line, TR_FUNC(init)));
748
749 #if NCURSES_SP_FUNCS
750     if (SP_PARM != 0 && SP_PARM->_prescreen)
751 #endif
752     {
753         if (line == 0) {
754             code = OK;
755         } else {
756             if (safe_ripoff_sp == 0)
757                 safe_ripoff_sp = safe_ripoff_stack;
758             if (safe_ripoff_sp < safe_ripoff_stack + N_RIPS) {
759                 safe_ripoff_sp->line = line;
760                 safe_ripoff_sp->hook = init;
761                 (safe_ripoff_sp)++;
762                 code = OK;
763             }
764         }
765     }
766
767     returnCode(code);
768 }
769
770 #if NCURSES_SP_FUNCS
771 NCURSES_EXPORT(int)
772 _nc_ripoffline(int line, int (*init) (WINDOW *, int))
773 {
774     return NCURSES_SP_NAME(_nc_ripoffline) (CURRENT_SCREEN_PRE, line, init);
775 }
776 #endif
777
778 NCURSES_EXPORT(int)
779 NCURSES_SP_NAME(ripoffline) (NCURSES_SP_DCLx
780                              int line,
781                              int (*init) (WINDOW *, int))
782 {
783     START_TRACE();
784     return NCURSES_SP_NAME(_nc_ripoffline) (NCURSES_SP_ARGx
785                                             (line < 0) ? -1 : 1,
786                                             init);
787 }
788
789 #if NCURSES_SP_FUNCS
790 NCURSES_EXPORT(int)
791 ripoffline(int line, int (*init) (WINDOW *, int))
792 {
793     return NCURSES_SP_NAME(ripoffline) (CURRENT_SCREEN_PRE, line, init);
794 }
795 #endif