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__)
_Getsh(register char * p)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__)
tidbit(char * term,char * cap,...)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__)
untidbit(char * term)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__)
open_terminfo_file(char * terminfo,char * term)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