1 /* $NetBSD: compile.c,v 1.26 2020/06/21 15:05:23 roy Exp $ */
2
3 /*
4 * Copyright (c) 2009, 2010, 2011, 2020 The NetBSD Foundation, Inc.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Roy Marples.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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.
17 *
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.
28 */
29
30 #if HAVE_NBTOOL_CONFIG_H
31 #include "nbtool_config.h"
32 #endif
33
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: compile.c,v 1.26 2020/06/21 15:05:23 roy Exp $");
36
37 #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
38 #include <sys/endian.h>
39 #endif
40
41 #include <assert.h>
42 #include <ctype.h>
43 #include <err.h>
44 #include <errno.h>
45 #include <limits.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <stdint.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <term_private.h>
52 #include <term.h>
53
54 static void __printflike(2, 3)
dowarn(int flags,const char * fmt,...)55 dowarn(int flags, const char *fmt, ...)
56 {
57 va_list va;
58
59 errno = EINVAL;
60 if (flags & TIC_WARNING) {
61 va_start(va, fmt);
62 vwarnx(fmt, va);
63 va_end(va);
64 }
65 }
66
67 #ifdef TERMINFO_COMPAT
68 int
_ti_promote(TIC * tic)69 _ti_promote(TIC *tic)
70 {
71 char *obuf, type, flag, *buf, *delim, *name, *nbuf;
72 const char *cap, *code, *str;
73 size_t n, entries, strl;
74 uint16_t ind;
75 int num, ortype, error = 0;
76
77 ortype = tic->rtype;
78 tic->rtype = TERMINFO_RTYPE;
79 obuf = tic->name;
80 tic->name = _ti_getname(tic->rtype, tic->name);
81 if (tic->name == NULL) {
82 warn("_ti_getname");
83 tic->name = obuf;
84 return -1;
85 }
86 free(obuf);
87
88 n = 0;
89 obuf = buf = tic->alias;
90 tic->alias = NULL;
91 while (buf != NULL) {
92 delim = strchr(buf, '|');
93 if (delim != NULL)
94 *delim++ = '\0';
95 name = _ti_getname(tic->rtype, buf);
96 strl = strlen(name) + 1;
97 nbuf = realloc(tic->alias, n + strl);
98 if (nbuf == NULL) {
99 free(name);
100 return -1;
101 }
102 tic->alias = nbuf;
103 memcpy(tic->alias + n, name, strl);
104 n += strl;
105 free(name);
106 buf = delim;
107 }
108 free(obuf);
109
110 obuf = tic->nums.buf;
111 cap = obuf;
112 entries = tic->nums.entries;
113 tic->nums.buf = NULL;
114 tic->nums.entries = tic->nums.buflen = tic->nums.bufpos = 0;
115 for (n = entries; n > 0; n--) {
116 ind = _ti_decode_16(&cap);
117 num = _ti_decode_num(&cap, ortype);
118 if (VALID_NUMERIC(num) &&
119 !_ti_encode_buf_id_num(&tic->nums, ind, num,
120 _ti_numsize(tic)))
121 {
122 warn("promote num");
123 error = -1;
124 break;
125 }
126 }
127 free(obuf);
128
129 obuf = tic->extras.buf;
130 cap = obuf;
131 entries = tic->extras.entries;
132 tic->extras.buf = NULL;
133 tic->extras.entries = tic->extras.buflen = tic->extras.bufpos = 0;
134 for (n = entries; n > 0; n--) {
135 num = _ti_decode_16(&cap);
136 flag = 0; /* satisfy gcc, won't be used for non flag types */
137 str = NULL; /* satisfy gcc, won't be used as strl is 0 */
138 strl = 0;
139 code = cap;
140 cap += num;
141 type = *cap++;
142 switch (type) {
143 case 'f':
144 flag = *cap++;
145 break;
146 case 'n':
147 num = _ti_decode_num(&cap, ortype);
148 break;
149 case 's':
150 strl = _ti_decode_16(&cap);
151 str = cap;
152 cap += strl;
153 break;
154 default:
155 errno = EINVAL;
156 break;
157 }
158 if (!_ti_store_extra(tic, 0, code, type, flag, num,
159 str, strl, TIC_EXTRA))
160 {
161 error = -1;
162 break;
163 }
164 }
165 free(obuf);
166
167 return error;
168 }
169 #endif
170
171 char *
_ti_grow_tbuf(TBUF * tbuf,size_t len)172 _ti_grow_tbuf(TBUF *tbuf, size_t len)
173 {
174 char *buf;
175 size_t l;
176
177 _DIAGASSERT(tbuf != NULL);
178
179 l = tbuf->bufpos + len;
180 if (l > tbuf->buflen) {
181 if (tbuf->buflen == 0)
182 buf = malloc(l);
183 else
184 buf = realloc(tbuf->buf, l);
185 if (buf == NULL)
186 return NULL;
187 tbuf->buf = buf;
188 tbuf->buflen = l;
189 }
190 return tbuf->buf;
191 }
192
193 const char *
_ti_find_cap(TIC * tic,TBUF * tbuf,char type,short ind)194 _ti_find_cap(TIC *tic, TBUF *tbuf, char type, short ind)
195 {
196 size_t n;
197 uint16_t num;
198 const char *cap;
199
200 _DIAGASSERT(tbuf != NULL);
201
202 cap = tbuf->buf;
203 for (n = tbuf->entries; n > 0; n--) {
204 num = _ti_decode_16(&cap);
205 if ((short)num == ind)
206 return cap;
207 switch (type) {
208 case 'f':
209 cap++;
210 break;
211 case 'n':
212 cap += _ti_numsize(tic);
213 break;
214 case 's':
215 num = _ti_decode_16(&cap);
216 cap += num;
217 break;
218 }
219 }
220
221 errno = ESRCH;
222 return NULL;
223 }
224
225 const char *
_ti_find_extra(TIC * tic,TBUF * tbuf,const char * code)226 _ti_find_extra(TIC *tic, TBUF *tbuf, const char *code)
227 {
228 size_t n;
229 uint16_t num;
230 const char *cap;
231
232 _DIAGASSERT(tbuf != NULL);
233 _DIAGASSERT(code != NULL);
234
235 cap = tbuf->buf;
236 for (n = tbuf->entries; n > 0; n--) {
237 num = _ti_decode_16(&cap);
238 if (strcmp(cap, code) == 0)
239 return cap + num;
240 cap += num;
241 switch (*cap++) {
242 case 'f':
243 cap++;
244 break;
245 case 'n':
246 cap += _ti_numsize(tic);
247 break;
248 case 's':
249 num = _ti_decode_16(&cap);
250 cap += num;
251 break;
252 }
253 }
254
255 errno = ESRCH;
256 return NULL;
257 }
258
259 char *
_ti_getname(int rtype,const char * orig)260 _ti_getname(int rtype, const char *orig)
261 {
262 #ifdef TERMINFO_COMPAT
263 const char *delim;
264 char *name;
265 const char *verstr;
266 size_t diff, vlen;
267
268 switch (rtype) {
269 case TERMINFO_RTYPE:
270 verstr = TERMINFO_VDELIMSTR "v3";
271 break;
272 case TERMINFO_RTYPE_O1:
273 verstr = "";
274 break;
275 default:
276 errno = EINVAL;
277 return NULL;
278 }
279
280 delim = orig;
281 while (*delim != '\0' && *delim != TERMINFO_VDELIM)
282 delim++;
283 diff = delim - orig;
284 vlen = strlen(verstr);
285 name = malloc(diff + vlen + 1);
286 if (name == NULL)
287 return NULL;
288
289 memcpy(name, orig, diff);
290 memcpy(name + diff, verstr, vlen + 1);
291 return name;
292 #else
293 return strdup(orig);
294 #endif
295 }
296
297 size_t
_ti_store_extra(TIC * tic,int wrn,const char * id,char type,char flag,int num,const char * str,size_t strl,int flags)298 _ti_store_extra(TIC *tic, int wrn, const char *id, char type, char flag,
299 int num, const char *str, size_t strl, int flags)
300 {
301 size_t l, capl;
302
303 _DIAGASSERT(tic != NULL);
304
305 if (strcmp(id, "use") != 0) {
306 if (_ti_find_extra(tic, &tic->extras, id) != NULL)
307 return 0;
308 if (!(flags & TIC_EXTRA)) {
309 if (wrn != 0)
310 dowarn(flags, "%s: %s: unknown capability",
311 tic->name, id);
312 return 0;
313 }
314 }
315
316 l = strlen(id) + 1;
317 if (l > UINT16_MAX) {
318 dowarn(flags, "%s: %s: cap name is too long", tic->name, id);
319 return 0;
320 }
321
322 capl = sizeof(uint16_t) + l + 1;
323 switch (type) {
324 case 'f':
325 capl++;
326 break;
327 case 'n':
328 capl += _ti_numsize(tic);
329 break;
330 case 's':
331 capl += sizeof(uint16_t) + strl;
332 break;
333 }
334
335 if (!_ti_grow_tbuf(&tic->extras, capl))
336 return 0;
337 _ti_encode_buf_count_str(&tic->extras, id, l);
338 tic->extras.buf[tic->extras.bufpos++] = type;
339 switch (type) {
340 case 'f':
341 tic->extras.buf[tic->extras.bufpos++] = flag;
342 break;
343 case 'n':
344 _ti_encode_buf_num(&tic->extras, num, tic->rtype);
345 break;
346 case 's':
347 _ti_encode_buf_count_str(&tic->extras, str, strl);
348 break;
349 }
350 tic->extras.entries++;
351 return 1;
352 }
353
354 static void
_ti_encode_buf(char ** cap,const TBUF * buf)355 _ti_encode_buf(char **cap, const TBUF *buf)
356 {
357 if (buf->entries == 0) {
358 _ti_encode_16(cap, 0);
359 } else {
360 _ti_encode_16(cap, buf->bufpos + sizeof(uint16_t));
361 _ti_encode_16(cap, buf->entries);
362 _ti_encode_str(cap, buf->buf, buf->bufpos);
363 }
364 }
365
366 ssize_t
_ti_flatten(uint8_t ** buf,const TIC * tic)367 _ti_flatten(uint8_t **buf, const TIC *tic)
368 {
369 size_t buflen, len, alen, dlen;
370 char *cap;
371
372 _DIAGASSERT(buf != NULL);
373 _DIAGASSERT(tic != NULL);
374
375 len = strlen(tic->name) + 1;
376 if (tic->alias == NULL)
377 alen = 0;
378 else
379 alen = strlen(tic->alias) + 1;
380 if (tic->desc == NULL)
381 dlen = 0;
382 else
383 dlen = strlen(tic->desc) + 1;
384
385 buflen = sizeof(char) +
386 sizeof(uint16_t) + len +
387 sizeof(uint16_t) + alen +
388 sizeof(uint16_t) + dlen +
389 (sizeof(uint16_t) * 2) + tic->flags.bufpos +
390 (sizeof(uint16_t) * 2) + tic->nums.bufpos +
391 (sizeof(uint16_t) * 2) + tic->strs.bufpos +
392 (sizeof(uint16_t) * 2) + tic->extras.bufpos;
393
394 *buf = malloc(buflen);
395 if (*buf == NULL)
396 return -1;
397
398 cap = (char *)*buf;
399 *cap++ = tic->rtype;
400
401 _ti_encode_count_str(&cap, tic->name, len);
402 _ti_encode_count_str(&cap, tic->alias, alen);
403 _ti_encode_count_str(&cap, tic->desc, dlen);
404
405 _ti_encode_buf(&cap, &tic->flags);
406
407 _ti_encode_buf(&cap, &tic->nums);
408 _ti_encode_buf(&cap, &tic->strs);
409 _ti_encode_buf(&cap, &tic->extras);
410
411 return (uint8_t *)cap - *buf;
412 }
413
414 static int
encode_string(const char * term,const char * cap,TBUF * tbuf,const char * str,int flags)415 encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str,
416 int flags)
417 {
418 int slash, i, num;
419 char ch, *p, *s, last;
420
421 if (_ti_grow_tbuf(tbuf, strlen(str) + 1) == NULL)
422 return -1;
423 p = s = tbuf->buf + tbuf->bufpos;
424 slash = 0;
425 last = '\0';
426 /* Convert escape codes */
427 while ((ch = *str++) != '\0') {
428 if (ch == '\n') {
429 /* Following a newline, strip leading whitespace from
430 * capability strings. */
431 while (isspace((unsigned char)*str))
432 str++;
433 continue;
434 }
435 if (slash == 0 && ch == '\\') {
436 slash = 1;
437 continue;
438 }
439 if (slash == 0) {
440 if (last != '%' && ch == '^') {
441 ch = *str++;
442 if (((unsigned char)ch) >= 128)
443 dowarn(flags,
444 "%s: %s: illegal ^ character",
445 term, cap);
446 if (ch == '\0')
447 break;
448 if (ch == '?')
449 ch = '\177';
450 else if ((ch &= 037) == 0)
451 ch = (char)128;
452 } else if (!isprint((unsigned char)ch))
453 dowarn(flags,
454 "%s: %s: unprintable character",
455 term, cap);
456 *p++ = ch;
457 last = ch;
458 continue;
459 }
460 slash = 0;
461 if (ch >= '0' && ch <= '7') {
462 num = ch - '0';
463 for (i = 0; i < 2; i++) {
464 if (*str < '0' || *str > '7') {
465 if (isdigit((unsigned char)*str))
466 dowarn(flags,
467 "%s: %s: non octal"
468 " digit", term, cap);
469 else
470 break;
471 }
472 num = num * 8 + *str++ - '0';
473 }
474 if (num == 0)
475 num = 0200;
476 *p++ = (char)num;
477 continue;
478 }
479 switch (ch) {
480 case 'a':
481 *p++ = '\a';
482 break;
483 case 'b':
484 *p++ = '\b';
485 break;
486 case 'e': /* FALLTHROUGH */
487 case 'E':
488 *p++ = '\033';
489 break;
490 case 'f':
491 *p++ = '\014';
492 break;
493 case 'l': /* FALLTHROUGH */
494 case 'n':
495 *p++ = '\n';
496 break;
497 case 'r':
498 *p++ = '\r';
499 break;
500 case 's':
501 *p++ = ' ';
502 break;
503 case 't':
504 *p++ = '\t';
505 break;
506 default:
507 /* We should warn here */
508 case '^':
509 case ',':
510 case ':':
511 case '|':
512 *p++ = ch;
513 break;
514 }
515 last = ch;
516 }
517 *p++ = '\0';
518 tbuf->bufpos += (size_t)(p - s);
519 return 0;
520 }
521
522 char *
_ti_get_token(char ** cap,char sep)523 _ti_get_token(char **cap, char sep)
524 {
525 char esc, *token;
526
527 while (isspace((unsigned char)**cap))
528 (*cap)++;
529 if (**cap == '\0')
530 return NULL;
531
532 /* We can't use stresep(3) as ^ we need two escape chars */
533 esc = '\0';
534 for (token = *cap;
535 **cap != '\0' && (esc != '\0' || **cap != sep);
536 (*cap)++)
537 {
538 if (esc == '\0') {
539 if (**cap == '\\' || **cap == '^')
540 esc = **cap;
541 } else {
542 /* termcap /E/ is valid */
543 if (sep == ':' && esc == '\\' && **cap == 'E')
544 esc = 'x';
545 else
546 esc = '\0';
547 }
548 }
549
550 if (**cap != '\0')
551 *(*cap)++ = '\0';
552
553 return token;
554 }
555
556 int
_ti_encode_buf_id_num(TBUF * tbuf,int ind,int num,size_t len)557 _ti_encode_buf_id_num(TBUF *tbuf, int ind, int num, size_t len)
558 {
559 if (!_ti_grow_tbuf(tbuf, sizeof(uint16_t) + len))
560 return 0;
561 _ti_encode_buf_16(tbuf, ind);
562 if (len == sizeof(uint32_t))
563 _ti_encode_buf_32(tbuf, (uint32_t)num);
564 else
565 _ti_encode_buf_16(tbuf, (uint16_t)num);
566 tbuf->entries++;
567 return 1;
568 }
569
570 int
_ti_encode_buf_id_count_str(TBUF * tbuf,int ind,const void * buf,size_t len)571 _ti_encode_buf_id_count_str(TBUF *tbuf, int ind, const void *buf, size_t len)
572 {
573 if (!_ti_grow_tbuf(tbuf, 2 * sizeof(uint16_t) + len))
574 return 0;
575 _ti_encode_buf_16(tbuf, ind);
576 _ti_encode_buf_count_str(tbuf, buf, len);
577 tbuf->entries++;
578 return 1;
579 }
580
581 int
_ti_encode_buf_id_flags(TBUF * tbuf,int ind,int flag)582 _ti_encode_buf_id_flags(TBUF *tbuf, int ind, int flag)
583 {
584 if (!_ti_grow_tbuf(tbuf, sizeof(uint16_t) + 1))
585 return 0;
586 _ti_encode_buf_16(tbuf, ind);
587 tbuf->buf[tbuf->bufpos++] = flag;
588 tbuf->entries++;
589 return 1;
590 }
591
592 TIC *
_ti_compile(char * cap,int flags)593 _ti_compile(char *cap, int flags)
594 {
595 char *token, *p, *e, *name, *desc, *alias;
596 signed char flag;
597 long cnum;
598 short ind;
599 int num;
600 size_t len;
601 TBUF buf;
602 TIC *tic;
603
604 _DIAGASSERT(cap != NULL);
605
606 name = _ti_get_token(&cap, ',');
607 if (name == NULL) {
608 dowarn(flags, "no separator found: %s", cap);
609 return NULL;
610 }
611 desc = strrchr(name, '|');
612 if (desc != NULL)
613 *desc++ = '\0';
614 alias = strchr(name, '|');
615 if (alias != NULL)
616 *alias++ = '\0';
617
618 if (strlen(name) > UINT16_MAX - 1) {
619 dowarn(flags, "%s: name too long", name);
620 return NULL;
621 }
622 if (desc != NULL && strlen(desc) > UINT16_MAX - 1) {
623 dowarn(flags, "%s: description too long: %s", name, desc);
624 return NULL;
625 }
626 if (alias != NULL && strlen(alias) > UINT16_MAX - 1) {
627 dowarn(flags, "%s: alias too long: %s", name, alias);
628 return NULL;
629 }
630
631 tic = calloc(sizeof(*tic), 1);
632 if (tic == NULL)
633 return NULL;
634
635 #ifdef TERMINFO_COMPAT
636 tic->rtype = TERMINFO_RTYPE_O1; /* will promote if needed */
637 #else
638 tic->rtype = TERMINFO_RTYPE;
639 #endif
640 buf.buf = NULL;
641 buf.buflen = 0;
642
643 tic->name = _ti_getname(tic->rtype, name);
644 if (tic->name == NULL)
645 goto error;
646 if (alias != NULL && flags & TIC_ALIAS) {
647 tic->alias = _ti_getname(tic->rtype, alias);
648 if (tic->alias == NULL)
649 goto error;
650 }
651 if (desc != NULL && flags & TIC_DESCRIPTION) {
652 tic->desc = strdup(desc);
653 if (tic->desc == NULL)
654 goto error;
655 }
656
657 for (token = _ti_get_token(&cap, ',');
658 token != NULL && *token != '\0';
659 token = _ti_get_token(&cap, ','))
660 {
661 /* Skip commented caps */
662 if (!(flags & TIC_COMMENT) && token[0] == '.')
663 continue;
664
665 /* Obsolete entries */
666 if (token[0] == 'O' && token[1] == 'T') {
667 if (!(flags & TIC_EXTRA))
668 continue;
669 token += 2;
670 }
671
672 /* str cap */
673 p = strchr(token, '=');
674 if (p != NULL) {
675 *p++ = '\0';
676 /* Don't use the string if we already have it */
677 ind = (short)_ti_strindex(token);
678 if (ind != -1 &&
679 _ti_find_cap(tic, &tic->strs, 's', ind) != NULL)
680 continue;
681
682 /* Encode the string to our scratch buffer */
683 buf.bufpos = 0;
684 if (encode_string(tic->name, token,
685 &buf, p, flags) == -1)
686 goto error;
687 if (buf.bufpos > UINT16_MAX - 1) {
688 dowarn(flags, "%s: %s: string is too long",
689 tic->name, token);
690 continue;
691 }
692 if (!VALID_STRING(buf.buf)) {
693 dowarn(flags, "%s: %s: invalid string",
694 tic->name, token);
695 continue;
696 }
697
698 if (ind == -1) {
699 if (!_ti_store_extra(tic, 1, token, 's', -1, -2,
700 buf.buf, buf.bufpos, flags))
701 goto error;
702 } else {
703 if (!_ti_encode_buf_id_count_str(&tic->strs,
704 ind, buf.buf, buf.bufpos))
705 goto error;
706 }
707 continue;
708 }
709
710 /* num cap */
711 p = strchr(token, '#');
712 if (p != NULL) {
713 *p++ = '\0';
714 /* Don't use the number if we already have it */
715 ind = (short)_ti_numindex(token);
716 if (ind != -1 &&
717 _ti_find_cap(tic, &tic->nums, 'n', ind) != NULL)
718 continue;
719
720 cnum = strtol(p, &e, 0);
721 if (*e != '\0') {
722 dowarn(flags, "%s: %s: not a number",
723 tic->name, token);
724 continue;
725 }
726 if (!VALID_NUMERIC(cnum) || cnum > INT32_MAX) {
727 dowarn(flags, "%s: %s: number %ld out of range",
728 tic->name, token, cnum);
729 continue;
730 }
731 if (cnum > INT16_MAX) {
732 if (flags & TIC_COMPAT_V1)
733 cnum = INT16_MAX;
734 else if (tic->rtype == TERMINFO_RTYPE_O1)
735 if (_ti_promote(tic) == -1)
736 goto error;
737 }
738
739 num = (int)cnum;
740 if (ind == -1) {
741 if (!_ti_store_extra(tic, 1, token, 'n', -1,
742 num, NULL, 0, flags))
743 goto error;
744 } else {
745 if (!_ti_encode_buf_id_num(&tic->nums,
746 ind, num, _ti_numsize(tic)))
747 goto error;
748 }
749 continue;
750 }
751
752 flag = 1;
753 len = strlen(token) - 1;
754 if (token[len] == '@') {
755 flag = CANCELLED_BOOLEAN;
756 token[len] = '\0';
757 }
758 ind = (short)_ti_flagindex(token);
759 if (ind == -1 && flag == CANCELLED_BOOLEAN) {
760 if ((ind = (short)_ti_numindex(token)) != -1) {
761 if (_ti_find_cap(tic, &tic->nums, 'n', ind)
762 != NULL)
763 continue;
764 if (!_ti_encode_buf_id_num(&tic->nums, ind,
765 CANCELLED_NUMERIC, _ti_numsize(tic)))
766 goto error;
767 continue;
768 } else if ((ind = (short)_ti_strindex(token)) != -1) {
769 if (_ti_find_cap(tic, &tic->strs, 's', ind)
770 != NULL)
771 continue;
772 if (!_ti_encode_buf_id_num(
773 &tic->strs, ind, 0, sizeof(uint16_t)))
774 goto error;
775 continue;
776 }
777 }
778 if (ind == -1) {
779 if (!_ti_store_extra(tic, 1, token, 'f', flag, 0, NULL,
780 0, flags))
781 goto error;
782 } else if (_ti_find_cap(tic, &tic->flags, 'f', ind) == NULL) {
783 if (!_ti_encode_buf_id_flags(&tic->flags, ind, flag))
784 goto error;
785 }
786 }
787
788 free(buf.buf);
789 return tic;
790
791 error:
792 free(buf.buf);
793 _ti_freetic(tic);
794 return NULL;
795 }
796
797 void
_ti_freetic(TIC * tic)798 _ti_freetic(TIC *tic)
799 {
800
801 if (tic != NULL) {
802 free(tic->name);
803 free(tic->alias);
804 free(tic->desc);
805 free(tic->extras.buf);
806 free(tic->flags.buf);
807 free(tic->nums.buf);
808 free(tic->strs.buf);
809 free(tic);
810 }
811 }
812