lib_setup.c revision 76726
1/**************************************************************************** 2 * Copyright (c) 1998,1999,2000 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 ****************************************************************************/ 33 34/* 35 * Terminal setup routines common to termcap and terminfo: 36 * 37 * use_env(bool) 38 * setupterm(char *, int, int *) 39 */ 40 41#include <curses.priv.h> 42#include <tic.h> /* for MAX_NAME_SIZE */ 43#include <term_entry.h> 44 45#if SVR4_TERMIO && !defined(_POSIX_SOURCE) 46#define _POSIX_SOURCE 47#endif 48 49#include <term.h> /* lines, columns, cur_term */ 50 51MODULE_ID("$Id: lib_setup.c,v 1.64 2000/12/10 02:55:07 tom Exp $") 52 53/**************************************************************************** 54 * 55 * Terminal size computation 56 * 57 ****************************************************************************/ 58 59#if HAVE_SIZECHANGE 60# if !defined(sun) || !TERMIOS 61# if HAVE_SYS_IOCTL_H 62# include <sys/ioctl.h> 63# endif 64# endif 65#endif 66 67#if NEED_PTEM_H 68 /* On SCO, they neglected to define struct winsize in termios.h -- it's only 69 * in termio.h and ptem.h (the former conflicts with other definitions). 70 */ 71# include <sys/stream.h> 72# include <sys/ptem.h> 73#endif 74 75/* 76 * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, 77 * Solaris, IRIX) define TIOCGWINSZ and struct winsize. 78 */ 79#ifdef TIOCGSIZE 80# define IOCTL_WINSIZE TIOCGSIZE 81# define STRUCT_WINSIZE struct ttysize 82# define WINSIZE_ROWS(n) (int)n.ts_lines 83# define WINSIZE_COLS(n) (int)n.ts_cols 84#else 85# ifdef TIOCGWINSZ 86# define IOCTL_WINSIZE TIOCGWINSZ 87# define STRUCT_WINSIZE struct winsize 88# define WINSIZE_ROWS(n) (int)n.ws_row 89# define WINSIZE_COLS(n) (int)n.ws_col 90# endif 91#endif 92 93static int _use_env = TRUE; 94 95static void do_prototype(void); 96 97NCURSES_EXPORT(void) 98use_env(bool f) 99{ 100 _use_env = f; 101} 102 103NCURSES_EXPORT_VAR(int) 104LINES = 0; 105NCURSES_EXPORT_VAR(int) 106COLS = 0; 107NCURSES_EXPORT_VAR(int) 108TABSIZE = 0; 109 110 static void 111 _nc_get_screensize(int *linep, int *colp) 112/* Obtain lines/columns values from the environment and/or terminfo entry */ 113{ 114 /* figure out the size of the screen */ 115 T(("screen size: terminfo lines = %d columns = %d", lines, columns)); 116 117 if (!_use_env) { 118 *linep = (int) lines; 119 *colp = (int) columns; 120 } else { /* usually want to query LINES and COLUMNS from environment */ 121 int value; 122 123 *linep = *colp = 0; 124 125 /* first, look for environment variables */ 126 if ((value = _nc_getenv_num("LINES")) > 0) { 127 *linep = value; 128 } 129 if ((value = _nc_getenv_num("COLUMNS")) > 0) { 130 *colp = value; 131 } 132 T(("screen size: environment LINES = %d COLUMNS = %d", *linep, *colp)); 133 134#ifdef __EMX__ 135 if (*linep <= 0 || *colp <= 0) { 136 int screendata[2]; 137 _scrsize(screendata); 138 *colp = screendata[0]; 139 *linep = screendata[1]; 140 T(("EMX screen size: environment LINES = %d COLUMNS = %d", 141 *linep, *colp)); 142 } 143#endif 144#if HAVE_SIZECHANGE 145 /* if that didn't work, maybe we can try asking the OS */ 146 if (*linep <= 0 || *colp <= 0) { 147 if (isatty(cur_term->Filedes)) { 148 STRUCT_WINSIZE size; 149 150 errno = 0; 151 do { 152 if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) < 0 153 && errno != EINTR) 154 goto failure; 155 } while 156 (errno == EINTR); 157 158 /* 159 * Solaris lets users override either dimension with an 160 * environment variable. 161 */ 162 if (*linep <= 0) 163 *linep = WINSIZE_ROWS(size); 164 if (*colp <= 0) 165 *colp = WINSIZE_COLS(size); 166 } 167 /* FALLTHRU */ 168 failure:; 169 } 170#endif /* HAVE_SIZECHANGE */ 171 172 /* if we can't get dynamic info about the size, use static */ 173 if (*linep <= 0) { 174 *linep = (int) lines; 175 } 176 if (*colp <= 0) { 177 *colp = (int) columns; 178 } 179 180 /* the ultimate fallback, assume fixed 24x80 size */ 181 if (*linep <= 0 || *colp <= 0) { 182 *linep = 24; 183 *colp = 80; 184 } 185 186 /* 187 * Put the derived values back in the screen-size caps, so 188 * tigetnum() and tgetnum() will do the right thing. 189 */ 190 lines = (short) (*linep); 191 columns = (short) (*colp); 192 } 193 194 T(("screen size is %dx%d", *linep, *colp)); 195 196 if (VALID_NUMERIC(init_tabs)) 197 TABSIZE = (int) init_tabs; 198 else 199 TABSIZE = 8; 200 T(("TABSIZE = %d", TABSIZE)); 201 202} 203 204#if USE_SIZECHANGE 205NCURSES_EXPORT(void) 206_nc_update_screensize(void) 207{ 208 int my_lines, my_cols; 209 210 _nc_get_screensize(&my_lines, &my_cols); 211 if (SP != 0 && SP->_resize != 0) 212 SP->_resize(my_lines, my_cols); 213} 214#endif 215 216/**************************************************************************** 217 * 218 * Terminal setup 219 * 220 ****************************************************************************/ 221 222#define ret_error(code, fmt, arg) if (errret) {\ 223 *errret = code;\ 224 returnCode(ERR);\ 225 } else {\ 226 fprintf(stderr, fmt, arg);\ 227 exit(EXIT_FAILURE);\ 228 } 229 230#define ret_error0(code, msg) if (errret) {\ 231 *errret = code;\ 232 returnCode(ERR);\ 233 } else {\ 234 fprintf(stderr, msg);\ 235 exit(EXIT_FAILURE);\ 236 } 237 238#if USE_DATABASE 239static int 240grab_entry(const char *const tn, TERMTYPE * const tp) 241/* return 1 if entry found, 0 if not found, -1 if database not accessible */ 242{ 243 char filename[PATH_MAX]; 244 int status; 245 246 /* 247 * $TERM shouldn't contain pathname delimiters. 248 */ 249 if (strchr(tn, '/')) 250 return 0; 251 252 if ((status = _nc_read_entry(tn, filename, tp)) != 1) { 253 254#if !PURE_TERMINFO 255 /* 256 * Try falling back on the termcap file. 257 * Note: allowing this call links the entire terminfo/termcap 258 * compiler into the startup code. It's preferable to build a 259 * real terminfo database and use that. 260 */ 261 status = _nc_read_termcap_entry(tn, tp); 262#endif /* PURE_TERMINFO */ 263 264 } 265 266 /* 267 * If we have an entry, force all of the cancelled strings to null 268 * pointers so we don't have to test them in the rest of the library. 269 * (The terminfo compiler bypasses this logic, since it must know if 270 * a string is cancelled, for merging entries). 271 */ 272 if (status == 1) { 273 int n; 274 for_each_boolean(n, tp) { 275 if (!VALID_BOOLEAN(tp->Booleans[n])) 276 tp->Booleans[n] = FALSE; 277 } 278 for_each_string(n, tp) { 279 if (tp->Strings[n] == CANCELLED_STRING) 280 tp->Strings[n] = ABSENT_STRING; 281 } 282 } 283 return (status); 284} 285#endif 286 287NCURSES_EXPORT_VAR(char) ttytype[NAMESIZE] = ""; 288 289/* 290 * setupterm(termname, Filedes, errret) 291 * 292 * Find and read the appropriate object file for the terminal 293 * Make cur_term point to the structure. 294 * 295 */ 296 297NCURSES_EXPORT(int) 298setupterm 299(NCURSES_CONST char *tname, int Filedes, int *errret) 300{ 301 struct term *term_ptr; 302 int status; 303 304 T((T_CALLED("setupterm(%s,%d,%p)"), _nc_visbuf(tname), Filedes, errret)); 305 306 if (tname == 0) { 307 tname = getenv("TERM"); 308 if (tname == 0 || *tname == '\0') { 309 ret_error0(-1, "TERM environment variable not set.\n"); 310 } 311 } 312 if (strlen(tname) > MAX_NAME_SIZE) { 313 ret_error(-1, "TERM environment must be <= %d characters.\n", 314 MAX_NAME_SIZE); 315 } 316 317 T(("your terminal name is %s", tname)); 318 319 term_ptr = typeCalloc(TERMINAL, 1); 320 321 if (term_ptr == 0) { 322 ret_error0(-1, "Not enough memory to create terminal structure.\n"); 323 } 324#if USE_DATABASE 325 status = grab_entry(tname, &term_ptr->type); 326#else 327 status = 0; 328#endif 329 330 /* try fallback list if entry on disk */ 331 if (status != 1) { 332 const TERMTYPE *fallback = _nc_fallback(tname); 333 334 if (fallback) { 335 term_ptr->type = *fallback; 336 status = 1; 337 } 338 } 339 340 if (status == -1) { 341 ret_error0(-1, "terminals database is inaccessible\n"); 342 } else if (status == 0) { 343 ret_error(0, "'%s': unknown terminal type.\n", tname); 344 } 345 346 /* 347 * Improve on SVr4 curses. If an application mixes curses and termcap 348 * calls, it may call both initscr and tgetent. This is not really a 349 * good thing to do, but can happen if someone tries using ncurses with 350 * the readline library. The problem we are fixing is that when 351 * tgetent calls setupterm, the resulting Ottyb struct in cur_term is 352 * zeroed. A subsequent call to endwin uses the zeroed terminal 353 * settings rather than the ones saved in initscr. So we check if 354 * cur_term appears to contain terminal settings for the same output 355 * file as our current call - and copy those terminal settings. (SVr4 356 * curses does not do this, however applications that are working 357 * around the problem will still work properly with this feature). 358 */ 359 if (cur_term != 0) { 360 if (cur_term->Filedes == Filedes) 361 term_ptr->Ottyb = cur_term->Ottyb; 362 } 363 364 set_curterm(term_ptr); 365 366 if (command_character && getenv("CC")) 367 do_prototype(); 368 369 strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1); 370 ttytype[NAMESIZE - 1] = '\0'; 371 372 /* 373 * Allow output redirection. This is what SVr3 does. 374 * If stdout is directed to a file, screen updates go 375 * to standard error. 376 */ 377 if (Filedes == STDOUT_FILENO && !isatty(Filedes)) 378 Filedes = STDERR_FILENO; 379 cur_term->Filedes = Filedes; 380 381 _nc_get_screensize(&LINES, &COLS); 382 383 if (errret) 384 *errret = 1; 385 386 T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS)); 387 388 if (generic_type) { 389 ret_error(0, "'%s': I need something more specific.\n", tname); 390 } 391 if (hard_copy) { 392 ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname); 393 } 394 returnCode(OK); 395} 396 397/* 398** do_prototype() 399** 400** Take the real command character out of the CC environment variable 401** and substitute it in for the prototype given in 'command_character'. 402** 403*/ 404 405static void 406do_prototype(void) 407{ 408 int i; 409 char CC; 410 char proto; 411 char *tmp; 412 413 tmp = getenv("CC"); 414 CC = *tmp; 415 proto = *command_character; 416 417 for_each_string(i, &(cur_term->type)) { 418 for (tmp = cur_term->type.Strings[i]; *tmp; tmp++) { 419 if (*tmp == proto) 420 *tmp = CC; 421 } 422 } 423} 424