ncurses 5.9 - patch 20110416
[ncurses.git] / ncurses / tinfo / lib_setup.c
1 /****************************************************************************
2  * Copyright (c) 1998-2010,2011 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  * Terminal setup routines common to termcap and terminfo:
38  *
39  *              use_env(bool)
40  *              setupterm(char *, int, int *)
41  */
42
43 #include <curses.priv.h>
44 #include <tic.h>                /* for MAX_NAME_SIZE */
45
46 #if HAVE_LOCALE_H
47 #include <locale.h>
48 #endif
49
50 MODULE_ID("$Id: lib_setup.c,v 1.136 2011/04/16 15:32:45 tom Exp $")
51
52 /****************************************************************************
53  *
54  * Terminal size computation
55  *
56  ****************************************************************************/
57
58 #if HAVE_SIZECHANGE
59 # if !defined(sun) || !TERMIOS
60 #  if HAVE_SYS_IOCTL_H
61 #   include <sys/ioctl.h>
62 #  endif
63 # endif
64 #endif
65
66 #if NEED_PTEM_H
67  /* On SCO, they neglected to define struct winsize in termios.h -- it's only
68   * in termio.h and ptem.h (the former conflicts with other definitions).
69   */
70 # include <sys/stream.h>
71 # include <sys/ptem.h>
72 #endif
73
74 #if HAVE_LANGINFO_CODESET
75 #include <langinfo.h>
76 #endif
77
78 /*
79  * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
80  * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
81  */
82 #ifdef TIOCGSIZE
83 # define IOCTL_WINSIZE TIOCGSIZE
84 # define STRUCT_WINSIZE struct ttysize
85 # define WINSIZE_ROWS(n) (int)n.ts_lines
86 # define WINSIZE_COLS(n) (int)n.ts_cols
87 #else
88 # ifdef TIOCGWINSZ
89 #  define IOCTL_WINSIZE TIOCGWINSZ
90 #  define STRUCT_WINSIZE struct winsize
91 #  define WINSIZE_ROWS(n) (int)n.ws_row
92 #  define WINSIZE_COLS(n) (int)n.ws_col
93 # endif
94 #endif
95
96 /*
97  * Reduce explicit use of "cur_term" global variable.
98  */
99 #undef CUR
100 #define CUR termp->type.
101
102 /*
103  * Wrap global variables in this module.
104  */
105 #if USE_REENTRANT
106
107 NCURSES_EXPORT(char *)
108 NCURSES_PUBLIC_VAR(ttytype) (void)
109 {
110     static char empty[] = "";
111     char *result = empty;
112
113 #if NCURSES_SP_FUNCS
114     if (CURRENT_SCREEN) {
115         TERMINAL *termp = TerminalOf(CURRENT_SCREEN);
116         if (termp != 0) {
117             result = termp->type.term_names;
118         }
119     }
120 #else
121     if (cur_term != 0) {
122         result = cur_term->type.term_names;
123     }
124 #endif
125     return result;
126 }
127
128 NCURSES_EXPORT(int *)
129 _nc_ptr_Lines(SCREEN *sp)
130 {
131     return ptrLines(sp);
132 }
133
134 NCURSES_EXPORT(int)
135 NCURSES_PUBLIC_VAR(LINES) (void)
136 {
137     return *_nc_ptr_Lines(CURRENT_SCREEN);
138 }
139
140 NCURSES_EXPORT(int *)
141 _nc_ptr_Cols(SCREEN *sp)
142 {
143     return ptrCols(sp);
144 }
145
146 NCURSES_EXPORT(int)
147 NCURSES_PUBLIC_VAR(COLS) (void)
148 {
149     return *_nc_ptr_Cols(CURRENT_SCREEN);
150 }
151
152 NCURSES_EXPORT(int *)
153 _nc_ptr_Tabsize(SCREEN *sp)
154 {
155     return ptrTabsize(sp);
156 }
157
158 NCURSES_EXPORT(int)
159 NCURSES_PUBLIC_VAR(TABSIZE) (void)
160 {
161     return *_nc_ptr_Tabsize(CURRENT_SCREEN);
162 }
163 #else
164 NCURSES_EXPORT_VAR(char) ttytype[NAMESIZE] = "";
165 NCURSES_EXPORT_VAR(int) LINES = 0;
166 NCURSES_EXPORT_VAR(int) COLS = 0;
167 NCURSES_EXPORT_VAR(int) TABSIZE = 8;
168 #endif
169
170 #if NCURSES_EXT_FUNCS
171 NCURSES_EXPORT(int)
172 NCURSES_SP_NAME(set_tabsize) (NCURSES_SP_DCLx int value)
173 {
174     int code = OK;
175 #if USE_REENTRANT
176     if (SP_PARM) {
177         SP_PARM->_TABSIZE = value;
178     } else {
179         code = ERR;
180     }
181 #else
182     (void) SP_PARM;
183     TABSIZE = value;
184 #endif
185     return code;
186 }
187
188 #if NCURSES_SP_FUNCS
189 NCURSES_EXPORT(int)
190 set_tabsize(int value)
191 {
192     return NCURSES_SP_NAME(set_tabsize) (CURRENT_SCREEN, value);
193 }
194 #endif
195 #endif /* NCURSES_EXT_FUNCS */
196
197 #if USE_SIGWINCH
198 /*
199  * If we have a pending SIGWINCH, set the flag in each screen.
200  */
201 NCURSES_EXPORT(int)
202 _nc_handle_sigwinch(SCREEN *sp)
203 {
204     SCREEN *scan;
205
206     if (_nc_globals.have_sigwinch) {
207         _nc_globals.have_sigwinch = 0;
208
209         for (each_screen(scan)) {
210             scan->_sig_winch = TRUE;
211         }
212     }
213
214     return (sp ? sp->_sig_winch : 0);
215 }
216
217 #endif
218
219 NCURSES_EXPORT(void)
220 NCURSES_SP_NAME(use_env) (NCURSES_SP_DCLx bool f)
221 {
222     T((T_CALLED("use_env(%p,%d)"), (void *) SP_PARM, (int) f));
223 #if NCURSES_SP_FUNCS
224     if (IsPreScreen(SP_PARM)) {
225         SP_PARM->_use_env = f;
226     }
227 #else
228     _nc_prescreen.use_env = f;
229 #endif
230     returnVoid;
231 }
232
233 #if NCURSES_SP_FUNCS
234 NCURSES_EXPORT(void)
235 use_env(bool f)
236 {
237     T((T_CALLED("use_env(%d)"), (int) f));
238     _nc_prescreen.use_env = f;
239     returnVoid;
240 }
241 #endif
242
243 NCURSES_EXPORT(void)
244 _nc_get_screensize(SCREEN *sp,
245 #ifdef USE_TERM_DRIVER
246                    TERMINAL * termp,
247 #endif
248                    int *linep, int *colp)
249 /* Obtain lines/columns values from the environment and/or terminfo entry */
250 {
251 #ifdef USE_TERM_DRIVER
252     TERMINAL_CONTROL_BLOCK *TCB;
253     int my_tabsize;
254
255     assert(termp != 0 && linep != 0 && colp != 0);
256     TCB = (TERMINAL_CONTROL_BLOCK *) termp;
257
258     my_tabsize = TCB->info.tabsize;
259     TCB->drv->size(TCB, linep, colp);
260
261 #if USE_REENTRANT
262     if (sp != 0) {
263         sp->_TABSIZE = my_tabsize;
264     }
265 #else
266     (void) sp;
267     TABSIZE = my_tabsize;
268 #endif
269     T(("TABSIZE = %d", my_tabsize));
270 #else /* !USE_TERM_DRIVER */
271     TERMINAL *termp = cur_term;
272     int my_tabsize;
273
274     /* figure out the size of the screen */
275     T(("screen size: terminfo lines = %d columns = %d", lines, columns));
276
277     *linep = (int) lines;
278     *colp = (int) columns;
279
280     if (_nc_prescreen.use_env) {
281         int value;
282
283 #ifdef __EMX__
284         {
285             int screendata[2];
286             _scrsize(screendata);
287             *colp = screendata[0];
288             *linep = screendata[1];
289             T(("EMX screen size: environment LINES = %d COLUMNS = %d",
290                *linep, *colp));
291         }
292 #endif
293 #if HAVE_SIZECHANGE
294         /* try asking the OS */
295         if (isatty(cur_term->Filedes)) {
296             STRUCT_WINSIZE size;
297
298             errno = 0;
299             do {
300                 if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) >= 0) {
301                     *linep = ((sp != 0 && sp->_filtered)
302                               ? 1
303                               : WINSIZE_ROWS(size));
304                     *colp = WINSIZE_COLS(size);
305                     T(("SYS screen size: environment LINES = %d COLUMNS = %d",
306                        *linep, *colp));
307                     break;
308                 }
309             } while
310                 (errno == EINTR);
311         }
312 #endif /* HAVE_SIZECHANGE */
313
314         /*
315          * Finally, look for environment variables.
316          *
317          * Solaris lets users override either dimension with an environment
318          * variable.
319          */
320         if ((value = _nc_getenv_num("LINES")) > 0) {
321             *linep = value;
322             T(("screen size: environment LINES = %d", *linep));
323         }
324         if ((value = _nc_getenv_num("COLUMNS")) > 0) {
325             *colp = value;
326             T(("screen size: environment COLUMNS = %d", *colp));
327         }
328
329         /* if we can't get dynamic info about the size, use static */
330         if (*linep <= 0) {
331             *linep = (int) lines;
332         }
333         if (*colp <= 0) {
334             *colp = (int) columns;
335         }
336
337         /* the ultimate fallback, assume fixed 24x80 size */
338         if (*linep <= 0) {
339             *linep = 24;
340         }
341         if (*colp <= 0) {
342             *colp = 80;
343         }
344
345         /*
346          * Put the derived values back in the screen-size caps, so
347          * tigetnum() and tgetnum() will do the right thing.
348          */
349         lines = (short) (*linep);
350         columns = (short) (*colp);
351     }
352
353     T(("screen size is %dx%d", *linep, *colp));
354
355     if (VALID_NUMERIC(init_tabs))
356         my_tabsize = (int) init_tabs;
357     else
358         my_tabsize = 8;
359
360 #if USE_REENTRANT
361     if (sp != 0)
362         sp->_TABSIZE = my_tabsize;
363 #else
364     TABSIZE = my_tabsize;
365 #endif
366     T(("TABSIZE = %d", TABSIZE));
367 #endif /* USE_TERM_DRIVER */
368 }
369
370 #if USE_SIZECHANGE
371 NCURSES_EXPORT(void)
372 _nc_update_screensize(SCREEN *sp)
373 {
374     int new_lines;
375     int new_cols;
376
377 #ifdef USE_TERM_DRIVER
378     int old_lines;
379     int old_cols;
380
381     assert(sp != 0);
382
383     CallDriver_2(sp, getsize, &old_lines, &old_cols);
384
385 #else
386     TERMINAL *termp = cur_term;
387     int old_lines = lines;
388     int old_cols = columns;
389 #endif
390
391     TINFO_GET_SIZE(sp, sp->_term, &new_lines, &new_cols);
392
393     /*
394      * See is_term_resized() and resizeterm().
395      * We're doing it this way because those functions belong to the upper
396      * ncurses library, while this resides in the lower terminfo library.
397      */
398     if (sp != 0
399         && sp->_resize != 0) {
400         if ((new_lines != old_lines) || (new_cols != old_cols))
401             sp->_resize(NCURSES_SP_ARGx new_lines, new_cols);
402         sp->_sig_winch = FALSE;
403     }
404 }
405 #endif
406
407 /****************************************************************************
408  *
409  * Terminal setup
410  *
411  ****************************************************************************/
412
413 #define ret_error(code, fmt, arg)       if (errret) {\
414                                             *errret = code;\
415                                             returnCode(ERR);\
416                                         } else {\
417                                             fprintf(stderr, fmt, arg);\
418                                             exit(EXIT_FAILURE);\
419                                         }
420
421 #define ret_error0(code, msg)           if (errret) {\
422                                             *errret = code;\
423                                             returnCode(ERR);\
424                                         } else {\
425                                             fprintf(stderr, msg);\
426                                             exit(EXIT_FAILURE);\
427                                         }
428
429 #if USE_DATABASE || USE_TERMCAP
430 /*
431  * Return 1 if entry found, 0 if not found, -1 if database not accessible,
432  * just like tgetent().
433  */
434 int
435 _nc_setup_tinfo(const char *const tn, TERMTYPE *const tp)
436 {
437     char filename[PATH_MAX];
438     int status = _nc_read_entry(tn, filename, tp);
439
440     /*
441      * If we have an entry, force all of the cancelled strings to null
442      * pointers so we don't have to test them in the rest of the library.
443      * (The terminfo compiler bypasses this logic, since it must know if
444      * a string is cancelled, for merging entries).
445      */
446     if (status == TGETENT_YES) {
447         unsigned n;
448         for_each_boolean(n, tp) {
449             if (!VALID_BOOLEAN(tp->Booleans[n]))
450                 tp->Booleans[n] = FALSE;
451         }
452         for_each_string(n, tp) {
453             if (tp->Strings[n] == CANCELLED_STRING)
454                 tp->Strings[n] = ABSENT_STRING;
455         }
456     }
457     return (status);
458 }
459 #endif
460
461 /*
462 **      Take the real command character out of the CC environment variable
463 **      and substitute it in for the prototype given in 'command_character'.
464 */
465 void
466 _nc_tinfo_cmdch(TERMINAL * termp, char proto)
467 {
468     unsigned i;
469     char CC;
470     char *tmp;
471
472     /*
473      * Only use the character if the string is a single character,
474      * since it is fairly common for developers to set the C compiler
475      * name as an environment variable - using the same symbol.
476      */
477     if ((tmp = getenv("CC")) != 0 && strlen(tmp) == 1) {
478         CC = *tmp;
479         for_each_string(i, &(termp->type)) {
480             for (tmp = termp->type.Strings[i]; *tmp; tmp++) {
481                 if (*tmp == proto)
482                     *tmp = CC;
483             }
484         }
485     }
486 }
487
488 /*
489  * Find the locale which is in effect.
490  */
491 NCURSES_EXPORT(char *)
492 _nc_get_locale(void)
493 {
494     char *env;
495 #if HAVE_LOCALE_H
496     /*
497      * This is preferable to using getenv() since it ensures that we are using
498      * the locale which was actually initialized by the application.
499      */
500     env = setlocale(LC_CTYPE, 0);
501 #else
502     if (((env = getenv("LC_ALL")) != 0 && *env != '\0')
503         || ((env = getenv("LC_CTYPE")) != 0 && *env != '\0')
504         || ((env = getenv("LANG")) != 0 && *env != '\0')) {
505         ;
506     }
507 #endif
508     T(("_nc_get_locale %s", _nc_visbuf(env)));
509     return env;
510 }
511
512 /*
513  * Check if we are running in a UTF-8 locale.
514  */
515 NCURSES_EXPORT(int)
516 _nc_unicode_locale(void)
517 {
518     int result = 0;
519 #if HAVE_LANGINFO_CODESET
520     char *env = nl_langinfo(CODESET);
521     result = !strcmp(env, "UTF-8");
522     T(("_nc_unicode_locale(%s) ->%d", env, result));
523 #else
524     char *env = _nc_get_locale();
525     if (env != 0) {
526         if (strstr(env, ".UTF-8") != 0) {
527             result = 1;
528             T(("_nc_unicode_locale(%s) ->%d", env, result));
529         }
530     }
531 #endif
532     return result;
533 }
534
535 #define CONTROL_N(s) ((s) != 0 && strstr(s, "\016") != 0)
536 #define CONTROL_O(s) ((s) != 0 && strstr(s, "\017") != 0)
537
538 /*
539  * Check for known broken cases where a UTF-8 locale breaks the alternate
540  * character set.
541  */
542 NCURSES_EXPORT(int)
543 _nc_locale_breaks_acs(TERMINAL * termp)
544 {
545     const char *env_name = "NCURSES_NO_UTF8_ACS";
546     char *env;
547     int value;
548     int result = 0;
549
550     if ((env = getenv(env_name)) != 0) {
551         result = _nc_getenv_num(env_name);
552     } else if ((value = tigetnum("U8")) >= 0) {
553         result = value;         /* use extension feature */
554     } else if ((env = getenv("TERM")) != 0) {
555         if (strstr(env, "linux")) {
556             result = 1;         /* always broken */
557         } else if (strstr(env, "screen") != 0
558                    && ((env = getenv("TERMCAP")) != 0
559                        && strstr(env, "screen") != 0)
560                    && strstr(env, "hhII00") != 0) {
561             if (CONTROL_N(enter_alt_charset_mode) ||
562                 CONTROL_O(enter_alt_charset_mode) ||
563                 CONTROL_N(set_attributes) ||
564                 CONTROL_O(set_attributes)) {
565                 result = 1;
566             }
567         }
568     }
569     return result;
570 }
571
572 NCURSES_EXPORT(int)
573 TINFO_SETUP_TERM(TERMINAL ** tp,
574                  NCURSES_CONST char *tname,
575                  int Filedes,
576                  int *errret,
577                  bool reuse)
578 {
579 #ifdef USE_TERM_DRIVER
580     TERMINAL_CONTROL_BLOCK *TCB = 0;
581 #else
582     int status;
583 #endif
584     TERMINAL *termp;
585     SCREEN *sp = 0;
586     int code = ERR;
587
588     START_TRACE();
589
590 #ifdef USE_TERM_DRIVER
591     T((T_CALLED("_nc_setupterm_ex(%p,%s,%d,%p)"),
592        (void *) tp, _nc_visbuf(tname), Filedes, (void *) errret));
593
594     if (tp == 0) {
595         ret_error0(TGETENT_ERR,
596                    "Invalid parameter, internal error.\n");
597     } else
598         termp = *tp;
599 #else
600     termp = cur_term;
601     T((T_CALLED("setupterm(%s,%d,%p)"), _nc_visbuf(tname), Filedes, (void *) errret));
602 #endif
603
604     if (tname == 0) {
605         tname = getenv("TERM");
606         if (tname == 0 || *tname == '\0') {
607             ret_error0(TGETENT_ERR, "TERM environment variable not set.\n");
608         }
609     }
610
611     if (strlen(tname) > MAX_NAME_SIZE) {
612         ret_error(TGETENT_ERR,
613                   "TERM environment must be <= %d characters.\n",
614                   MAX_NAME_SIZE);
615     }
616
617     T(("your terminal name is %s", tname));
618
619     /*
620      * Allow output redirection.  This is what SVr3 does.  If stdout is
621      * directed to a file, screen updates go to standard error.
622      */
623     if (Filedes == STDOUT_FILENO && !isatty(Filedes))
624         Filedes = STDERR_FILENO;
625
626     /*
627      * Check if we have already initialized to use this terminal.  If so, we
628      * do not need to re-read the terminfo entry, or obtain TTY settings.
629      *
630      * This is an improvement on SVr4 curses.  If an application mixes curses
631      * and termcap calls, it may call both initscr and tgetent.  This is not
632      * really a good thing to do, but can happen if someone tries using ncurses
633      * with the readline library.  The problem we are fixing is that when
634      * tgetent calls setupterm, the resulting Ottyb struct in cur_term is
635      * zeroed.  A subsequent call to endwin uses the zeroed terminal settings
636      * rather than the ones saved in initscr.  So we check if cur_term appears
637      * to contain terminal settings for the same output file as our current
638      * call - and copy those terminal settings.  (SVr4 curses does not do this,
639      * however applications that are working around the problem will still work
640      * properly with this feature).
641      */
642     if (reuse
643         && (termp != 0)
644         && termp->Filedes == Filedes
645         && termp->_termname != 0
646         && !strcmp(termp->_termname, tname)
647         && _nc_name_match(termp->type.term_names, tname, "|")) {
648         T(("reusing existing terminal information and mode-settings"));
649         code = OK;
650     } else {
651 #ifdef USE_TERM_DRIVER
652         termp = (TERMINAL *) typeCalloc(TERMINAL_CONTROL_BLOCK, 1);
653 #else
654         termp = typeCalloc(TERMINAL, 1);
655 #endif
656         if (termp == 0) {
657             ret_error0(TGETENT_ERR,
658                        "Not enough memory to create terminal structure.\n");
659         }
660 #ifdef USE_TERM_DRIVER
661         INIT_TERM_DRIVER();
662         TCB = (TERMINAL_CONTROL_BLOCK *) termp;
663         code = _nc_globals.term_driver(TCB, tname, errret);
664         if (code == OK) {
665             termp->Filedes = (short) Filedes;
666             termp->_termname = strdup(tname);
667         } else {
668             ret_error0(TGETENT_ERR,
669                        "Could not find any driver to handle this terminal.\n");
670         }
671 #else
672 #if USE_DATABASE || USE_TERMCAP
673         status = _nc_setup_tinfo(tname, &termp->type);
674 #else
675         status = TGETENT_NO;
676 #endif
677
678         /* try fallback list if entry on disk */
679         if (status != TGETENT_YES) {
680             const TERMTYPE *fallback = _nc_fallback(tname);
681
682             if (fallback) {
683                 termp->type = *fallback;
684                 status = TGETENT_YES;
685             }
686         }
687
688         if (status != TGETENT_YES) {
689             del_curterm(termp);
690             if (status == TGETENT_ERR) {
691                 ret_error0(status, "terminals database is inaccessible\n");
692             } else if (status == TGETENT_NO) {
693                 ret_error(status, "'%s': unknown terminal type.\n", tname);
694             }
695         }
696 #if !USE_REENTRANT
697         strncpy(ttytype, termp->type.term_names, NAMESIZE - 1);
698         ttytype[NAMESIZE - 1] = '\0';
699 #endif
700
701         termp->Filedes = (short) Filedes;
702         termp->_termname = strdup(tname);
703
704         set_curterm(termp);
705
706         if (command_character)
707             _nc_tinfo_cmdch(termp, *command_character);
708
709         /*
710          * If an application calls setupterm() rather than initscr() or
711          * newterm(), we will not have the def_prog_mode() call in
712          * _nc_setupscreen().  Do it now anyway, so we can initialize the
713          * baudrate.
714          */
715         if (isatty(Filedes)) {
716             def_prog_mode();
717             baudrate();
718         }
719         code = OK;
720 #endif
721     }
722
723 #ifdef USE_TERM_DRIVER
724     *tp = termp;
725     NCURSES_SP_NAME(set_curterm) (sp, termp);
726     TCB->drv->init(TCB);
727 #else
728     sp = SP;
729 #endif
730
731     /*
732      * We should always check the screensize, just in case.
733      */
734     TINFO_GET_SIZE(sp, termp, ptrLines(sp), ptrCols(sp));
735
736     if (errret)
737         *errret = TGETENT_YES;
738
739 #ifndef USE_TERM_DRIVER
740     if (generic_type) {
741         ret_error(TGETENT_NO, "'%s': I need something more specific.\n", tname);
742     }
743     if (hard_copy) {
744         ret_error(TGETENT_YES, "'%s': I can't handle hardcopy terminals.\n", tname);
745     }
746 #endif
747     returnCode(code);
748 }
749
750 #if NCURSES_SP_FUNCS
751 /*
752  * In case of handling multiple screens, we need to have a screen before
753  * initialization in setupscreen takes place.  This is to extend the substitute
754  * for some of the stuff in _nc_prescreen, especially for slk and ripoff
755  * handling which should be done per screen.
756  */
757 NCURSES_EXPORT(SCREEN *)
758 new_prescr(void)
759 {
760     static SCREEN *sp;
761
762     START_TRACE();
763     T((T_CALLED("new_prescr()")));
764
765     if (sp == 0) {
766         sp = _nc_alloc_screen_sp();
767         if (sp != 0) {
768             sp->rsp = sp->rippedoff;
769             sp->_filtered = _nc_prescreen.filter_mode;
770             sp->_use_env = _nc_prescreen.use_env;
771 #if NCURSES_NO_PADDING
772             sp->_no_padding = _nc_prescreen._no_padding;
773 #endif
774             sp->slk_format = 0;
775             sp->_slk = 0;
776             sp->_prescreen = TRUE;
777             SP_PRE_INIT(sp);
778 #if USE_REENTRANT
779             sp->_TABSIZE = _nc_prescreen._TABSIZE;
780             sp->_ESCDELAY = _nc_prescreen._ESCDELAY;
781 #endif
782         }
783     }
784     returnSP(sp);
785 }
786 #endif
787
788 #ifdef USE_TERM_DRIVER
789 /*
790  * This entrypoint is called from tgetent() to allow a special case of reusing
791  * the same TERMINAL data (see comment).
792  */
793 NCURSES_EXPORT(int)
794 _nc_setupterm(NCURSES_CONST char *tname,
795               int Filedes,
796               int *errret,
797               bool reuse)
798 {
799     int res;
800     TERMINAL *termp;
801     res = TINFO_SETUP_TERM(&termp, tname, Filedes, errret, reuse);
802     if (ERR != res)
803         NCURSES_SP_NAME(set_curterm) (CURRENT_SCREEN_PRE, termp);
804     return res;
805 }
806 #endif
807
808 /*
809  *      setupterm(termname, Filedes, errret)
810  *
811  *      Find and read the appropriate object file for the terminal
812  *      Make cur_term point to the structure.
813  */
814 NCURSES_EXPORT(int)
815 setupterm(NCURSES_CONST char *tname, int Filedes, int *errret)
816 {
817     return _nc_setupterm(tname, Filedes, errret, FALSE);
818 }