1 /* $OpenBSD: lib_setup.c,v 1.1 1999/01/18 19:10:19 millert Exp $ */ 2 3 /**************************************************************************** 4 * Copyright (c) 1998 Free Software Foundation, Inc. * 5 * * 6 * Permission is hereby granted, free of charge, to any person obtaining a * 7 * copy of this software and associated documentation files (the * 8 * "Software"), to deal in the Software without restriction, including * 9 * without limitation the rights to use, copy, modify, merge, publish, * 10 * distribute, distribute with modifications, sublicense, and/or sell * 11 * copies of the Software, and to permit persons to whom the Software is * 12 * furnished to do so, subject to the following conditions: * 13 * * 14 * The above copyright notice and this permission notice shall be included * 15 * in all copies or substantial portions of the Software. * 16 * * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 20 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 23 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 24 * * 25 * Except as contained in this notice, the name(s) of the above copyright * 26 * holders shall not be used in advertising or otherwise to promote the * 27 * sale, use or other dealings in this Software without prior written * 28 * authorization. * 29 ****************************************************************************/ 30 31 /**************************************************************************** 32 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 33 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 34 ****************************************************************************/ 35 36 37 /* 38 * Terminal setup routines common to termcap and terminfo: 39 * 40 * use_env(bool) 41 * setupterm(char *, int, int *) 42 */ 43 44 #include <curses.priv.h> 45 #include <tic.h> /* for MAX_NAME_SIZE */ 46 47 #if defined(SVR4_TERMIO) && !defined(_POSIX_SOURCE) 48 #define _POSIX_SOURCE 49 #endif 50 51 #include <term.h> /* lines, columns, cur_term */ 52 53 MODULE_ID("$From: lib_setup.c,v 1.48 1999/01/02 23:11:56 tom Exp $") 54 55 /**************************************************************************** 56 * 57 * Terminal size computation 58 * 59 ****************************************************************************/ 60 61 #if HAVE_SIZECHANGE 62 # if !defined(sun) || !TERMIOS 63 # if HAVE_SYS_IOCTL_H 64 # include <sys/ioctl.h> 65 # endif 66 # endif 67 #endif 68 69 #if NEED_PTEM_H 70 /* On SCO, they neglected to define struct winsize in termios.h -- it's only 71 * in termio.h and ptem.h (the former conflicts with other definitions). 72 */ 73 # include <sys/stream.h> 74 # include <sys/ptem.h> 75 #endif 76 77 /* 78 * SCO defines TIOCGSIZE and the corresponding struct. Other systems (SunOS, 79 * Solaris, IRIX) define TIOCGWINSZ and struct winsize. 80 */ 81 #ifdef TIOCGSIZE 82 # define IOCTL_WINSIZE TIOCGSIZE 83 # define STRUCT_WINSIZE struct ttysize 84 # define WINSIZE_ROWS(n) (int)n.ts_lines 85 # define WINSIZE_COLS(n) (int)n.ts_cols 86 #else 87 # ifdef TIOCGWINSZ 88 # define IOCTL_WINSIZE TIOCGWINSZ 89 # define STRUCT_WINSIZE struct winsize 90 # define WINSIZE_ROWS(n) (int)n.ws_row 91 # define WINSIZE_COLS(n) (int)n.ws_col 92 # endif 93 #endif 94 95 static int _use_env = TRUE; 96 97 static void do_prototype(void); 98 99 void use_env(bool f) 100 { 101 _use_env = f; 102 } 103 104 int LINES, COLS, TABSIZE; 105 106 static void _nc_get_screensize(int *linep, int *colp) 107 /* Obtain lines/columns values from the environment and/or terminfo entry */ 108 { 109 /* figure out the size of the screen */ 110 T(("screen size: terminfo lines = %d columns = %d", lines, columns)); 111 112 if (!_use_env) 113 { 114 *linep = (int)lines; 115 *colp = (int)columns; 116 } 117 else /* usually want to query LINES and COLUMNS from environment */ 118 { 119 int value; 120 121 *linep = *colp = 0; 122 123 /* first, look for environment variables */ 124 if ((value = _nc_getenv_num("LINES")) > 0) { 125 *linep = value; 126 } 127 if ((value = _nc_getenv_num("COLUMNS")) > 0) { 128 *colp = value; 129 } 130 T(("screen size: environment LINES = %d COLUMNS = %d",*linep,*colp)); 131 132 #ifdef __EMX__ 133 if (*linep <= 0 || *colp <= 0) 134 { 135 int screendata[2]; 136 _scrsize(screendata); 137 *colp = screendata[0]; 138 *linep = screendata[1]; 139 T(("EMX screen size: environment LINES = %d COLUMNS = %d",*linep,*colp)); 140 } 141 #endif 142 #if HAVE_SIZECHANGE 143 /* if that didn't work, maybe we can try asking the OS */ 144 if (*linep <= 0 || *colp <= 0) 145 { 146 if (isatty(cur_term->Filedes)) 147 { 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 || *colp <= 0) 174 if (lines > 0 && columns > 0) 175 { 176 *linep = (int)lines; 177 *colp = (int)columns; 178 } 179 180 /* the ultimate fallback, assume fixed 24x80 size */ 181 if (*linep <= 0 || *colp <= 0) 182 { 183 *linep = 24; 184 *colp = 80; 185 } 186 187 /* 188 * Put the derived values back in the screen-size caps, so 189 * tigetnum() and tgetnum() will do the right thing. 190 */ 191 lines = (short)(*linep); 192 columns = (short)(*colp); 193 } 194 195 T(("screen size is %dx%d", *linep, *colp)); 196 197 if (init_tabs != -1) 198 TABSIZE = (int)init_tabs; 199 else 200 TABSIZE = 8; 201 T(("TABSIZE = %d", TABSIZE)); 202 203 } 204 205 #if USE_SIZECHANGE 206 void _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 239 static int grab_entry(const char *const tn, TERMTYPE *const tp) 240 /* return 1 if entry found, 0 if not found, -1 if database not accessible */ 241 { 242 char filename[PATH_MAX]; 243 int status = 0; 244 int _nc_read_bsd_terminfo_entry(const char *, TERMTYPE *); /* XXX */ 245 246 #ifdef __OpenBSD__ 247 status = _nc_read_bsd_terminfo_entry(tn, tp); 248 #endif /* __OpenBSD__ */ 249 250 if (status != 1 && (status = _nc_read_entry(tn, filename, tp)) != 1) { 251 252 #ifndef PURE_TERMINFO 253 /* 254 * Try falling back on the termcap file. 255 * Note: allowing this call links the entire terminfo/termcap 256 * compiler into the startup code. It's preferable to build a 257 * real terminfo database and use that. 258 */ 259 status = _nc_read_termcap_entry(tn, tp); 260 #endif /* PURE_TERMINFO */ 261 262 } 263 264 /* 265 * If we have an entry, force all of the cancelled strings to null 266 * pointers so we don't have to test them in the rest of the library. 267 * (The terminfo compiler bypasses this logic, since it must know if 268 * a string is cancelled, for merging entries). 269 */ 270 if (status == 1) { 271 unsigned n; 272 for (n = 0; n < BOOLCOUNT; n++) 273 if (!VALID_BOOLEAN(tp->Booleans[n])) 274 tp->Booleans[n] = FALSE; 275 for (n = 0; n < STRCOUNT; n++) 276 if (tp->Strings[n] == CANCELLED_STRING) 277 tp->Strings[n] = ABSENT_STRING; 278 } 279 return(status); 280 } 281 #endif 282 283 char ttytype[NAMESIZE]; 284 285 /* 286 * setupterm(termname, Filedes, errret) 287 * 288 * Find and read the appropriate object file for the terminal 289 * Make cur_term point to the structure. 290 * 291 */ 292 293 int setupterm(NCURSES_CONST char *tname, int Filedes, int *errret) 294 { 295 struct term *term_ptr; 296 int status; 297 298 T((T_CALLED("setupterm(\"%s\",%d,%p)"), tname, Filedes, errret)); 299 300 if (tname == 0) { 301 tname = getenv("TERM"); 302 if (tname == 0 || *tname == '\0') { 303 ret_error0(-1, "TERM environment variable not set.\n"); 304 } 305 } 306 if (strlen(tname) > MAX_NAME_SIZE) { 307 ret_error(-1, "TERM environment must be <= %d characters.\n", 308 MAX_NAME_SIZE); 309 } 310 311 T(("your terminal name is %s", tname)); 312 313 term_ptr = typeCalloc(TERMINAL, 1); 314 315 if (term_ptr == 0) { 316 ret_error0(-1, "Not enough memory to create terminal structure.\n") ; 317 } 318 #if USE_DATABASE 319 status = grab_entry(tname, &term_ptr->type); 320 #else 321 status = 0; 322 #endif 323 324 /* try fallback list if entry on disk */ 325 if (status != 1) 326 { 327 const TERMTYPE *fallback = _nc_fallback(tname); 328 329 if (fallback) 330 { 331 memcpy(&term_ptr->type, fallback, sizeof(TERMTYPE)); 332 status = 1; 333 } 334 } 335 336 if (status == -1) 337 { 338 ret_error0(-1, "terminals database is inaccessible\n"); 339 } 340 else if (status == 0) 341 { 342 ret_error(0, "'%s': unknown terminal type.\n", tname); 343 } 344 345 set_curterm(term_ptr); 346 347 if (command_character && getenv("CC")) 348 do_prototype(); 349 350 strlcpy(ttytype, cur_term->type.term_names, NAMESIZE); 351 352 /* 353 * Allow output redirection. This is what SVr3 does. 354 * If stdout is directed to a file, screen updates go 355 * to standard error. 356 */ 357 if (Filedes == STDOUT_FILENO && !isatty(Filedes)) 358 Filedes = STDERR_FILENO; 359 cur_term->Filedes = Filedes; 360 361 _nc_get_screensize(&LINES, &COLS); 362 363 if (errret) 364 *errret = 1; 365 366 T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS)); 367 368 if (generic_type) { 369 ret_error(0, "'%s': I need something more specific.\n", tname); 370 } 371 if (hard_copy) { 372 ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname); 373 } 374 returnCode(OK); 375 } 376 377 /* 378 ** do_prototype() 379 ** 380 ** Take the real command character out of the CC environment variable 381 ** and substitute it in for the prototype given in 'command_character'. 382 ** 383 */ 384 385 static void 386 do_prototype(void) 387 { 388 int i, j; 389 char CC; 390 char proto; 391 char *tmp; 392 393 tmp = getenv("CC"); 394 CC = *tmp; 395 proto = *command_character; 396 397 for (i=0; i < STRCOUNT; i++) { 398 j = 0; 399 while (cur_term->type.Strings[i][j]) { 400 if (cur_term->type.Strings[i][j] == proto) 401 cur_term->type.Strings[i][j] = CC; 402 j++; 403 } 404 } 405 } 406