X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Flib_setup.c;h=4b0ec46ea6eaabe36414a7d87a8ed60dc2cd5dbf;hp=50c330eb5739a1e030d98feff067d0760e76dd65;hb=55ccd2b959766810cf7db8d1c4462f338ce0afc8;hpb=b1f61d9f3aa244512045a6b02e759825d7049d34 diff --git a/ncurses/tinfo/lib_setup.c b/ncurses/tinfo/lib_setup.c index 50c330eb..4b0ec46e 100644 --- a/ncurses/tinfo/lib_setup.c +++ b/ncurses/tinfo/lib_setup.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998,1999,2000 Free Software Foundation, Inc. * + * Copyright (c) 1998-2004,2005 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -29,6 +29,7 @@ /**************************************************************************** * Author: Zeyd M. Ben-Halim 1992,1995 * * and: Eric S. Raymond * + * and: Thomas E. Dickey 1996-2003 * ****************************************************************************/ /* @@ -42,13 +43,17 @@ #include /* for MAX_NAME_SIZE */ #include -#if defined(SVR4_TERMIO) && !defined(_POSIX_SOURCE) +#if SVR4_TERMIO && !defined(_POSIX_SOURCE) #define _POSIX_SOURCE #endif +#if HAVE_LOCALE_H +#include +#endif + #include /* lines, columns, cur_term */ -MODULE_ID("$Id: lib_setup.c,v 1.59 2000/02/13 01:01:26 tom Exp $") +MODULE_ID("$Id: lib_setup.c,v 1.88 2005/03/12 19:41:45 tom Exp $") /**************************************************************************** * @@ -72,6 +77,10 @@ MODULE_ID("$Id: lib_setup.c,v 1.59 2000/02/13 01:01:26 tom Exp $") # include #endif +#if HAVE_LANGINFO_CODESET +#include +#endif + /* * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, * Solaris, IRIX) define TIOCGWINSZ and struct winsize. @@ -90,18 +99,21 @@ MODULE_ID("$Id: lib_setup.c,v 1.59 2000/02/13 01:01:26 tom Exp $") # endif #endif -static int _use_env = TRUE; +NCURSES_EXPORT_VAR(char) ttytype[NAMESIZE] = ""; +NCURSES_EXPORT_VAR(int) LINES = 0; +NCURSES_EXPORT_VAR(int) COLS = 0; +NCURSES_EXPORT_VAR(int) TABSIZE = 0; -static void do_prototype(void); +static int _use_env = TRUE; -void +NCURSES_EXPORT(void) use_env(bool f) { + T((T_CALLED("use_env()"))); _use_env = f; + returnVoid; } -int LINES = 0, COLS = 0, TABSIZE = 0; - static void _nc_get_screensize(int *linep, int *colp) /* Obtain lines/columns values from the environment and/or terminfo entry */ @@ -133,7 +145,7 @@ _nc_get_screensize(int *linep, int *colp) *colp = screendata[0]; *linep = screendata[1]; T(("EMX screen size: environment LINES = %d COLUMNS = %d", - *linep, *colp)); + *linep, *colp)); } #endif #if HAVE_SIZECHANGE @@ -165,15 +177,18 @@ _nc_get_screensize(int *linep, int *colp) #endif /* HAVE_SIZECHANGE */ /* if we can't get dynamic info about the size, use static */ - if (*linep <= 0 || *colp <= 0) - if (lines > 0 && columns > 0) { - *linep = (int) lines; - *colp = (int) columns; - } + if (*linep <= 0) { + *linep = (int) lines; + } + if (*colp <= 0) { + *colp = (int) columns; + } /* the ultimate fallback, assume fixed 24x80 size */ - if (*linep <= 0 || *colp <= 0) { + if (*linep <= 0) { *linep = 24; + } + if (*colp <= 0) { *colp = 80; } @@ -192,18 +207,30 @@ _nc_get_screensize(int *linep, int *colp) else TABSIZE = 8; T(("TABSIZE = %d", TABSIZE)); - } #if USE_SIZECHANGE -void +NCURSES_EXPORT(void) _nc_update_screensize(void) { - int my_lines, my_cols; + int old_lines = lines; + int new_lines; + int old_cols = columns; + int new_cols; + + _nc_get_screensize(&new_lines, &new_cols); - _nc_get_screensize(&my_lines, &my_cols); - if (SP != 0 && SP->_resize != 0) - SP->_resize(my_lines, my_cols); + /* + * See is_term_resized() and resizeterm(). + * We're doing it this way because those functions belong to the upper + * ncurses library, while this resides in the lower terminfo library. + */ + if (SP != 0 + && SP->_resize != 0) { + if ((new_lines != old_lines) || (new_cols != old_cols)) + SP->_resize(new_lines, new_cols); + SP->_sig_winch = FALSE; + } } #endif @@ -229,12 +256,14 @@ _nc_update_screensize(void) exit(EXIT_FAILURE);\ } -#if USE_DATABASE +#if USE_DATABASE || USE_TERMCAP static int -grab_entry(const char *const tn, TERMTYPE * const tp) +grab_entry(const char *const tn, TERMTYPE *const tp) /* return 1 if entry found, 0 if not found, -1 if database not accessible */ { +#if USE_DATABASE char filename[PATH_MAX]; +#endif int status; /* @@ -243,9 +272,10 @@ grab_entry(const char *const tn, TERMTYPE * const tp) if (strchr(tn, '/')) return 0; +#if USE_DATABASE if ((status = _nc_read_entry(tn, filename, tp)) != 1) { -#ifndef PURE_TERMINFO +#if !PURE_TERMINFO /* * Try falling back on the termcap file. * Note: allowing this call links the entire terminfo/termcap @@ -256,6 +286,9 @@ grab_entry(const char *const tn, TERMTYPE * const tp) #endif /* PURE_TERMINFO */ } +#else + status = _nc_read_termcap_entry(tn, tp); +#endif /* * If we have an entry, force all of the cancelled strings to null @@ -264,34 +297,135 @@ grab_entry(const char *const tn, TERMTYPE * const tp) * a string is cancelled, for merging entries). */ if (status == 1) { - int n; - for_each_boolean(n, tp) + unsigned n; + for_each_boolean(n, tp) { if (!VALID_BOOLEAN(tp->Booleans[n])) - tp->Booleans[n] = FALSE; - for_each_string(n, tp) + tp->Booleans[n] = FALSE; + } + for_each_string(n, tp) { if (tp->Strings[n] == CANCELLED_STRING) - tp->Strings[n] = ABSENT_STRING; + tp->Strings[n] = ABSENT_STRING; + } } return (status); } #endif -char ttytype[NAMESIZE] = ""; +/* +** do_prototype() +** +** Take the real command character out of the CC environment variable +** and substitute it in for the prototype given in 'command_character'. +** +*/ +static void +do_prototype(void) +{ + int i; + char CC; + char proto; + char *tmp; + + tmp = getenv("CC"); + CC = *tmp; + proto = *command_character; + + for_each_string(i, &(cur_term->type)) { + for (tmp = cur_term->type.Strings[i]; *tmp; tmp++) { + if (*tmp == proto) + *tmp = CC; + } + } +} /* - * setupterm(termname, Filedes, errret) - * - * Find and read the appropriate object file for the terminal - * Make cur_term point to the structure. - * + * Find the locale which is in effect. */ +NCURSES_EXPORT(char *) +_nc_get_locale(void) +{ + char *env; +#if HAVE_LOCALE_H + /* + * This is preferable to using getenv() since it ensures that we are using + * the locale which was actually initialized by the application. + */ + env = setlocale(LC_CTYPE, 0); +#else + if (((env = getenv("LC_ALL")) != 0 && *env != '\0') + || ((env = getenv("LC_CTYPE")) != 0 && *env != '\0') + || ((env = getenv("LANG")) != 0 && *env != '\0')) { + ; + } +#endif + T(("_nc_get_locale %s", _nc_visbuf(env))); + return env; +} -int -setupterm(NCURSES_CONST char *tname, int Filedes, int *errret) +/* + * Check if we are running in a UTF-8 locale. + */ +NCURSES_EXPORT(int) +_nc_unicode_locale(void) +{ + int result = 0; +#if HAVE_LANGINFO_CODESET + char *env = nl_langinfo(CODESET); + result = !strcmp(env, "UTF-8"); + T(("_nc_unicode_locale(%s) ->%d", env, result)); +#else + char *env = _nc_get_locale(); + if (env != 0) { + if (strstr(env, ".UTF-8") != 0) { + result = 1; + T(("_nc_unicode_locale(%s) ->%d", env, result)); + } + } +#endif + return result; +} + +#define CONTROL_N(s) ((s) != 0 && strstr(s, "\016") != 0) +#define CONTROL_O(s) ((s) != 0 && strstr(s, "\017") != 0) + +/* + * Check for known broken cases where a UTF-8 locale breaks the alternate + * character set. + */ +NCURSES_EXPORT(int) +_nc_locale_breaks_acs(void) +{ + char *env; + + if ((env = getenv("NCURSES_NO_UTF8_ACS")) != 0) { + return atoi(env); + } else if ((env = getenv("TERM")) != 0) { + if (strstr(env, "linux")) + return 1; /* always broken */ + if (strstr(env, "screen") != 0 + && ((env = getenv("TERMCAP")) != 0 + && strstr(env, "screen") != 0) + && strstr(env, "hhII00") != 0) { + if (CONTROL_N(enter_alt_charset_mode) || + CONTROL_O(enter_alt_charset_mode) || + CONTROL_N(set_attributes) || + CONTROL_O(set_attributes)) + return 1; + } + } + return 0; +} + +/* + * This entrypoint is called from tgetent() to allow special a case of reusing + * the same TERMINAL data (see comment). + */ +NCURSES_EXPORT(int) +_nc_setupterm(NCURSES_CONST char *tname, int Filedes, int *errret, bool reuse) { - struct term *term_ptr; int status; + START_TRACE(); T((T_CALLED("setupterm(%s,%d,%p)"), _nc_visbuf(tname), Filedes, errret)); if (tname == 0) { @@ -302,73 +436,101 @@ setupterm(NCURSES_CONST char *tname, int Filedes, int *errret) } if (strlen(tname) > MAX_NAME_SIZE) { ret_error(-1, "TERM environment must be <= %d characters.\n", - MAX_NAME_SIZE); + MAX_NAME_SIZE); } T(("your terminal name is %s", tname)); - term_ptr = typeCalloc(TERMINAL, 1); + /* + * Allow output redirection. This is what SVr3 does. If stdout is + * directed to a file, screen updates go to standard error. + */ + if (Filedes == STDOUT_FILENO && !isatty(Filedes)) + Filedes = STDERR_FILENO; - if (term_ptr == 0) { - ret_error0(-1, "Not enough memory to create terminal structure.\n"); - } -#if USE_DATABASE - status = grab_entry(tname, &term_ptr->type); + /* + * Check if we have already initialized to use this terminal. If so, we + * do not need to re-read the terminfo entry, or obtain TTY settings. + * + * This is an improvement on SVr4 curses. If an application mixes curses + * and termcap calls, it may call both initscr and tgetent. This is not + * really a good thing to do, but can happen if someone tries using ncurses + * with the readline library. The problem we are fixing is that when + * tgetent calls setupterm, the resulting Ottyb struct in cur_term is + * zeroed. A subsequent call to endwin uses the zeroed terminal settings + * rather than the ones saved in initscr. So we check if cur_term appears + * to contain terminal settings for the same output file as our current + * call - and copy those terminal settings. (SVr4 curses does not do this, + * however applications that are working around the problem will still work + * properly with this feature). + */ + if (reuse + && cur_term != 0 + && cur_term->Filedes == Filedes + && cur_term->_termname != 0 + && !strcmp(cur_term->_termname, tname) + && _nc_name_match(cur_term->type.term_names, tname, "|")) { + T(("reusing existing terminal information and mode-settings")); + } else { + TERMINAL *term_ptr; + + term_ptr = typeCalloc(TERMINAL, 1); + + if (term_ptr == 0) { + ret_error0(-1, + "Not enough memory to create terminal structure.\n"); + } +#if USE_DATABASE || USE_TERMCAP + status = grab_entry(tname, &term_ptr->type); #else - status = 0; + status = 0; #endif - /* try fallback list if entry on disk */ - if (status != 1) { - const TERMTYPE *fallback = _nc_fallback(tname); + /* try fallback list if entry on disk */ + if (status != 1) { + const TERMTYPE *fallback = _nc_fallback(tname); - if (fallback) { - term_ptr->type = *fallback; - status = 1; + if (fallback) { + term_ptr->type = *fallback; + status = 1; + } } - } - if (status == -1) { - ret_error0(-1, "terminals database is inaccessible\n"); - } else if (status == 0) { - ret_error(0, "'%s': unknown terminal type.\n", tname); - } + if (status <= 0) { + del_curterm(term_ptr); + if (status == -1) { + ret_error0(-1, "terminals database is inaccessible\n"); + } else if (status == 0) { + ret_error(0, "'%s': unknown terminal type.\n", tname); + } + } - /* - * Improve on SVr4 curses. If an application mixes curses and termcap - * calls, it may call both initscr and tgetent. This is not really a - * good thing to do, but can happen if someone tries using ncurses with - * the readline library. The problem we are fixing is that when - * tgetent calls setupterm, the resulting Ottyb struct in cur_term is - * zeroed. A subsequent call to endwin uses the zeroed terminal - * settings rather than the ones saved in initscr. So we check if - * cur_term appears to contain terminal settings for the same output - * file as our current call - and copy those terminal settings. (SVr4 - * curses does not do this, however applications that are working - * around the problem will still work properly with this feature). - */ - if (cur_term != 0) { - if (cur_term->Filedes == Filedes) - term_ptr->Ottyb = cur_term->Ottyb; - } + set_curterm(term_ptr); + + if (command_character && getenv("CC")) + do_prototype(); - set_curterm(term_ptr); + strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1); + ttytype[NAMESIZE - 1] = '\0'; - if (command_character && getenv("CC")) - do_prototype(); + cur_term->Filedes = Filedes; + cur_term->_termname = strdup(tname); - strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1); - ttytype[NAMESIZE - 1] = '\0'; + /* + * If an application calls setupterm() rather than initscr() or + * newterm(), we will not have the def_prog_mode() call in + * _nc_setupscreen(). Do it now anyway, so we can initialize the + * baudrate. + */ + if (isatty(Filedes)) { + def_prog_mode(); + baudrate(); + } + } /* - * Allow output redirection. This is what SVr3 does. - * If stdout is directed to a file, screen updates go - * to standard error. + * We should always check the screensize, just in case. */ - if (Filedes == STDOUT_FILENO && !isatty(Filedes)) - Filedes = STDERR_FILENO; - cur_term->Filedes = Filedes; - _nc_get_screensize(&LINES, &COLS); if (errret) @@ -386,29 +548,15 @@ setupterm(NCURSES_CONST char *tname, int Filedes, int *errret) } /* -** do_prototype() -** -** Take the real command character out of the CC environment variable -** and substitute it in for the prototype given in 'command_character'. -** -*/ + * setupterm(termname, Filedes, errret) + * + * Find and read the appropriate object file for the terminal + * Make cur_term point to the structure. + * + */ -static void -do_prototype(void) +NCURSES_EXPORT(int) +setupterm(NCURSES_CONST char *tname, int Filedes, int *errret) { - int i; - char CC; - char proto; - char *tmp; - - tmp = getenv("CC"); - CC = *tmp; - proto = *command_character; - - for_each_string(i, &(cur_term->type)) { - for (tmp = cur_term->type.Strings[i]; *tmp; tmp++) { - if (*tmp == proto) - *tmp = CC; - } - } + return _nc_setupterm(tname, Filedes, errret, FALSE); }