xref: /illumos-gate/usr/src/cmd/lp/lib/lp/tidbit.c (revision 3db86aab)
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