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