Home | History | Annotate | Download | only in lp
      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