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