1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.12 */ 32 33 #include "errno.h" 34 #include "string.h" 35 #include "sys/types.h" 36 #include "sys/stat.h" 37 38 #if defined(__STDC__) 39 #include "stdarg.h" 40 #else 41 #include "varargs.h" 42 #endif 43 44 #include "lp.h" 45 46 extern char *boolnames[], 47 *numnames[], 48 *stringnames[]; 49 50 extern char *getenv(); 51 52 ushort tidbit_boolean = 0; 53 54 short tidbit_number = 0; 55 56 char *tidbit_string = 0; 57 58 #if defined(__STDC__) 59 static int open_terminfo_file ( char * , char * ); 60 #else 61 static int open_terminfo_file(); 62 #endif 63 64 /** 65 ** _Getsh() - GET TWO-BYTE SHORT FROM (char *) POINTER PORTABLY 66 **/ 67 68 /* 69 * "function" to get a short from a pointer. The short is in a standard 70 * format: two bytes, the first is the low order byte, the second is 71 * the high order byte (base 256). The only negative number allowed is 72 * -1, which is represented as 255, 255. This format happens to be the 73 * same as the hardware on the pdp-11 and vax, making it fast and 74 * convenient and small to do this on a pdp-11. 75 */ 76 77 #if vax || pdp11 || i386 78 #define _Getsh(ip) (*((short *)((char *)(ip)))) 79 #endif /* vax || pdp11 || i386 */ 80 81 /* 82 * The following macro is partly due to Mike Laman, laman@sdcsvax 83 * NCR @ Torrey Pines. - Tony Hansen 84 */ 85 #if u3b || u3b15 || u3b2 || m68000 || sparc 86 #define _Getsh(ip) ((short) (*((unsigned char *) ip) | (*(ip+1) << 8))) 87 #endif /* u3b || u3b15 || u3b2 || m68000 || sparc */ 88 89 #ifndef _Getsh 90 /* 91 * Here is a more portable version, which does not assume byte ordering 92 * in shorts, sign extension, etc. It does assume that the C preprocessor 93 * does sign-extension the same as on the machine being compiled for. 94 * When ANSI C comes along, this should be changed to check <limits.h> 95 * to see if the low character value is negative. 96 */ 97 98 static int 99 #if defined(__STDC__) 100 _Getsh ( 101 register char * p 102 ) 103 #else 104 _Getsh (p) 105 register char *p; 106 #endif 107 { 108 register int rv, 109 rv2; 110 111 #if -1 == '\377' /* sign extension occurs */ 112 rv = (*p++) & 0377; 113 rv2 = (*p) & 0377; 114 #else /* -1 == '\377' */ /* no sign extension */ 115 rv = *p++; 116 rv2 = *p; 117 #endif /* -1 == '\377' */ 118 if ((rv2 == 0377) && ((rv == 0377) || (rv == 0376))) 119 return (-1); 120 return (rv + (rv2 * 256)); 121 } 122 #endif /* _Getsh */ 123 124 #define MAX_TIDBS 32 125 126 static struct tidb { 127 128 int snames, 129 nbools, 130 nints, 131 nstrs; 132 133 char *term, 134 *tiebuf, 135 *boolean_offset, 136 *number_offset, 137 *string_offset, 138 *string_table; 139 140 } tidbs[MAX_TIDBS + 1]; /* one for last ditch */ 141 142 /** 143 ** tidbit() - TERMINFO DATABASE LOOKUP 144 **/ 145 146 /* 147 * Four forms of calling: 148 * 149 * tidbit ("term-type", "boolean-cap-name", &ushort) 150 * tidbit ("term-type", "numeric-cap-name", &short) 151 * tidbit ("term-type", "string-cap-name", &charstar) 152 * tidbit ("term-type", "any-cap-name", (char *)0) 153 * 154 * The last one is chancy, because of the pointer alignment 155 * problem, but hey--what the heck. Anyway, the last one 156 * causes the value to be stored in one of 157 * 158 * ushort tidbit_boolean; 159 * short tidbit_number; 160 * char *tidbit_string; 161 * 162 * as appropriate, and returns one of 1, 2, or 3 as the type 163 * of the capability is boolean, numeric, or string. 164 * 165 * For example, to extract the size of the screen for a 5410: 166 * 167 * short cols, lines; 168 * 169 * tidbit ("5410", "cols", &cols); 170 * tidbit ("5410", "lines", &lines); 171 * 172 * Note that for the lines and columns, this does NOT check 173 * the LINES and COLUMNS environment variables nor the window 174 * size, if running on a windowing terminal. That can be done 175 * by the caller. 176 * 177 * If first argument is (char *)0, "tidbit()" uses the same TERM 178 * used in the last call, or the TERM environment variable if this 179 * is the first call. 180 * If second argument is (char *)0, no lookup just verification 181 * of terminal type. 182 * 183 * Return is 0 (or 1, 2, 3 as above) if successful, otherwise -1 184 * with "errno" set: 185 * 186 * ENOENT can't open Terminfo file for terminal type 187 * EBADF Terminfo file is corrupted 188 * ENOMEM malloc failed 189 */ 190 191 /*VARARGS2*/ 192 int 193 #if defined(__STDC__) 194 tidbit ( 195 char * term, 196 char * cap, 197 ... 198 ) 199 #else 200 tidbit (term, cap, va_alist) 201 char *term, 202 *cap; 203 va_dcl 204 #endif 205 { 206 va_list ap; 207 208 int rc; 209 210 register int i; 211 212 register char **pp; 213 214 register struct tidb *pt; 215 216 static char *last_term; 217 218 219 if (!term) 220 if (last_term) 221 term = last_term; 222 else { 223 term = getenv("TERM"); 224 if (!term || !*term) 225 term = NAME_UNKNOWN; 226 } 227 if (term != last_term) { 228 if (last_term) 229 Free (last_term); 230 last_term = Strdup(term); 231 } 232 233 for (i = 0; i < MAX_TIDBS; i++) 234 if (tidbs[i].term && STREQU(tidbs[i].term, term)) { 235 pt = &tidbs[i]; 236 break; 237 } 238 239 /* 240 * Not cached, so read the file and cache it. 241 */ 242 if (i >= MAX_TIDBS) { 243 244 register int n, 245 tfd; 246 247 register char *terminfo; 248 249 struct stat statbuf; 250 251 252 /* 253 * If no empty spot can be found, "i" will index the 254 * last spot, a spare reserved to avoid problems with 255 * a full cache. 256 */ 257 for (i = 0; i < MAX_TIDBS; i++) 258 if (!tidbs[i].term) 259 break; 260 pt = &tidbs[i]; 261 262 tfd = -1; 263 if ((terminfo = getenv("TERMINFO")) && *terminfo) 264 tfd = open_terminfo_file(terminfo, term); 265 #if defined(TERMINFO) 266 if (tfd < 0) 267 tfd = open_terminfo_file(TERMINFO, term); 268 #endif 269 if (tfd >= 0) 270 (void)Fstat (tfd, &statbuf); 271 272 if (tfd < 0 || !statbuf.st_size) { 273 errno = ENOENT; 274 return (-1); 275 } 276 277 if (pt->tiebuf) 278 Free (pt->tiebuf); 279 if (!(pt->tiebuf = Malloc(statbuf.st_size))) { 280 errno = ENOMEM; 281 return (-1); 282 } 283 284 n = Read(tfd, pt->tiebuf, statbuf.st_size); 285 (void)Close (tfd); 286 if (n <= 0 || n >= 4096 || _Getsh(pt->tiebuf) != 0432) { 287 Free (pt->tiebuf); 288 pt->tiebuf = 0; 289 errno = EBADF; 290 return (-1); 291 } 292 293 if (pt->term) 294 Free (pt->term); 295 if (!(pt->term = Strdup(term))) { 296 Free (pt->tiebuf); 297 pt->tiebuf = 0; 298 errno = ENOMEM; 299 return (-1); 300 } 301 302 pt->snames = _Getsh(pt->tiebuf + 2); 303 pt->nbools = _Getsh(pt->tiebuf + 4); 304 pt->nints = _Getsh(pt->tiebuf + 6); 305 pt->nstrs = _Getsh(pt->tiebuf + 8); 306 307 pt->boolean_offset = pt->tiebuf + 6 * 2 + pt->snames; 308 309 pt->number_offset = pt->boolean_offset + pt->nbools; 310 if ((unsigned int)pt->number_offset & 1) 311 pt->number_offset++; 312 313 pt->string_offset = pt->number_offset + pt->nints * 2; 314 315 pt->string_table = pt->string_offset + pt->nstrs * 2; 316 317 } 318 319 rc = 0; 320 321 #if defined(__STDC__) 322 va_start (ap, cap); 323 #else 324 va_start (ap); 325 #endif 326 327 if (!cap || !*cap) 328 ; 329 330 else if ((pp = wherelist(cap, boolnames))) { 331 register ushort *ushort_p; 332 333 register char *ip; 334 335 register int index = pp - boolnames; 336 337 if (!(ushort_p = va_arg(ap, ushort *))) { 338 ushort_p = &tidbit_boolean; 339 rc = 1; 340 } 341 342 if (index >= pt->nbools) 343 *ushort_p = 0; 344 else { 345 ip = pt->boolean_offset + index; 346 *ushort_p = (*ip & 01); 347 } 348 349 } else if ((pp = wherelist(cap, numnames))) { 350 register short *short_p; 351 352 register char *ip; 353 354 register int index = pp - numnames; 355 356 if (!(short_p = va_arg(ap, short *))) { 357 short_p = &tidbit_number; 358 rc = 2; 359 } 360 361 if (index >= pt->nints) 362 *short_p = -1; 363 else { 364 ip = pt->number_offset + index * 2; 365 *short_p = _Getsh(ip); 366 if (*short_p == -2) 367 *short_p = -1; 368 } 369 370 } else if ((pp = wherelist(cap, stringnames))) { 371 register char **charstar_p; 372 373 register char *ip; 374 375 register int index = pp - stringnames; 376 377 register short sindex; 378 379 380 if (!(charstar_p = va_arg(ap, char **))) { 381 charstar_p = &tidbit_string; 382 rc = 3; 383 } 384 385 if (index >= pt->nstrs) 386 *charstar_p = 0; 387 else { 388 ip = pt->string_offset + index * 2; 389 if ((sindex = _Getsh(ip)) >= 0) 390 *charstar_p = pt->string_table + sindex; 391 else 392 *charstar_p = 0; 393 } 394 } 395 396 va_end (ap); 397 return (rc); 398 } 399 400 /** 401 ** untidbit() - FREE SPACE ASSOCIATED WITH A TERMINFO ENTRY 402 **/ 403 404 void 405 #if defined(__STDC__) 406 untidbit ( 407 char * term 408 ) 409 #else 410 untidbit (term) 411 char *term; 412 #endif 413 { 414 register int i; 415 416 417 for (i = 0; i < MAX_TIDBS; i++) 418 if (tidbs[i].term && STREQU(tidbs[i].term, term)) { 419 if (tidbs[i].tiebuf) { 420 Free (tidbs[i].tiebuf); 421 tidbs[i].tiebuf = 0; 422 } 423 Free (tidbs[i].term); 424 tidbs[i].term = 0; 425 break; 426 } 427 return; 428 } 429 430 /** 431 ** open_terminfo_file() - OPEN FILE FOR TERM ENTRY 432 **/ 433 434 static int 435 #if defined(__STDC__) 436 open_terminfo_file ( 437 char * terminfo, 438 char * term 439 ) 440 #else 441 open_terminfo_file (terminfo, term) 442 char *terminfo, 443 *term; 444 #endif 445 { 446 char *first_letter = "X", 447 *path; 448 449 int fd; 450 451 first_letter[0] = term[0]; 452 path = makepath(terminfo, first_letter, term, (char *)0); 453 454 /* start fix for bugid 1109709 */ 455 if (path == NULL) { 456 return -1; 457 } 458 /* end fix for bugid 1109709 */ 459 460 fd = Open(path, 0); 461 Free (path); 462 return (fd); 463 } 464