Annotation of src/lib/libterminfo/compile.c, Revision 1.11
1.11 ! roy 1: /* $NetBSD: compile.c,v 1.10 2017/02/11 14:57:15 roy Exp $ */
1.1 roy 2:
3: /*
1.5 roy 4: * Copyright (c) 2009, 2010, 2011 The NetBSD Foundation, Inc.
1.1 roy 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>
1.11 ! roy 35: __RCSID("$NetBSD: compile.c,v 1.10 2017/02/11 14:57:15 roy Exp $");
1.3 dholland 36:
37: #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
38: #include <sys/endian.h>
39: #endif
1.1 roy 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:
1.6 joerg 54: static void __printflike(2, 3)
1.1 roy 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: char *
68: _ti_grow_tbuf(TBUF *tbuf, size_t len)
69: {
70: char *buf;
71: size_t l;
72:
73: _DIAGASSERT(tbuf != NULL);
74:
75: l = tbuf->bufpos + len;
76: if (l > tbuf->buflen) {
1.7 joerg 77: if (tbuf->buflen == 0)
1.1 roy 78: buf = malloc(l);
79: else
80: buf = realloc(tbuf->buf, l);
81: if (buf == NULL)
82: return NULL;
83: tbuf->buf = buf;
84: tbuf->buflen = l;
85: }
86: return tbuf->buf;
87: }
88:
89: char *
90: _ti_find_cap(TBUF *tbuf, char type, short ind)
91: {
92: size_t n;
93: short num;
94: char *cap;
95:
96: _DIAGASSERT(tbuf != NULL);
97:
98: cap = tbuf->buf;
99: for (n = tbuf->entries; n > 0; n--) {
100: num = le16dec(cap);
101: cap += sizeof(uint16_t);
102: if (num == ind)
103: return cap;
104: switch (type) {
105: case 'f':
106: cap++;
107: break;
108: case 'n':
109: cap += sizeof(uint16_t);
110: break;
111: case 's':
112: num = le16dec(cap);
113: cap += sizeof(uint16_t);
114: cap += num;
115: break;
116: }
117: }
1.9 roy 118:
1.1 roy 119: errno = ESRCH;
120: return NULL;
121: }
122:
123: char *
124: _ti_find_extra(TBUF *tbuf, const char *code)
125: {
126: size_t n;
127: short num;
128: char *cap;
129:
130: _DIAGASSERT(tbuf != NULL);
131: _DIAGASSERT(code != NULL);
132:
133: cap = tbuf->buf;
134: for (n = tbuf->entries; n > 0; n--) {
135: num = le16dec(cap);
136: cap += sizeof(uint16_t);
137: if (strcmp(cap, code) == 0)
138: return cap + num;
139: cap += num;
140: switch (*cap++) {
141: case 'f':
142: cap++;
143: break;
144: case 'n':
145: cap += sizeof(uint16_t);
146: break;
147: case 's':
148: num = le16dec(cap);
149: cap += sizeof(uint16_t);
150: cap += num;
151: break;
152: }
153: }
1.9 roy 154:
1.1 roy 155: errno = ESRCH;
156: return NULL;
157: }
158:
159: size_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)
162: {
163: size_t l;
164:
165: _DIAGASSERT(tic != NULL);
166:
167: if (strcmp(id, "use") != 0) {
168: if (_ti_find_extra(&tic->extras, id) != NULL)
169: return 0;
170: if (!(flags & TIC_EXTRA)) {
171: if (wrn != 0)
172: dowarn(flags, "%s: %s: unknown capability",
173: tic->name, id);
174: return 0;
175: }
176: }
1.9 roy 177:
1.1 roy 178: l = strlen(id) + 1;
179: if (l > UINT16_T_MAX) {
180: dowarn(flags, "%s: %s: cap name is too long", tic->name, id);
181: return 0;
182: }
1.9 roy 183:
1.1 roy 184: if (!_ti_grow_tbuf(&tic->extras,
185: l + strl + (sizeof(uint16_t) * 2) + 1))
186: return 0;
187: le16enc(tic->extras.buf + tic->extras.bufpos, l);
188: tic->extras.bufpos += sizeof(uint16_t);
1.9 roy 189: memcpy(tic->extras.buf + tic->extras.bufpos, id, l);
1.1 roy 190: tic->extras.bufpos += l;
191: tic->extras.buf[tic->extras.bufpos++] = type;
192: switch (type) {
193: case 'f':
194: tic->extras.buf[tic->extras.bufpos++] = flag;
195: break;
196: case 'n':
197: le16enc(tic->extras.buf + tic->extras.bufpos, num);
198: tic->extras.bufpos += sizeof(uint16_t);
199: break;
200: case 's':
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;
205: break;
206: }
207: tic->extras.entries++;
208: return 1;
209: }
210:
211: ssize_t
212: _ti_flatten(uint8_t **buf, const TIC *tic)
213: {
214: size_t buflen, len, alen, dlen;
215: uint8_t *cap;
216:
217: _DIAGASSERT(buf != NULL);
218: _DIAGASSERT(tic != NULL);
219:
220: len = strlen(tic->name) + 1;
221: if (tic->alias == NULL)
222: alen = 0;
223: else
224: alen = strlen(tic->alias) + 1;
225: if (tic->desc == NULL)
226: dlen = 0;
227: else
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);
238: if (*buf == NULL)
239: return -1;
1.9 roy 240:
1.1 roy 241: cap = *buf;
1.8 joerg 242: *cap++ = 1;
1.1 roy 243: le16enc(cap, len);
244: cap += sizeof(uint16_t);
245: memcpy(cap, tic->name, len);
246: cap += len;
1.9 roy 247:
1.1 roy 248: le16enc(cap, alen);
249: cap += sizeof(uint16_t);
250: if (tic->alias != NULL) {
251: memcpy(cap, tic->alias, alen);
252: cap += alen;
253: }
254: le16enc(cap, dlen);
255: cap += sizeof(uint16_t);
256: if (tic->desc != NULL) {
257: memcpy(cap, tic->desc, dlen);
258: cap += dlen;
259: }
260:
261: if (tic->flags.entries == 0) {
262: le16enc(cap, 0);
263: cap += sizeof(uint16_t);
264: } else {
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;
271: }
1.9 roy 272:
1.1 roy 273: if (tic->nums.entries == 0) {
274: le16enc(cap, 0);
275: cap += sizeof(uint16_t);
276: } else {
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;
283: }
1.9 roy 284:
1.1 roy 285: if (tic->strs.entries == 0) {
286: le16enc(cap, 0);
287: cap += sizeof(uint16_t);
288: } else {
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;
295: }
1.9 roy 296:
1.1 roy 297: if (tic->extras.entries == 0) {
298: le16enc(cap, 0);
299: cap += sizeof(uint16_t);
300: } else {
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;
307: }
308:
309: return cap - *buf;
310: }
311:
312: static int
313: encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str,
314: int flags)
315: {
316: int slash, i, num;
317: char ch, *p, *s, last;
1.9 roy 318:
1.1 roy 319: if (_ti_grow_tbuf(tbuf, strlen(str) + 1) == NULL)
320: return -1;
321: p = s = tbuf->buf + tbuf->bufpos;
322: slash = 0;
323: last = '\0';
324: /* Convert escape codes */
325: while ((ch = *str++) != '\0') {
1.10 roy 326: if (ch == '\n') {
327: /* Following a newline, strip leading whitespace from
328: * capability strings. */
329: while (isspace((unsigned char)*str))
330: str++;
331: continue;
332: }
1.1 roy 333: if (slash == 0 && ch == '\\') {
334: slash = 1;
335: continue;
336: }
337: if (slash == 0) {
338: if (last != '%' && ch == '^') {
339: ch = *str++;
340: if (((unsigned char)ch) >= 128)
341: dowarn(flags,
342: "%s: %s: illegal ^ character",
343: term, cap);
344: if (ch == '\0')
345: break;
346: if (ch == '?')
347: ch = '\177';
348: else if ((ch &= 037) == 0)
1.5 roy 349: ch = (char)128;
1.11 ! roy 350: } else if (!isprint((unsigned char)ch))
! 351: dowarn(flags,
! 352: "%s: %s: unprintable character",
! 353: term, cap);
1.1 roy 354: *p++ = ch;
355: last = ch;
356: continue;
357: }
358: slash = 0;
359: if (ch >= '0' && ch <= '7') {
360: num = ch - '0';
361: for (i = 0; i < 2; i++) {
362: if (*str < '0' || *str > '7') {
363: if (isdigit((unsigned char)*str))
364: dowarn(flags,
365: "%s: %s: non octal"
366: " digit", term, cap);
367: else
368: break;
369: }
370: num = num * 8 + *str++ - '0';
371: }
372: if (num == 0)
373: num = 0200;
374: *p++ = (char)num;
375: continue;
376: }
377: switch (ch) {
378: case 'a':
379: *p++ = '\a';
380: break;
381: case 'b':
382: *p++ = '\b';
383: break;
384: case 'e': /* FALLTHROUGH */
385: case 'E':
386: *p++ = '\033';
387: break;
388: case 'f':
389: *p++ = '\014';
390: break;
391: case 'l': /* FALLTHROUGH */
392: case 'n':
393: *p++ = '\n';
394: break;
395: case 'r':
396: *p++ = '\r';
397: break;
398: case 's':
399: *p++ = ' ';
400: break;
401: case 't':
402: *p++ = '\t';
403: break;
404: default:
405: /* We should warn here */
406: case '^':
407: case ',':
408: case ':':
409: case '|':
410: *p++ = ch;
411: break;
412: }
413: last = ch;
414: }
415: *p++ = '\0';
416: tbuf->bufpos += p - s;
417: return 0;
418: }
419:
1.4 roy 420: char *
421: _ti_get_token(char **cap, char sep)
1.1 roy 422: {
1.4 roy 423: char esc, *token;
1.1 roy 424:
425: while (isspace((unsigned char)**cap))
426: (*cap)++;
427: if (**cap == '\0')
428: return NULL;
429:
430: /* We can't use stresep(3) as ^ we need two escape chars */
1.4 roy 431: esc = '\0';
1.1 roy 432: for (token = *cap;
1.4 roy 433: **cap != '\0' && (esc != '\0' || **cap != sep);
1.1 roy 434: (*cap)++)
435: {
1.4 roy 436: if (esc == '\0') {
1.1 roy 437: if (**cap == '\\' || **cap == '^')
1.4 roy 438: esc = **cap;
439: } else {
440: /* termcap /E/ is valid */
441: if (sep == ':' && esc == '\\' && **cap == 'E')
442: esc = 'x';
443: else
444: esc = '\0';
445: }
1.1 roy 446: }
447:
448: if (**cap != '\0')
449: *(*cap)++ = '\0';
450:
451: return token;
452: }
453:
454: TIC *
455: _ti_compile(char *cap, int flags)
456: {
457: char *token, *p, *e, *name, *desc, *alias;
458: signed char flag;
1.5 roy 459: long cnum;
460: short num;
1.1 roy 461: ssize_t ind;
462: size_t len;
463: TBUF buf;
464: TIC *tic;
465:
1.9 roy 466: _DIAGASSERT(cap != NULL);
1.1 roy 467:
1.4 roy 468: name = _ti_get_token(&cap, ',');
1.1 roy 469: if (name == NULL) {
470: dowarn(flags, "no seperator found: %s", cap);
471: return NULL;
472: }
473: desc = strrchr(name, '|');
474: if (desc != NULL)
475: *desc++ = '\0';
476: alias = strchr(name, '|');
477: if (alias != NULL)
478: *alias++ = '\0';
479:
480: tic = calloc(sizeof(*tic), 1);
481: if (tic == NULL)
482: return NULL;
483:
484: buf.buf = NULL;
485: buf.buflen = 0;
486:
487: tic->name = strdup(name);
488: if (tic->name == NULL)
489: goto error;
490: if (alias != NULL && flags & TIC_ALIAS) {
491: tic->alias = strdup(alias);
492: if (tic->alias == NULL)
493: goto error;
494: }
495: if (desc != NULL && flags & TIC_DESCRIPTION) {
496: tic->desc = strdup(desc);
497: if (tic->desc == NULL)
498: goto error;
499: }
500:
1.4 roy 501: for (token = _ti_get_token(&cap, ',');
1.1 roy 502: token != NULL && *token != '\0';
1.4 roy 503: token = _ti_get_token(&cap, ','))
1.1 roy 504: {
505: /* Skip commented caps */
506: if (!(flags & TIC_COMMENT) && token[0] == '.')
507: continue;
508:
509: /* Obsolete entries */
510: if (token[0] == 'O' && token[1] == 'T') {
511: if (!(flags & TIC_EXTRA))
512: continue;
513: token += 2;
514: }
515:
516: /* str cap */
517: p = strchr(token, '=');
518: if (p != NULL) {
519: *p++ = '\0';
520: /* Don't use the string if we already have it */
521: ind = _ti_strindex(token);
522: if (ind != -1 &&
523: _ti_find_cap(&tic->strs, 's', ind) != NULL)
524: continue;
525:
526: /* Encode the string to our scratch buffer */
527: buf.bufpos = 0;
528: if (encode_string(tic->name, token,
529: &buf, p, flags) == -1)
530: goto error;
531: if (buf.bufpos > UINT16_T_MAX) {
532: dowarn(flags, "%s: %s: string is too long",
533: tic->name, token);
534: continue;
535: }
536: if (!VALID_STRING(buf.buf)) {
537: dowarn(flags, "%s: %s: invalid string",
538: tic->name, token);
539: continue;
540: }
541:
542: if (ind == -1)
543: _ti_store_extra(tic, 1, token, 's', -1, -2,
544: buf.buf, buf.bufpos, flags);
545: else {
546: if (!_ti_grow_tbuf(&tic->strs,
547: (sizeof(uint16_t) * 2) + buf.bufpos))
548: goto error;
549: le16enc(tic->strs.buf + tic->strs.bufpos, ind);
550: tic->strs.bufpos += sizeof(uint16_t);
551: le16enc(tic->strs.buf + tic->strs.bufpos,
552: buf.bufpos);
553: tic->strs.bufpos += sizeof(uint16_t);
554: memcpy(tic->strs.buf + tic->strs.bufpos,
555: buf.buf, buf.bufpos);
556: tic->strs.bufpos += buf.bufpos;
557: tic->strs.entries++;
558: }
559: continue;
560: }
561:
562: /* num cap */
563: p = strchr(token, '#');
564: if (p != NULL) {
565: *p++ = '\0';
566: /* Don't use the number if we already have it */
567: ind = _ti_numindex(token);
568: if (ind != -1 &&
569: _ti_find_cap(&tic->nums, 'n', ind) != NULL)
570: continue;
571:
1.5 roy 572: cnum = strtol(p, &e, 0);
1.1 roy 573: if (*e != '\0') {
574: dowarn(flags, "%s: %s: not a number",
575: tic->name, token);
576: continue;
577: }
1.5 roy 578: if (!VALID_NUMERIC(cnum)) {
1.1 roy 579: dowarn(flags, "%s: %s: number out of range",
580: tic->name, token);
581: continue;
582: }
1.5 roy 583: num = (short)cnum;
1.1 roy 584: if (ind == -1)
585: _ti_store_extra(tic, 1, token, 'n', -1,
586: num, NULL, 0, flags);
587: else {
588: if (_ti_grow_tbuf(&tic->nums,
589: sizeof(uint16_t) * 2) == NULL)
590: goto error;
591: le16enc(tic->nums.buf + tic->nums.bufpos, ind);
592: tic->nums.bufpos += sizeof(uint16_t);
593: le16enc(tic->nums.buf + tic->nums.bufpos, num);
594: tic->nums.bufpos += sizeof(uint16_t);
595: tic->nums.entries++;
596: }
597: continue;
598: }
599:
600: flag = 1;
601: len = strlen(token) - 1;
602: if (token[len] == '@') {
603: flag = CANCELLED_BOOLEAN;
604: token[len] = '\0';
605: }
606: ind = _ti_flagindex(token);
607: if (ind == -1 && flag == CANCELLED_BOOLEAN) {
608: if ((ind = _ti_numindex(token)) != -1) {
609: if (_ti_find_cap(&tic->nums, 'n', ind) != NULL)
610: continue;
611: if (_ti_grow_tbuf(&tic->nums,
612: sizeof(uint16_t) * 2) == NULL)
613: goto error;
614: le16enc(tic->nums.buf + tic->nums.bufpos, ind);
615: tic->nums.bufpos += sizeof(uint16_t);
616: le16enc(tic->nums.buf + tic->nums.bufpos,
1.5 roy 617: (uint16_t)CANCELLED_NUMERIC);
1.1 roy 618: tic->nums.bufpos += sizeof(uint16_t);
619: tic->nums.entries++;
620: continue;
621: } else if ((ind = _ti_strindex(token)) != -1) {
622: if (_ti_find_cap(&tic->strs, 's', ind) != NULL)
623: continue;
624: if (_ti_grow_tbuf(&tic->strs,
625: (sizeof(uint16_t) * 2) + 1) == NULL)
626: goto error;
627: le16enc(tic->strs.buf + tic->strs.bufpos, ind);
628: tic->strs.bufpos += sizeof(uint16_t);
629: le16enc(tic->strs.buf + tic->strs.bufpos, 0);
630: tic->strs.bufpos += sizeof(uint16_t);
631: tic->strs.entries++;
632: continue;
633: }
634: }
635: if (ind == -1)
636: _ti_store_extra(tic, 1, token, 'f', flag, 0, NULL, 0,
637: flags);
638: else if (_ti_find_cap(&tic->flags, 'f', ind) == NULL) {
639: if (_ti_grow_tbuf(&tic->flags, sizeof(uint16_t) + 1)
640: == NULL)
641: goto error;
642: le16enc(tic->flags.buf + tic->flags.bufpos, ind);
643: tic->flags.bufpos += sizeof(uint16_t);
644: tic->flags.buf[tic->flags.bufpos++] = flag;
645: tic->flags.entries++;
646: }
647: }
648:
649: free(buf.buf);
650: return tic;
651:
652: error:
653: free(buf.buf);
654: _ti_freetic(tic);
655: return NULL;
656: }
657:
658: void
659: _ti_freetic(TIC *tic)
660: {
661:
662: if (tic != NULL) {
663: free(tic->name);
664: free(tic->alias);
665: free(tic->desc);
1.7 joerg 666: free(tic->extras.buf);
1.1 roy 667: free(tic->flags.buf);
668: free(tic->nums.buf);
669: free(tic->strs.buf);
670: free(tic);
671: }
672: }
CVSweb <webmaster@jp.NetBSD.org>