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