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