1*96dad784Sandvar /* $NetBSD: termcap.c,v 1.25 2023/01/31 21:11:24 andvar Exp $ */
24ca00e00Sroy
34ca00e00Sroy /*
44ca00e00Sroy * Copyright (c) 2009 The NetBSD Foundation, Inc.
54ca00e00Sroy *
64ca00e00Sroy * This code is derived from software contributed to The NetBSD Foundation
74ca00e00Sroy * by Roy Marples.
84ca00e00Sroy *
94ca00e00Sroy * Redistribution and use in source and binary forms, with or without
104ca00e00Sroy * modification, are permitted provided that the following conditions
114ca00e00Sroy * are met:
124ca00e00Sroy * 1. Redistributions of source code must retain the above copyright
134ca00e00Sroy * notice, this list of conditions and the following disclaimer.
144ca00e00Sroy * 2. Redistributions in binary form must reproduce the above copyright
154ca00e00Sroy * notice, this list of conditions and the following disclaimer in the
164ca00e00Sroy * documentation and/or other materials provided with the distribution.
174ca00e00Sroy *
184ca00e00Sroy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
194ca00e00Sroy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204ca00e00Sroy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
214ca00e00Sroy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
224ca00e00Sroy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
234ca00e00Sroy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244ca00e00Sroy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254ca00e00Sroy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264ca00e00Sroy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
274ca00e00Sroy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284ca00e00Sroy */
294ca00e00Sroy
304ca00e00Sroy #include <sys/cdefs.h>
31*96dad784Sandvar __RCSID("$NetBSD: termcap.c,v 1.25 2023/01/31 21:11:24 andvar Exp $");
324ca00e00Sroy
334ca00e00Sroy #include <assert.h>
34007ba6f7Sroy #include <ctype.h>
35007ba6f7Sroy #include <errno.h>
3604f58b48Sroy #include <stdbool.h>
37eedd9adeSroy #include <stdint.h>
384ca00e00Sroy #include <string.h>
394ca00e00Sroy #include <term_private.h>
404ca00e00Sroy #include <term.h>
414ca00e00Sroy #include <termcap.h>
424ca00e00Sroy #include <unistd.h>
434ca00e00Sroy #include <stdio.h>
444ca00e00Sroy
454ca00e00Sroy #include "termcap_map.c"
464ca00e00Sroy #include "termcap_hash.c"
474ca00e00Sroy
484ca00e00Sroy char *UP;
494ca00e00Sroy char *BC;
504ca00e00Sroy
514ca00e00Sroy /* ARGSUSED */
524ca00e00Sroy int
tgetent(__unused char * bp,const char * name)534ca00e00Sroy tgetent(__unused char *bp, const char *name)
544ca00e00Sroy {
554ca00e00Sroy int errret;
564ca00e00Sroy static TERMINAL *last = NULL;
574ca00e00Sroy
584ca00e00Sroy _DIAGASSERT(name != NULL);
594ca00e00Sroy
604ca00e00Sroy /* Free the old term */
618b22ec00Schristos if (cur_term != NULL) {
628b22ec00Schristos if (last != NULL && cur_term != last)
634ca00e00Sroy del_curterm(last);
648b22ec00Schristos last = cur_term;
654ca00e00Sroy }
664ca00e00Sroy errret = -1;
674ca00e00Sroy if (setupterm(name, STDOUT_FILENO, &errret) != 0)
684ca00e00Sroy return errret;
698b22ec00Schristos
708b22ec00Schristos if (last == NULL)
714ca00e00Sroy last = cur_term;
724ca00e00Sroy
734ca00e00Sroy if (pad_char != NULL)
744ca00e00Sroy PC = pad_char[0];
754ca00e00Sroy UP = __UNCONST(cursor_up);
764ca00e00Sroy BC = __UNCONST(cursor_left);
774ca00e00Sroy return 1;
784ca00e00Sroy }
794ca00e00Sroy
804ca00e00Sroy int
tgetflag(const char * id2)81cc9ecc5eSchristos tgetflag(const char *id2)
824ca00e00Sroy {
834ca00e00Sroy uint32_t ind;
844ca00e00Sroy size_t i;
854ca00e00Sroy TERMUSERDEF *ud;
86b9c2e080Schristos const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
874ca00e00Sroy
884ca00e00Sroy if (cur_term == NULL)
894ca00e00Sroy return 0;
904ca00e00Sroy
914ca00e00Sroy ind = _t_flaghash((const unsigned char *)id, strlen(id));
9253035e70Sroy if (ind < __arraycount(_ti_cap_flagids)) {
934ca00e00Sroy if (strcmp(id, _ti_cap_flagids[ind].id) == 0)
944ca00e00Sroy return cur_term->flags[_ti_cap_flagids[ind].ti];
954ca00e00Sroy }
964ca00e00Sroy for (i = 0; i < cur_term->_nuserdefs; i++) {
974ca00e00Sroy ud = &cur_term->_userdefs[i];
984ca00e00Sroy if (ud->type == 'f' && strcmp(ud->id, id) == 0)
994ca00e00Sroy return ud->flag;
1004ca00e00Sroy }
1014ca00e00Sroy return 0;
1024ca00e00Sroy }
1034ca00e00Sroy
1044ca00e00Sroy int
tgetnum(const char * id2)105cc9ecc5eSchristos tgetnum(const char *id2)
1064ca00e00Sroy {
1074ca00e00Sroy uint32_t ind;
1084ca00e00Sroy size_t i;
1094ca00e00Sroy TERMUSERDEF *ud;
1104ca00e00Sroy const TENTRY *te;
111b9c2e080Schristos const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
1124ca00e00Sroy
1134ca00e00Sroy if (cur_term == NULL)
1144ca00e00Sroy return -1;
1154ca00e00Sroy
1164ca00e00Sroy ind = _t_numhash((const unsigned char *)id, strlen(id));
11753035e70Sroy if (ind < __arraycount(_ti_cap_numids)) {
1184ca00e00Sroy te = &_ti_cap_numids[ind];
1194ca00e00Sroy if (strcmp(id, te->id) == 0) {
1204ca00e00Sroy if (!VALID_NUMERIC(cur_term->nums[te->ti]))
1214ca00e00Sroy return ABSENT_NUMERIC;
1224ca00e00Sroy return cur_term->nums[te->ti];
1234ca00e00Sroy }
1244ca00e00Sroy }
1254ca00e00Sroy for (i = 0; i < cur_term->_nuserdefs; i++) {
1264ca00e00Sroy ud = &cur_term->_userdefs[i];
1274ca00e00Sroy if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
1284ca00e00Sroy if (!VALID_NUMERIC(ud->num))
1294ca00e00Sroy return ABSENT_NUMERIC;
1304ca00e00Sroy return ud->num;
1314ca00e00Sroy }
1324ca00e00Sroy }
1334ca00e00Sroy return -1;
1344ca00e00Sroy }
1354ca00e00Sroy
1364ca00e00Sroy char *
tgetstr(const char * id2,char ** area)137cc9ecc5eSchristos tgetstr(const char *id2, char **area)
1384ca00e00Sroy {
1394ca00e00Sroy uint32_t ind;
1404ca00e00Sroy size_t i;
1414ca00e00Sroy TERMUSERDEF *ud;
1424ca00e00Sroy const char *str;
143b9c2e080Schristos const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
1444ca00e00Sroy
1454ca00e00Sroy if (cur_term == NULL)
1464ca00e00Sroy return NULL;
1474ca00e00Sroy
1484ca00e00Sroy str = NULL;
1494ca00e00Sroy ind = _t_strhash((const unsigned char *)id, strlen(id));
15053035e70Sroy if (ind < __arraycount(_ti_cap_strids)) {
1514ca00e00Sroy if (strcmp(id, _ti_cap_strids[ind].id) == 0) {
1524ca00e00Sroy str = cur_term->strs[_ti_cap_strids[ind].ti];
1534ca00e00Sroy if (str == NULL)
1544ca00e00Sroy return NULL;
1554ca00e00Sroy }
1564ca00e00Sroy }
1574ca00e00Sroy if (str != NULL)
1584ca00e00Sroy for (i = 0; i < cur_term->_nuserdefs; i++) {
1594ca00e00Sroy ud = &cur_term->_userdefs[i];
1604ca00e00Sroy if (ud->type == 's' && strcmp(ud->id, id) == 0)
1614ca00e00Sroy str = ud->str;
1624ca00e00Sroy }
1634ca00e00Sroy
164*96dad784Sandvar /* XXX: FIXME
1654ca00e00Sroy * We should fix sgr0(me) as it has a slightly different meaning
1664ca00e00Sroy * for termcap. */
1674ca00e00Sroy
1684ca00e00Sroy if (str != NULL && area != NULL && *area != NULL) {
1694ca00e00Sroy char *s;
1704ca00e00Sroy s = *area;
1714ca00e00Sroy strcpy(*area, str);
1724ca00e00Sroy *area += strlen(*area) + 1;
1734ca00e00Sroy return s;
1744ca00e00Sroy }
1754ca00e00Sroy
1764ca00e00Sroy return __UNCONST(str);
1774ca00e00Sroy }
1784ca00e00Sroy
1794ca00e00Sroy char *
tgoto(const char * cm,int destcol,int destline)1804ca00e00Sroy tgoto(const char *cm, int destcol, int destline)
1814ca00e00Sroy {
1824ca00e00Sroy _DIAGASSERT(cm != NULL);
18339aae097Sroy return tiparm(cm, destline, destcol);
1844ca00e00Sroy }
185007ba6f7Sroy
186b6924e8aSmartin #ifdef TERMINFO_COMPILE
187007ba6f7Sroy static const char *
flagname(const char * key)188007ba6f7Sroy flagname(const char *key)
189007ba6f7Sroy {
190007ba6f7Sroy uint32_t idx;
191007ba6f7Sroy
192007ba6f7Sroy idx = _t_flaghash((const unsigned char *)key, strlen(key));
19353035e70Sroy if (idx < __arraycount(_ti_cap_flagids) &&
194007ba6f7Sroy strcmp(key, _ti_cap_flagids[idx].id) == 0)
195007ba6f7Sroy return _ti_flagid(_ti_cap_flagids[idx].ti);
196007ba6f7Sroy return key;
197007ba6f7Sroy }
198007ba6f7Sroy
199007ba6f7Sroy static const char *
numname(const char * key)200007ba6f7Sroy numname(const char *key)
201007ba6f7Sroy {
202007ba6f7Sroy uint32_t idx;
203007ba6f7Sroy
204007ba6f7Sroy idx = _t_numhash((const unsigned char *)key, strlen(key));
20553035e70Sroy if (idx < __arraycount(_ti_cap_numids) &&
206007ba6f7Sroy strcmp(key, _ti_cap_numids[idx].id) == 0)
207007ba6f7Sroy return _ti_numid(_ti_cap_numids[idx].ti);
208007ba6f7Sroy return key;
209007ba6f7Sroy }
210007ba6f7Sroy
211007ba6f7Sroy static const char *
strname(const char * key)212007ba6f7Sroy strname(const char *key)
213007ba6f7Sroy {
214007ba6f7Sroy uint32_t idx;
215007ba6f7Sroy
216007ba6f7Sroy idx = _t_strhash((const unsigned char *)key, strlen(key));
21753035e70Sroy if (idx < __arraycount(_ti_cap_strids) &&
218007ba6f7Sroy strcmp(key, _ti_cap_strids[idx].id) == 0)
219007ba6f7Sroy return _ti_strid(_ti_cap_strids[idx].ti);
220007ba6f7Sroy
221007ba6f7Sroy if (strcmp(key, "tc") == 0)
222007ba6f7Sroy return "use";
223007ba6f7Sroy
224007ba6f7Sroy return key;
225007ba6f7Sroy }
226007ba6f7Sroy
227f42fd8d0Sroy /* Print a parameter if needed */
22804f58b48Sroy static size_t
printparam(char ** dst,char p,bool * nop)22904f58b48Sroy printparam(char **dst, char p, bool *nop)
230f42fd8d0Sroy {
23104f58b48Sroy if (*nop) {
23204f58b48Sroy *nop = false;
233f42fd8d0Sroy return 0;
234f42fd8d0Sroy }
235f42fd8d0Sroy
236f42fd8d0Sroy *(*dst)++ = '%';
237f42fd8d0Sroy *(*dst)++ = 'p';
238f42fd8d0Sroy *(*dst)++ = '0' + p;
239f42fd8d0Sroy return 3;
240f42fd8d0Sroy }
241f42fd8d0Sroy
24240109496Sroy /* Convert a termcap character into terminfo equivalents */
24304f58b48Sroy static size_t
printchar(char ** dst,const char ** src)24440109496Sroy printchar(char **dst, const char **src)
24540109496Sroy {
24604f58b48Sroy char v;
24704f58b48Sroy size_t l;
24840109496Sroy
24940109496Sroy l = 4;
25004f58b48Sroy v = *++(*src);
25140109496Sroy if (v == '\\') {
25204f58b48Sroy v = *++(*src);
25340109496Sroy switch (v) {
25440109496Sroy case '0':
25540109496Sroy case '1':
25640109496Sroy case '2':
25740109496Sroy case '3':
25840109496Sroy v = 0;
25940109496Sroy while (isdigit((unsigned char) **src))
26004f58b48Sroy v = 8 * v + (*(*src)++ - '0');
26140109496Sroy (*src)--;
26240109496Sroy break;
26340109496Sroy case '\0':
26440109496Sroy v = '\\';
26540109496Sroy break;
26640109496Sroy }
26740109496Sroy } else if (v == '^')
26804f58b48Sroy v = *++(*src) & 0x1f;
26940109496Sroy *(*dst)++ = '%';
27004f58b48Sroy if (isgraph((unsigned char )v) &&
27104f58b48Sroy v != ',' && v != '\'' && v != '\\' && v != ':')
27204f58b48Sroy {
27340109496Sroy *(*dst)++ = '\'';
27440109496Sroy *(*dst)++ = v;
27540109496Sroy *(*dst)++ = '\'';
27640109496Sroy } else {
27740109496Sroy *(*dst)++ = '{';
27840109496Sroy if (v > 99) {
27940109496Sroy *(*dst)++ = '0'+ v / 100;
28040109496Sroy l++;
28140109496Sroy }
28240109496Sroy if (v > 9) {
28340109496Sroy *(*dst)++ = '0' + ((int) (v / 10)) % 10;
28440109496Sroy l++;
28540109496Sroy }
28640109496Sroy *(*dst)++ = '0' + v % 10;
28740109496Sroy *(*dst)++ = '}';
28840109496Sroy }
28940109496Sroy return l;
29040109496Sroy }
29140109496Sroy
29240109496Sroy /* Convert termcap commands into terminfo commands */
293f42fd8d0Sroy static const char fmtB[] = "%p0%{10}%/%{16}%*%p0%{10}%m%+";
294f42fd8d0Sroy static const char fmtD[] = "%p0%p0%{2}%*%-";
295f42fd8d0Sroy static const char fmtIf[] = "%p0%p0%?";
296f42fd8d0Sroy static const char fmtThen[] = "%>%t";
297f42fd8d0Sroy static const char fmtElse[] = "%+%;";
298f42fd8d0Sroy
299007ba6f7Sroy static char *
strval(const char * val)300007ba6f7Sroy strval(const char *val)
301007ba6f7Sroy {
30204f58b48Sroy char *info, *ip, c, p;
3036855db0fSroy const char *ps, *pe;
30404f58b48Sroy bool nop;
305e6dabc3cSchristos size_t len, l;
306007ba6f7Sroy
307007ba6f7Sroy len = 1024; /* no single string should be bigger */
308007ba6f7Sroy info = ip = malloc(len);
309007ba6f7Sroy if (info == NULL)
310007ba6f7Sroy return 0;
311007ba6f7Sroy
3126855db0fSroy /* Move the = */
3136855db0fSroy *ip++ = *val++;
3146855db0fSroy
3156855db0fSroy /* Set ps and pe to point to the start and end of the padding */
3166855db0fSroy if (isdigit((unsigned char)*val)) {
3176855db0fSroy for (ps = pe = val;
3186855db0fSroy isdigit((unsigned char)*val) || *val == '.';
3196855db0fSroy val++)
3206855db0fSroy pe++;
3216855db0fSroy if (*val == '*') {
3226855db0fSroy val++;
3236855db0fSroy pe++;
3246855db0fSroy }
3256855db0fSroy } else
3266855db0fSroy ps = pe = NULL;
3276855db0fSroy
32804f58b48Sroy nop = false;
32904f58b48Sroy l = 0;
330007ba6f7Sroy p = 1;
331007ba6f7Sroy for (; *val != '\0'; val++) {
332007ba6f7Sroy if (l + 2 > len)
333007ba6f7Sroy goto elen;
334007ba6f7Sroy if (*val != '%') {
335c6aefd4dSroy if (*val == ',') {
336c6aefd4dSroy if (l + 3 > len)
337c6aefd4dSroy goto elen;
338c6aefd4dSroy *ip++ = '\\';
339c6aefd4dSroy l++;
340c6aefd4dSroy }
341007ba6f7Sroy *ip++ = *val;
342007ba6f7Sroy l++;
343007ba6f7Sroy continue;
344007ba6f7Sroy }
34540109496Sroy switch (c = *++(val)) {
34640109496Sroy case 'B':
347f42fd8d0Sroy if (l + sizeof(fmtB) > len)
34840109496Sroy goto elen;
349f42fd8d0Sroy memcpy(ip, fmtB, sizeof(fmtB) - 1);
350f42fd8d0Sroy /* Replace the embedded parameters with real ones */
351f42fd8d0Sroy ip[2] += p;
352f42fd8d0Sroy ip[19] += p;
353f42fd8d0Sroy ip += sizeof(fmtB) - 1;
354f42fd8d0Sroy l += sizeof(fmtB) - 1;
35504f58b48Sroy nop = true;
35640109496Sroy continue;
35740109496Sroy case 'D':
358f42fd8d0Sroy if (l + sizeof(fmtD) > len)
359007ba6f7Sroy goto elen;
360f42fd8d0Sroy memcpy(ip, fmtD, sizeof(fmtD) - 1);
361f42fd8d0Sroy /* Replace the embedded parameters with real ones */
362f42fd8d0Sroy ip[2] += p;
363f42fd8d0Sroy ip[5] += p;
364f42fd8d0Sroy ip += sizeof(fmtD) - 1;
365f42fd8d0Sroy l += sizeof(fmtD) - 1;
36604f58b48Sroy nop = true;
36740109496Sroy continue;
368007ba6f7Sroy case 'r':
36940109496Sroy /* non op as switched below */
37040109496Sroy break;
37140109496Sroy case '2': /* FALLTHROUGH */
37240109496Sroy case '3': /* FALLTHROUGH */
37340109496Sroy case 'd':
37440109496Sroy if (l + 7 > len)
37540109496Sroy goto elen;
376f42fd8d0Sroy l += printparam(&ip, p, &nop);
37740109496Sroy *ip++ = '%';
37840109496Sroy if (c != 'd') {
37940109496Sroy *ip++ = c;
38040109496Sroy l++;
38140109496Sroy }
38240109496Sroy *ip++ = 'd';
38340109496Sroy l += 2;
38440109496Sroy break;
38540109496Sroy case '+':
38640109496Sroy if (l + 13 > len)
38740109496Sroy goto elen;
388f42fd8d0Sroy l += printparam(&ip, p, &nop);
38940109496Sroy l += printchar(&ip, &val);
39040109496Sroy *ip++ = '%';
39140109496Sroy *ip++ = c;
39240109496Sroy *ip++ = '%';
39340109496Sroy *ip++ = 'c';
39440109496Sroy l += 7;
39540109496Sroy break;
39640109496Sroy case '>':
397f42fd8d0Sroy if (l + sizeof(fmtIf) + sizeof(fmtThen) +
398f42fd8d0Sroy sizeof(fmtElse) + (6 * 2) > len)
39940109496Sroy goto elen;
400f42fd8d0Sroy
401f42fd8d0Sroy memcpy(ip, fmtIf, sizeof(fmtIf) - 1);
402f42fd8d0Sroy /* Replace the embedded parameters with real ones */
403f42fd8d0Sroy ip[2] += p;
404f42fd8d0Sroy ip[5] += p;
405f42fd8d0Sroy ip += sizeof(fmtIf) - 1;
406f42fd8d0Sroy l += sizeof(fmtIf) - 1;
40740109496Sroy l += printchar(&ip, &val);
408f42fd8d0Sroy memcpy(ip, fmtThen, sizeof(fmtThen) - 1);
409f42fd8d0Sroy ip += sizeof(fmtThen) - 1;
410f42fd8d0Sroy l += sizeof(fmtThen) - 1;
41140109496Sroy l += printchar(&ip, &val);
412f42fd8d0Sroy memcpy(ip, fmtElse, sizeof(fmtElse) - 1);
413f42fd8d0Sroy ip += sizeof(fmtElse) - 1;
414f42fd8d0Sroy l += sizeof(fmtElse) - 1;
41540109496Sroy l += 16;
41604f58b48Sroy nop = true;
41740109496Sroy continue;
41840109496Sroy case '.':
41940109496Sroy if (l + 6 > len)
42040109496Sroy goto elen;
421f42fd8d0Sroy l += printparam(&ip, p, &nop);
42240109496Sroy *ip++ = '%';
42340109496Sroy *ip++ = 'c';
42440109496Sroy l += 2;
425007ba6f7Sroy break;
426007ba6f7Sroy default:
427007ba6f7Sroy /* Hope it matches a terminfo command. */
428007ba6f7Sroy *ip++ = '%';
429007ba6f7Sroy *ip++ = c;
430007ba6f7Sroy l += 2;
43140109496Sroy if (c == 'i')
43240109496Sroy continue;
433007ba6f7Sroy break;
434007ba6f7Sroy }
43540109496Sroy /* Swap p1 and p2 */
43640109496Sroy p = 3 - p;
437007ba6f7Sroy }
438007ba6f7Sroy
4394b2d6106Sroy /* \E\ is valid termcap.
4404b2d6106Sroy * We need to escape the final \ for terminfo. */
4414b2d6106Sroy if (l > 2 && info[l - 1] == '\\' &&
4424b2d6106Sroy (info[l - 2] != '\\' && info[l - 2] != '^'))
4434b2d6106Sroy {
4444b2d6106Sroy if (l + 1 > len)
4454b2d6106Sroy goto elen;
4464b2d6106Sroy *ip++ = '\\';
4474b2d6106Sroy }
4484b2d6106Sroy
4496855db0fSroy /* Add our padding at the end. */
4506855db0fSroy if (ps != NULL) {
45104f58b48Sroy size_t n = (size_t)(pe - ps);
4526855db0fSroy if (l + n + 4 > len)
4536855db0fSroy goto elen;
4546855db0fSroy *ip++ = '$';
4556855db0fSroy *ip++ = '<';
4566855db0fSroy strncpy(ip, ps, n);
4576855db0fSroy ip += n;
4586855db0fSroy *ip++ = '/';
4596855db0fSroy *ip++ = '>';
4606855db0fSroy }
4616855db0fSroy
462007ba6f7Sroy *ip = '\0';
463007ba6f7Sroy return info;
464007ba6f7Sroy
465007ba6f7Sroy elen:
466007ba6f7Sroy free(info);
467007ba6f7Sroy errno = ENOMEM;
468007ba6f7Sroy return NULL;
469007ba6f7Sroy }
470007ba6f7Sroy
471215c5976Sroy typedef struct {
4726855db0fSroy const char *name;
4736855db0fSroy const char *cap;
474215c5976Sroy } DEF_INFO;
475215c5976Sroy
476215c5976Sroy static DEF_INFO def_infos[] = {
4776855db0fSroy { "bel", "^G" },
4786855db0fSroy { "cr", "^M" },
4796855db0fSroy { "cud1", "^J" },
4806855db0fSroy { "ht", "^I" },
4816855db0fSroy { "ind", "^J" },
4826855db0fSroy { "kbs", "^H" },
4836855db0fSroy { "kcub1", "^H" },
4846855db0fSroy { "kcud1", "^J" },
4856855db0fSroy { "nel", "^M^J" }
4866855db0fSroy };
4876855db0fSroy
488007ba6f7Sroy char *
captoinfo(char * cap)489007ba6f7Sroy captoinfo(char *cap)
490007ba6f7Sroy {
491007ba6f7Sroy char *info, *ip, *token, *val, *p, tok[3];
492007ba6f7Sroy const char *name;
493007ba6f7Sroy size_t len, lp, nl, vl, rl;
4941f27d9b1Sroy int defs[__arraycount(def_infos)], fv;
495007ba6f7Sroy
496007ba6f7Sroy _DIAGASSERT(cap != NULL);
497007ba6f7Sroy
498007ba6f7Sroy len = strlen(cap) * 2;
4996855db0fSroy len += __arraycount(def_infos) * (5 + 4 + 3); /* reserve for defs */
500007ba6f7Sroy info = ip = malloc(len);
501007ba6f7Sroy if (info == NULL)
502007ba6f7Sroy return NULL;
503007ba6f7Sroy
5046855db0fSroy memset(defs, 0, sizeof(defs));
505007ba6f7Sroy lp = 0;
506007ba6f7Sroy tok[2] = '\0';
5074b2d6106Sroy for (token = _ti_get_token(&cap, ':');
5084b2d6106Sroy token != NULL;
5094b2d6106Sroy token = _ti_get_token(&cap, ':'))
5104b2d6106Sroy {
511007ba6f7Sroy if (token[0] == '\0')
512007ba6f7Sroy continue;
513007ba6f7Sroy name = token;
5141f27d9b1Sroy val = p = NULL;
5151d30fdaeSchristos fv = 0;
5161d30fdaeSchristos nl = 0;
517007ba6f7Sroy if (token[1] != '\0') {
518007ba6f7Sroy tok[0] = token[0];
519007ba6f7Sroy tok[1] = token[1];
5201f27d9b1Sroy nl = 1;
521007ba6f7Sroy if (token[2] == '\0') {
522007ba6f7Sroy name = flagname(tok);
523007ba6f7Sroy val = NULL;
524007ba6f7Sroy } else if (token[2] == '#') {
525007ba6f7Sroy name = numname(tok);
526007ba6f7Sroy val = token + 2;
527007ba6f7Sroy } else if (token[2] == '=') {
528007ba6f7Sroy name = strname(tok);
529007ba6f7Sroy val = strval(token + 2);
5301f27d9b1Sroy fv = 1;
5311f27d9b1Sroy } else
5321f27d9b1Sroy nl = 0;
5331f27d9b1Sroy }
5341f27d9b1Sroy /* If not matched we may need to convert padding still. */
5351f27d9b1Sroy if (nl == 0) {
5361f27d9b1Sroy p = strchr(name, '=');
5371f27d9b1Sroy if (p != NULL) {
5381f27d9b1Sroy val = strval(p);
5391f27d9b1Sroy *p = '\0';
5401f27d9b1Sroy fv = 1;
541007ba6f7Sroy }
542007ba6f7Sroy }
5436855db0fSroy
5446855db0fSroy /* See if this sets a default. */
5456855db0fSroy for (nl = 0; nl < __arraycount(def_infos); nl++) {
5466855db0fSroy if (strcmp(name, def_infos[nl].name) == 0) {
5476855db0fSroy defs[nl] = 1;
5486855db0fSroy break;
5496855db0fSroy }
5506855db0fSroy }
5516855db0fSroy
552007ba6f7Sroy nl = strlen(name);
553007ba6f7Sroy if (val == NULL)
554007ba6f7Sroy vl = 0;
555007ba6f7Sroy else
556007ba6f7Sroy vl = strlen(val);
557007ba6f7Sroy rl = nl + vl + 3; /* , \0 */
558007ba6f7Sroy
559007ba6f7Sroy if (lp + rl > len) {
560007ba6f7Sroy if (rl < 256)
561007ba6f7Sroy len += 256;
562007ba6f7Sroy else
563007ba6f7Sroy len += rl;
564007ba6f7Sroy p = realloc(info, len);
565db71acfdSchristos if (p == NULL) {
566db71acfdSchristos if (fv == 1)
567db71acfdSchristos free(val);
568007ba6f7Sroy return NULL;
569db71acfdSchristos }
570007ba6f7Sroy info = p;
571007ba6f7Sroy }
572007ba6f7Sroy
573007ba6f7Sroy if (ip != info) {
574007ba6f7Sroy *ip++ = ',';
575007ba6f7Sroy *ip++ = ' ';
576007ba6f7Sroy }
577007ba6f7Sroy
578007ba6f7Sroy strcpy(ip, name);
579007ba6f7Sroy ip += nl;
580007ba6f7Sroy if (val != NULL) {
581007ba6f7Sroy strcpy(ip, val);
582007ba6f7Sroy ip += vl;
5831f27d9b1Sroy if (fv == 1)
584007ba6f7Sroy free(val);
585007ba6f7Sroy }
586007ba6f7Sroy }
587007ba6f7Sroy
5886855db0fSroy /* Add any defaults not set above. */
5896855db0fSroy for (nl = 0; nl < __arraycount(def_infos); nl++) {
5906855db0fSroy if (defs[nl] == 0) {
5916855db0fSroy *ip++ = ',';
5926855db0fSroy *ip++ = ' ';
5936855db0fSroy strcpy(ip, def_infos[nl].name);
5946855db0fSroy ip += strlen(def_infos[nl].name);
5956855db0fSroy *ip++ = '=';
5966855db0fSroy strcpy(ip, def_infos[nl].cap);
5976855db0fSroy ip += strlen(def_infos[nl].cap);
5986855db0fSroy }
5996855db0fSroy }
6006855db0fSroy
601007ba6f7Sroy *ip = '\0';
602007ba6f7Sroy return info;
603007ba6f7Sroy }
604b6924e8aSmartin #endif
605