1 /* $NetBSD: termcap.c,v 1.17 2011/11/13 15:24:04 christos Exp $ */
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: termcap.c,v 1.17 2011/11/13 15:24:04 christos Exp $");
38 #include <term_private.h>
44 #include "termcap_map.c"
45 #include "termcap_hash.c"
52 tgetent(__unused
char *bp
, const char *name
)
55 static TERMINAL
*last
= NULL
;
57 _DIAGASSERT(name
!= NULL
);
59 /* Free the old term */
65 if (setupterm(name
, STDOUT_FILENO
, &errret
) != 0)
71 UP
= __UNCONST(cursor_up
);
72 BC
= __UNCONST(cursor_left
);
77 tgetflag(const char *id2
)
82 const char id
[] = { id2
[0], id2
[0] ? id2
[1] : '\0', '\0' };
87 ind
= _t_flaghash((const unsigned char *)id
, strlen(id
));
88 if (ind
<= __arraycount(_ti_cap_flagids
)) {
89 if (strcmp(id
, _ti_cap_flagids
[ind
].id
) == 0)
90 return cur_term
->flags
[_ti_cap_flagids
[ind
].ti
];
92 for (i
= 0; i
< cur_term
->_nuserdefs
; i
++) {
93 ud
= &cur_term
->_userdefs
[i
];
94 if (ud
->type
== 'f' && strcmp(ud
->id
, id
) == 0)
101 tgetnum(const char *id2
)
107 const char id
[] = { id2
[0], id2
[0] ? id2
[1] : '\0', '\0' };
109 if (cur_term
== NULL
)
112 ind
= _t_numhash((const unsigned char *)id
, strlen(id
));
113 if (ind
<= __arraycount(_ti_cap_numids
)) {
114 te
= &_ti_cap_numids
[ind
];
115 if (strcmp(id
, te
->id
) == 0) {
116 if (!VALID_NUMERIC(cur_term
->nums
[te
->ti
]))
117 return ABSENT_NUMERIC
;
118 return cur_term
->nums
[te
->ti
];
121 for (i
= 0; i
< cur_term
->_nuserdefs
; i
++) {
122 ud
= &cur_term
->_userdefs
[i
];
123 if (ud
->type
== 'n' && strcmp(ud
->id
, id
) == 0) {
124 if (!VALID_NUMERIC(ud
->num
))
125 return ABSENT_NUMERIC
;
133 tgetstr(const char *id2
, char **area
)
139 const char id
[] = { id2
[0], id2
[0] ? id2
[1] : '\0', '\0' };
141 if (cur_term
== NULL
)
145 ind
= _t_strhash((const unsigned char *)id
, strlen(id
));
146 if (ind
<= __arraycount(_ti_cap_strids
)) {
147 if (strcmp(id
, _ti_cap_strids
[ind
].id
) == 0) {
148 str
= cur_term
->strs
[_ti_cap_strids
[ind
].ti
];
154 for (i
= 0; i
< cur_term
->_nuserdefs
; i
++) {
155 ud
= &cur_term
->_userdefs
[i
];
156 if (ud
->type
== 's' && strcmp(ud
->id
, id
) == 0)
161 * We should fix sgr0(me) as it has a slightly different meaning
164 if (str
!= NULL
&& area
!= NULL
&& *area
!= NULL
) {
168 *area
+= strlen(*area
) + 1;
172 return __UNCONST(str
);
176 tgoto(const char *cm
, int destcol
, int destline
)
178 _DIAGASSERT(cm
!= NULL
);
179 return tiparm(cm
, destline
, destcol
);
183 flagname(const char *key
)
187 idx
= _t_flaghash((const unsigned char *)key
, strlen(key
));
188 if (idx
<= __arraycount(_ti_cap_flagids
) &&
189 strcmp(key
, _ti_cap_flagids
[idx
].id
) == 0)
190 return _ti_flagid(_ti_cap_flagids
[idx
].ti
);
195 numname(const char *key
)
199 idx
= _t_numhash((const unsigned char *)key
, strlen(key
));
200 if (idx
<= __arraycount(_ti_cap_numids
) &&
201 strcmp(key
, _ti_cap_numids
[idx
].id
) == 0)
202 return _ti_numid(_ti_cap_numids
[idx
].ti
);
207 strname(const char *key
)
211 idx
= _t_strhash((const unsigned char *)key
, strlen(key
));
212 if (idx
<= __arraycount(_ti_cap_strids
) &&
213 strcmp(key
, _ti_cap_strids
[idx
].id
) == 0)
214 return _ti_strid(_ti_cap_strids
[idx
].ti
);
216 if (strcmp(key
, "tc") == 0)
222 /* Print a parameter if needed */
224 printparam(char **dst
, char p
, int *nop
)
237 /* Convert a termcap character into terminfo equivalents */
239 printchar(char **dst
, const char **src
)
245 v
= (unsigned char) *++(*src
);
247 v
= (unsigned char) *++(*src
);
254 while (isdigit((unsigned char) **src
))
255 v
= 8 * v
+ ((unsigned char) *(*src
)++ - '0');
263 v
= (unsigned char) (*++(*src
) & 0x1f);
265 if (isgraph(v
) && v
!= ',' && v
!= '\'' && v
!= '\\' && v
!= ':') {
272 *(*dst
)++ = '0'+ v
/ 100;
276 *(*dst
)++ = '0' + ((int) (v
/ 10)) % 10;
279 *(*dst
)++ = '0' + v
% 10;
285 /* Convert termcap commands into terminfo commands */
286 static const char fmtB
[] = "%p0%{10}%/%{16}%*%p0%{10}%m%+";
287 static const char fmtD
[] = "%p0%p0%{2}%*%-";
288 static const char fmtIf
[] = "%p0%p0%?";
289 static const char fmtThen
[] = "%>%t";
290 static const char fmtElse
[] = "%+%;";
293 strval(const char *val
)
300 len
= 1024; /* no single string should be bigger */
301 info
= ip
= malloc(len
);
308 /* Set ps and pe to point to the start and end of the padding */
309 if (isdigit((unsigned char)*val
)) {
311 isdigit((unsigned char)*val
) || *val
== '.';
323 for (; *val
!= '\0'; val
++) {
337 switch (c
= *++(val
)) {
339 if (l
+ sizeof(fmtB
) > len
)
341 memcpy(ip
, fmtB
, sizeof(fmtB
) - 1);
342 /* Replace the embedded parameters with real ones */
345 ip
+= sizeof(fmtB
) - 1;
346 l
+= sizeof(fmtB
) - 1;
350 if (l
+ sizeof(fmtD
) > len
)
352 memcpy(ip
, fmtD
, sizeof(fmtD
) - 1);
353 /* Replace the embedded parameters with real ones */
356 ip
+= sizeof(fmtD
) - 1;
357 l
+= sizeof(fmtD
) - 1;
361 /* non op as switched below */
363 case '2': /* FALLTHROUGH */
364 case '3': /* FALLTHROUGH */
368 l
+= printparam(&ip
, p
, &nop
);
380 l
+= printparam(&ip
, p
, &nop
);
381 l
+= printchar(&ip
, &val
);
389 if (l
+ sizeof(fmtIf
) + sizeof(fmtThen
) +
390 sizeof(fmtElse
) + (6 * 2) > len
)
393 memcpy(ip
, fmtIf
, sizeof(fmtIf
) - 1);
394 /* Replace the embedded parameters with real ones */
397 ip
+= sizeof(fmtIf
) - 1;
398 l
+= sizeof(fmtIf
) - 1;
399 l
+= printchar(&ip
, &val
);
400 memcpy(ip
, fmtThen
, sizeof(fmtThen
) - 1);
401 ip
+= sizeof(fmtThen
) - 1;
402 l
+= sizeof(fmtThen
) - 1;
403 l
+= printchar(&ip
, &val
);
404 memcpy(ip
, fmtElse
, sizeof(fmtElse
) - 1);
405 ip
+= sizeof(fmtElse
) - 1;
406 l
+= sizeof(fmtElse
) - 1;
413 l
+= printparam(&ip
, p
, &nop
);
419 /* Hope it matches a terminfo command. */
431 /* \E\ is valid termcap.
432 * We need to escape the final \ for terminfo. */
433 if (l
> 2 && info
[l
- 1] == '\\' &&
434 (info
[l
- 2] != '\\' && info
[l
- 2] != '^'))
441 /* Add our padding at the end. */
468 static DEF_INFO def_infos
[] = {
483 char *info
, *ip
, *token
, *val
, *p
, tok
[3];
485 size_t len
, lp
, nl
, vl
, rl
;
486 int defs
[__arraycount(def_infos
)], fv
;
488 _DIAGASSERT(cap
!= NULL
);
490 len
= strlen(cap
) * 2;
491 len
+= __arraycount(def_infos
) * (5 + 4 + 3); /* reserve for defs */
492 info
= ip
= malloc(len
);
496 memset(defs
, 0, sizeof(defs
));
499 for (token
= _ti_get_token(&cap
, ':');
501 token
= _ti_get_token(&cap
, ':'))
503 if (token
[0] == '\0')
508 if (token
[1] != '\0') {
512 if (token
[2] == '\0') {
513 name
= flagname(tok
);
515 } else if (token
[2] == '#') {
518 } else if (token
[2] == '=') {
520 val
= strval(token
+ 2);
525 /* If not matched we may need to convert padding still. */
527 p
= strchr(name
, '=');
535 /* See if this sets a default. */
536 for (nl
= 0; nl
< __arraycount(def_infos
); nl
++) {
537 if (strcmp(name
, def_infos
[nl
].name
) == 0) {
548 rl
= nl
+ vl
+ 3; /* , \0 */
555 p
= realloc(info
, len
);
576 /* Add any defaults not set above. */
577 for (nl
= 0; nl
< __arraycount(def_infos
); nl
++) {
581 strcpy(ip
, def_infos
[nl
].name
);
582 ip
+= strlen(def_infos
[nl
].name
);
584 strcpy(ip
, def_infos
[nl
].cap
);
585 ip
+= strlen(def_infos
[nl
].cap
);