1 /* $NetBSD: compile.c,v 1.8 2012/06/03 23:19:10 joerg Exp $ */
4 * Copyright (c) 2009, 2010, 2011 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 #if HAVE_NBTOOL_CONFIG_H
31 #include "nbtool_config.h"
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: compile.c,v 1.8 2012/06/03 23:19:10 joerg Exp $");
37 #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
38 #include <sys/endian.h>
51 #include <term_private.h>
54 static void __printflike(2, 3)
55 dowarn(int flags
, const char *fmt
, ...)
60 if (flags
& TIC_WARNING
) {
68 _ti_grow_tbuf(TBUF
*tbuf
, size_t len
)
73 _DIAGASSERT(tbuf
!= NULL
);
75 l
= tbuf
->bufpos
+ len
;
76 if (l
> tbuf
->buflen
) {
77 if (tbuf
->buflen
== 0)
80 buf
= realloc(tbuf
->buf
, l
);
90 _ti_find_cap(TBUF
*tbuf
, char type
, short ind
)
96 _DIAGASSERT(tbuf
!= NULL
);
99 for (n
= tbuf
->entries
; n
> 0; n
--) {
101 cap
+= sizeof(uint16_t);
109 cap
+= sizeof(uint16_t);
113 cap
+= sizeof(uint16_t);
124 _ti_find_extra(TBUF
*tbuf
, const char *code
)
130 _DIAGASSERT(tbuf
!= NULL
);
131 _DIAGASSERT(code
!= NULL
);
134 for (n
= tbuf
->entries
; n
> 0; n
--) {
136 cap
+= sizeof(uint16_t);
137 if (strcmp(cap
, code
) == 0)
145 cap
+= sizeof(uint16_t);
149 cap
+= sizeof(uint16_t);
160 _ti_store_extra(TIC
*tic
, int wrn
, char *id
, char type
, char flag
, short num
,
161 char *str
, size_t strl
, int flags
)
165 _DIAGASSERT(tic
!= NULL
);
167 if (strcmp(id
, "use") != 0) {
168 if (_ti_find_extra(&tic
->extras
, id
) != NULL
)
170 if (!(flags
& TIC_EXTRA
)) {
172 dowarn(flags
, "%s: %s: unknown capability",
179 if (l
> UINT16_T_MAX
) {
180 dowarn(flags
, "%s: %s: cap name is too long", tic
->name
, id
);
184 if (!_ti_grow_tbuf(&tic
->extras
,
185 l
+ strl
+ (sizeof(uint16_t) * 2) + 1))
187 le16enc(tic
->extras
.buf
+ tic
->extras
.bufpos
, l
);
188 tic
->extras
.bufpos
+= sizeof(uint16_t);
189 memcpy(tic
->extras
.buf
+ tic
->extras
.bufpos
, id
, l
);
190 tic
->extras
.bufpos
+= l
;
191 tic
->extras
.buf
[tic
->extras
.bufpos
++] = type
;
194 tic
->extras
.buf
[tic
->extras
.bufpos
++] = flag
;
197 le16enc(tic
->extras
.buf
+ tic
->extras
.bufpos
, num
);
198 tic
->extras
.bufpos
+= sizeof(uint16_t);
201 le16enc(tic
->extras
.buf
+ tic
->extras
.bufpos
, strl
);
202 tic
->extras
.bufpos
+= sizeof(uint16_t);
203 memcpy(tic
->extras
.buf
+ tic
->extras
.bufpos
, str
, strl
);
204 tic
->extras
.bufpos
+= strl
;
207 tic
->extras
.entries
++;
212 _ti_flatten(uint8_t **buf
, const TIC
*tic
)
214 size_t buflen
, len
, alen
, dlen
;
217 _DIAGASSERT(buf
!= NULL
);
218 _DIAGASSERT(tic
!= NULL
);
220 len
= strlen(tic
->name
) + 1;
221 if (tic
->alias
== NULL
)
224 alen
= strlen(tic
->alias
) + 1;
225 if (tic
->desc
== NULL
)
228 dlen
= strlen(tic
->desc
) + 1;
229 buflen
= sizeof(char) +
230 sizeof(uint16_t) + len
+
231 sizeof(uint16_t) + alen
+
232 sizeof(uint16_t) + dlen
+
233 (sizeof(uint16_t) * 2) + tic
->flags
.bufpos
+
234 (sizeof(uint16_t) * 2) + tic
->nums
.bufpos
+
235 (sizeof(uint16_t) * 2) + tic
->strs
.bufpos
+
236 (sizeof(uint16_t) * 2) + tic
->extras
.bufpos
;
237 *buf
= malloc(buflen
);
244 cap
+= sizeof(uint16_t);
245 memcpy(cap
, tic
->name
, len
);
249 cap
+= sizeof(uint16_t);
250 if (tic
->alias
!= NULL
) {
251 memcpy(cap
, tic
->alias
, alen
);
255 cap
+= sizeof(uint16_t);
256 if (tic
->desc
!= NULL
) {
257 memcpy(cap
, tic
->desc
, dlen
);
261 if (tic
->flags
.entries
== 0) {
263 cap
+= sizeof(uint16_t);
265 le16enc(cap
, (tic
->flags
.bufpos
+ sizeof(uint16_t)));
266 cap
+= sizeof(uint16_t);
267 le16enc(cap
, tic
->flags
.entries
);
268 cap
+= sizeof(uint16_t);
269 memcpy(cap
, tic
->flags
.buf
, tic
->flags
.bufpos
);
270 cap
+= tic
->flags
.bufpos
;
273 if (tic
->nums
.entries
== 0) {
275 cap
+= sizeof(uint16_t);
277 le16enc(cap
, (tic
->nums
.bufpos
+ sizeof(uint16_t)));
278 cap
+= sizeof(uint16_t);
279 le16enc(cap
, tic
->nums
.entries
);
280 cap
+= sizeof(uint16_t);
281 memcpy(cap
, tic
->nums
.buf
, tic
->nums
.bufpos
);
282 cap
+= tic
->nums
.bufpos
;
285 if (tic
->strs
.entries
== 0) {
287 cap
+= sizeof(uint16_t);
289 le16enc(cap
, (tic
->strs
.bufpos
+ sizeof(uint16_t)));
290 cap
+= sizeof(uint16_t);
291 le16enc(cap
, tic
->strs
.entries
);
292 cap
+= sizeof(uint16_t);
293 memcpy(cap
, tic
->strs
.buf
, tic
->strs
.bufpos
);
294 cap
+= tic
->strs
.bufpos
;
297 if (tic
->extras
.entries
== 0) {
299 cap
+= sizeof(uint16_t);
301 le16enc(cap
, (tic
->extras
.bufpos
+ sizeof(uint16_t)));
302 cap
+= sizeof(uint16_t);
303 le16enc(cap
, tic
->extras
.entries
);
304 cap
+= sizeof(uint16_t);
305 memcpy(cap
, tic
->extras
.buf
, tic
->extras
.bufpos
);
306 cap
+= tic
->extras
.bufpos
;
313 encode_string(const char *term
, const char *cap
, TBUF
*tbuf
, const char *str
,
317 char ch
, *p
, *s
, last
;
319 if (_ti_grow_tbuf(tbuf
, strlen(str
) + 1) == NULL
)
321 p
= s
= tbuf
->buf
+ tbuf
->bufpos
;
324 /* Convert escape codes */
325 while ((ch
= *str
++) != '\0') {
326 if (slash
== 0 && ch
== '\\') {
331 if (last
!= '%' && ch
== '^') {
333 if (((unsigned char)ch
) >= 128)
335 "%s: %s: illegal ^ character",
341 else if ((ch
&= 037) == 0)
349 if (ch
>= '0' && ch
<= '7') {
351 for (i
= 0; i
< 2; i
++) {
352 if (*str
< '0' || *str
> '7') {
353 if (isdigit((unsigned char)*str
))
356 " digit", term
, cap
);
360 num
= num
* 8 + *str
++ - '0';
374 case 'e': /* FALLTHROUGH */
381 case 'l': /* FALLTHROUGH */
396 /* We should warn here */
407 tbuf
->bufpos
+= p
- s
;
412 _ti_get_token(char **cap
, char sep
)
416 while (isspace((unsigned char)**cap
))
421 /* We can't use stresep(3) as ^ we need two escape chars */
424 **cap
!= '\0' && (esc
!= '\0' || **cap
!= sep
);
428 if (**cap
== '\\' || **cap
== '^')
431 /* termcap /E/ is valid */
432 if (sep
== ':' && esc
== '\\' && **cap
== 'E')
446 _ti_compile(char *cap
, int flags
)
448 char *token
, *p
, *e
, *name
, *desc
, *alias
;
457 _DIAGASSERT(cap
!= NULL
);
459 name
= _ti_get_token(&cap
, ',');
461 dowarn(flags
, "no seperator found: %s", cap
);
464 desc
= strrchr(name
, '|');
467 alias
= strchr(name
, '|');
471 tic
= calloc(sizeof(*tic
), 1);
478 tic
->name
= strdup(name
);
479 if (tic
->name
== NULL
)
481 if (alias
!= NULL
&& flags
& TIC_ALIAS
) {
482 tic
->alias
= strdup(alias
);
483 if (tic
->alias
== NULL
)
486 if (desc
!= NULL
&& flags
& TIC_DESCRIPTION
) {
487 tic
->desc
= strdup(desc
);
488 if (tic
->desc
== NULL
)
492 for (token
= _ti_get_token(&cap
, ',');
493 token
!= NULL
&& *token
!= '\0';
494 token
= _ti_get_token(&cap
, ','))
496 /* Skip commented caps */
497 if (!(flags
& TIC_COMMENT
) && token
[0] == '.')
500 /* Obsolete entries */
501 if (token
[0] == 'O' && token
[1] == 'T') {
502 if (!(flags
& TIC_EXTRA
))
508 p
= strchr(token
, '=');
511 /* Don't use the string if we already have it */
512 ind
= _ti_strindex(token
);
514 _ti_find_cap(&tic
->strs
, 's', ind
) != NULL
)
517 /* Encode the string to our scratch buffer */
519 if (encode_string(tic
->name
, token
,
520 &buf
, p
, flags
) == -1)
522 if (buf
.bufpos
> UINT16_T_MAX
) {
523 dowarn(flags
, "%s: %s: string is too long",
527 if (!VALID_STRING(buf
.buf
)) {
528 dowarn(flags
, "%s: %s: invalid string",
534 _ti_store_extra(tic
, 1, token
, 's', -1, -2,
535 buf
.buf
, buf
.bufpos
, flags
);
537 if (!_ti_grow_tbuf(&tic
->strs
,
538 (sizeof(uint16_t) * 2) + buf
.bufpos
))
540 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
, ind
);
541 tic
->strs
.bufpos
+= sizeof(uint16_t);
542 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
,
544 tic
->strs
.bufpos
+= sizeof(uint16_t);
545 memcpy(tic
->strs
.buf
+ tic
->strs
.bufpos
,
546 buf
.buf
, buf
.bufpos
);
547 tic
->strs
.bufpos
+= buf
.bufpos
;
554 p
= strchr(token
, '#');
557 /* Don't use the number if we already have it */
558 ind
= _ti_numindex(token
);
560 _ti_find_cap(&tic
->nums
, 'n', ind
) != NULL
)
563 cnum
= strtol(p
, &e
, 0);
565 dowarn(flags
, "%s: %s: not a number",
569 if (!VALID_NUMERIC(cnum
)) {
570 dowarn(flags
, "%s: %s: number out of range",
576 _ti_store_extra(tic
, 1, token
, 'n', -1,
577 num
, NULL
, 0, flags
);
579 if (_ti_grow_tbuf(&tic
->nums
,
580 sizeof(uint16_t) * 2) == NULL
)
582 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
, ind
);
583 tic
->nums
.bufpos
+= sizeof(uint16_t);
584 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
, num
);
585 tic
->nums
.bufpos
+= sizeof(uint16_t);
592 len
= strlen(token
) - 1;
593 if (token
[len
] == '@') {
594 flag
= CANCELLED_BOOLEAN
;
597 ind
= _ti_flagindex(token
);
598 if (ind
== -1 && flag
== CANCELLED_BOOLEAN
) {
599 if ((ind
= _ti_numindex(token
)) != -1) {
600 if (_ti_find_cap(&tic
->nums
, 'n', ind
) != NULL
)
602 if (_ti_grow_tbuf(&tic
->nums
,
603 sizeof(uint16_t) * 2) == NULL
)
605 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
, ind
);
606 tic
->nums
.bufpos
+= sizeof(uint16_t);
607 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
,
608 (uint16_t)CANCELLED_NUMERIC
);
609 tic
->nums
.bufpos
+= sizeof(uint16_t);
612 } else if ((ind
= _ti_strindex(token
)) != -1) {
613 if (_ti_find_cap(&tic
->strs
, 's', ind
) != NULL
)
615 if (_ti_grow_tbuf(&tic
->strs
,
616 (sizeof(uint16_t) * 2) + 1) == NULL
)
618 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
, ind
);
619 tic
->strs
.bufpos
+= sizeof(uint16_t);
620 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
, 0);
621 tic
->strs
.bufpos
+= sizeof(uint16_t);
627 _ti_store_extra(tic
, 1, token
, 'f', flag
, 0, NULL
, 0,
629 else if (_ti_find_cap(&tic
->flags
, 'f', ind
) == NULL
) {
630 if (_ti_grow_tbuf(&tic
->flags
, sizeof(uint16_t) + 1)
633 le16enc(tic
->flags
.buf
+ tic
->flags
.bufpos
, ind
);
634 tic
->flags
.bufpos
+= sizeof(uint16_t);
635 tic
->flags
.buf
[tic
->flags
.bufpos
++] = flag
;
636 tic
->flags
.entries
++;
650 _ti_freetic(TIC
*tic
)
657 free(tic
->extras
.buf
);
658 free(tic
->flags
.buf
);