1 /* $NetBSD: compile.c,v 1.4 2010/03/02 14:11:11 roy Exp $ */
4 * Copyright (c) 2009, 2010 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.4 2010/03/02 14:11:11 roy Exp $");
37 #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
38 #include <sys/endian.h>
51 #include <term_private.h>
54 static void __attribute__((__format__(__printf__
, 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
->bufpos
== 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
);
242 if (alen
== 0 && dlen
== 0 && tic
->flags
.bufpos
== 0 &&
243 tic
->nums
.bufpos
== 0 && tic
->strs
.bufpos
== 0 &&
244 tic
->extras
.bufpos
== 0)
245 *cap
++ = 0; /* alias */
247 *cap
++ = 2; /* version */
249 cap
+= sizeof(uint16_t);
250 memcpy(cap
, tic
->name
, len
);
254 cap
+= sizeof(uint16_t);
255 if (tic
->alias
!= NULL
) {
256 memcpy(cap
, tic
->alias
, alen
);
260 cap
+= sizeof(uint16_t);
261 if (tic
->desc
!= NULL
) {
262 memcpy(cap
, tic
->desc
, dlen
);
266 if (tic
->flags
.entries
== 0) {
268 cap
+= sizeof(uint16_t);
270 le16enc(cap
, (tic
->flags
.bufpos
+ sizeof(uint16_t)));
271 cap
+= sizeof(uint16_t);
272 le16enc(cap
, tic
->flags
.entries
);
273 cap
+= sizeof(uint16_t);
274 memcpy(cap
, tic
->flags
.buf
, tic
->flags
.bufpos
);
275 cap
+= tic
->flags
.bufpos
;
278 if (tic
->nums
.entries
== 0) {
280 cap
+= sizeof(uint16_t);
282 le16enc(cap
, (tic
->nums
.bufpos
+ sizeof(uint16_t)));
283 cap
+= sizeof(uint16_t);
284 le16enc(cap
, tic
->nums
.entries
);
285 cap
+= sizeof(uint16_t);
286 memcpy(cap
, tic
->nums
.buf
, tic
->nums
.bufpos
);
287 cap
+= tic
->nums
.bufpos
;
290 if (tic
->strs
.entries
== 0) {
292 cap
+= sizeof(uint16_t);
294 le16enc(cap
, (tic
->strs
.bufpos
+ sizeof(uint16_t)));
295 cap
+= sizeof(uint16_t);
296 le16enc(cap
, tic
->strs
.entries
);
297 cap
+= sizeof(uint16_t);
298 memcpy(cap
, tic
->strs
.buf
, tic
->strs
.bufpos
);
299 cap
+= tic
->strs
.bufpos
;
302 if (tic
->extras
.entries
== 0) {
304 cap
+= sizeof(uint16_t);
306 le16enc(cap
, (tic
->extras
.bufpos
+ sizeof(uint16_t)));
307 cap
+= sizeof(uint16_t);
308 le16enc(cap
, tic
->extras
.entries
);
309 cap
+= sizeof(uint16_t);
310 memcpy(cap
, tic
->extras
.buf
, tic
->extras
.bufpos
);
311 cap
+= tic
->extras
.bufpos
;
318 encode_string(const char *term
, const char *cap
, TBUF
*tbuf
, const char *str
,
322 char ch
, *p
, *s
, last
;
324 if (_ti_grow_tbuf(tbuf
, strlen(str
) + 1) == NULL
)
326 p
= s
= tbuf
->buf
+ tbuf
->bufpos
;
329 /* Convert escape codes */
330 while ((ch
= *str
++) != '\0') {
331 if (slash
== 0 && ch
== '\\') {
336 if (last
!= '%' && ch
== '^') {
338 if (((unsigned char)ch
) >= 128)
340 "%s: %s: illegal ^ character",
346 else if ((ch
&= 037) == 0)
354 if (ch
>= '0' && ch
<= '7') {
356 for (i
= 0; i
< 2; i
++) {
357 if (*str
< '0' || *str
> '7') {
358 if (isdigit((unsigned char)*str
))
361 " digit", term
, cap
);
365 num
= num
* 8 + *str
++ - '0';
379 case 'e': /* FALLTHROUGH */
386 case 'l': /* FALLTHROUGH */
401 /* We should warn here */
412 tbuf
->bufpos
+= p
- s
;
417 _ti_get_token(char **cap
, char sep
)
421 while (isspace((unsigned char)**cap
))
426 /* We can't use stresep(3) as ^ we need two escape chars */
429 **cap
!= '\0' && (esc
!= '\0' || **cap
!= sep
);
433 if (**cap
== '\\' || **cap
== '^')
436 /* termcap /E/ is valid */
437 if (sep
== ':' && esc
== '\\' && **cap
== 'E')
451 _ti_compile(char *cap
, int flags
)
453 char *token
, *p
, *e
, *name
, *desc
, *alias
;
461 _DIAGASSERT(cap
!= NULL
);
463 name
= _ti_get_token(&cap
, ',');
465 dowarn(flags
, "no seperator found: %s", cap
);
468 desc
= strrchr(name
, '|');
471 alias
= strchr(name
, '|');
475 tic
= calloc(sizeof(*tic
), 1);
482 tic
->name
= strdup(name
);
483 if (tic
->name
== NULL
)
485 if (alias
!= NULL
&& flags
& TIC_ALIAS
) {
486 tic
->alias
= strdup(alias
);
487 if (tic
->alias
== NULL
)
490 if (desc
!= NULL
&& flags
& TIC_DESCRIPTION
) {
491 tic
->desc
= strdup(desc
);
492 if (tic
->desc
== NULL
)
496 for (token
= _ti_get_token(&cap
, ',');
497 token
!= NULL
&& *token
!= '\0';
498 token
= _ti_get_token(&cap
, ','))
500 /* Skip commented caps */
501 if (!(flags
& TIC_COMMENT
) && token
[0] == '.')
504 /* Obsolete entries */
505 if (token
[0] == 'O' && token
[1] == 'T') {
506 if (!(flags
& TIC_EXTRA
))
512 p
= strchr(token
, '=');
515 /* Don't use the string if we already have it */
516 ind
= _ti_strindex(token
);
518 _ti_find_cap(&tic
->strs
, 's', ind
) != NULL
)
521 /* Encode the string to our scratch buffer */
523 if (encode_string(tic
->name
, token
,
524 &buf
, p
, flags
) == -1)
526 if (buf
.bufpos
> UINT16_T_MAX
) {
527 dowarn(flags
, "%s: %s: string is too long",
531 if (!VALID_STRING(buf
.buf
)) {
532 dowarn(flags
, "%s: %s: invalid string",
538 _ti_store_extra(tic
, 1, token
, 's', -1, -2,
539 buf
.buf
, buf
.bufpos
, flags
);
541 if (!_ti_grow_tbuf(&tic
->strs
,
542 (sizeof(uint16_t) * 2) + buf
.bufpos
))
544 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
, ind
);
545 tic
->strs
.bufpos
+= sizeof(uint16_t);
546 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
,
548 tic
->strs
.bufpos
+= sizeof(uint16_t);
549 memcpy(tic
->strs
.buf
+ tic
->strs
.bufpos
,
550 buf
.buf
, buf
.bufpos
);
551 tic
->strs
.bufpos
+= buf
.bufpos
;
558 p
= strchr(token
, '#');
561 /* Don't use the number if we already have it */
562 ind
= _ti_numindex(token
);
564 _ti_find_cap(&tic
->nums
, 'n', ind
) != NULL
)
567 num
= strtol(p
, &e
, 0);
569 dowarn(flags
, "%s: %s: not a number",
573 if (!VALID_NUMERIC(num
)) {
574 dowarn(flags
, "%s: %s: number out of range",
579 _ti_store_extra(tic
, 1, token
, 'n', -1,
580 num
, NULL
, 0, flags
);
582 if (_ti_grow_tbuf(&tic
->nums
,
583 sizeof(uint16_t) * 2) == NULL
)
585 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
, ind
);
586 tic
->nums
.bufpos
+= sizeof(uint16_t);
587 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
, num
);
588 tic
->nums
.bufpos
+= sizeof(uint16_t);
595 len
= strlen(token
) - 1;
596 if (token
[len
] == '@') {
597 flag
= CANCELLED_BOOLEAN
;
600 ind
= _ti_flagindex(token
);
601 if (ind
== -1 && flag
== CANCELLED_BOOLEAN
) {
602 if ((ind
= _ti_numindex(token
)) != -1) {
603 if (_ti_find_cap(&tic
->nums
, 'n', ind
) != NULL
)
605 if (_ti_grow_tbuf(&tic
->nums
,
606 sizeof(uint16_t) * 2) == NULL
)
608 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
, ind
);
609 tic
->nums
.bufpos
+= sizeof(uint16_t);
610 le16enc(tic
->nums
.buf
+ tic
->nums
.bufpos
,
612 tic
->nums
.bufpos
+= sizeof(uint16_t);
615 } else if ((ind
= _ti_strindex(token
)) != -1) {
616 if (_ti_find_cap(&tic
->strs
, 's', ind
) != NULL
)
618 if (_ti_grow_tbuf(&tic
->strs
,
619 (sizeof(uint16_t) * 2) + 1) == NULL
)
621 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
, ind
);
622 tic
->strs
.bufpos
+= sizeof(uint16_t);
623 le16enc(tic
->strs
.buf
+ tic
->strs
.bufpos
, 0);
624 tic
->strs
.bufpos
+= sizeof(uint16_t);
630 _ti_store_extra(tic
, 1, token
, 'f', flag
, 0, NULL
, 0,
632 else if (_ti_find_cap(&tic
->flags
, 'f', ind
) == NULL
) {
633 if (_ti_grow_tbuf(&tic
->flags
, sizeof(uint16_t) + 1)
636 le16enc(tic
->flags
.buf
+ tic
->flags
.bufpos
, ind
);
637 tic
->flags
.bufpos
+= sizeof(uint16_t);
638 tic
->flags
.buf
[tic
->flags
.bufpos
++] = flag
;
639 tic
->flags
.entries
++;
653 _ti_freetic(TIC
*tic
)
660 free(tic
->flags
.buf
);