Home | History | Annotate | Line # | Download | only in libterminfo
termcap.c revision 1.19
      1  1.19  christos /* $NetBSD: termcap.c,v 1.19 2016/04/01 19:59:08 christos Exp $ */
      2   1.1       roy 
      3   1.1       roy /*
      4   1.1       roy  * Copyright (c) 2009 The NetBSD Foundation, Inc.
      5   1.1       roy  *
      6   1.1       roy  * This code is derived from software contributed to The NetBSD Foundation
      7   1.1       roy  * by Roy Marples.
      8   1.1       roy  *
      9   1.1       roy  * Redistribution and use in source and binary forms, with or without
     10   1.1       roy  * modification, are permitted provided that the following conditions
     11   1.1       roy  * are met:
     12   1.1       roy  * 1. Redistributions of source code must retain the above copyright
     13   1.1       roy  *    notice, this list of conditions and the following disclaimer.
     14   1.1       roy  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.1       roy  *    notice, this list of conditions and the following disclaimer in the
     16   1.1       roy  *    documentation and/or other materials provided with the distribution.
     17   1.1       roy  *
     18   1.1       roy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19   1.1       roy  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20   1.1       roy  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21   1.1       roy  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22   1.1       roy  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23   1.1       roy  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24   1.1       roy  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25   1.1       roy  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26   1.1       roy  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27   1.1       roy  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28   1.1       roy  */
     29   1.1       roy 
     30   1.1       roy #include <sys/cdefs.h>
     31  1.19  christos __RCSID("$NetBSD: termcap.c,v 1.19 2016/04/01 19:59:08 christos Exp $");
     32   1.1       roy 
     33   1.1       roy #include <assert.h>
     34   1.3       roy #include <ctype.h>
     35   1.3       roy #include <errno.h>
     36   1.2       roy #include <stdint.h>
     37   1.1       roy #include <string.h>
     38   1.1       roy #include <term_private.h>
     39   1.1       roy #include <term.h>
     40   1.1       roy #include <termcap.h>
     41   1.1       roy #include <unistd.h>
     42   1.1       roy #include <stdio.h>
     43   1.1       roy 
     44   1.1       roy #include "termcap_map.c"
     45   1.1       roy #include "termcap_hash.c"
     46   1.1       roy 
     47   1.1       roy char *UP;
     48   1.1       roy char *BC;
     49   1.1       roy 
     50   1.1       roy /* ARGSUSED */
     51   1.1       roy int
     52   1.1       roy tgetent(__unused char *bp, const char *name)
     53   1.1       roy {
     54   1.1       roy 	int errret;
     55   1.1       roy 	static TERMINAL *last = NULL;
     56   1.1       roy 
     57   1.1       roy 	_DIAGASSERT(name != NULL);
     58   1.1       roy 
     59   1.1       roy 	/* Free the old term */
     60  1.19  christos 	if (cur_term != NULL) {
     61  1.19  christos 		if (last != NULL && cur_term != last)
     62  1.19  christos 			del_curterm(last);
     63  1.19  christos 		last = cur_term;
     64   1.1       roy 	}
     65   1.1       roy 	errret = -1;
     66   1.1       roy 	if (setupterm(name, STDOUT_FILENO, &errret) != 0)
     67   1.1       roy 		return errret;
     68  1.19  christos 
     69  1.19  christos 	if (last == NULL)
     70  1.19  christos 		last = cur_term;
     71   1.1       roy 
     72   1.1       roy 	if (pad_char != NULL)
     73   1.1       roy 		PC = pad_char[0];
     74   1.1       roy 	UP = __UNCONST(cursor_up);
     75   1.1       roy 	BC = __UNCONST(cursor_left);
     76   1.1       roy 	return 1;
     77   1.1       roy }
     78   1.1       roy 
     79   1.1       roy int
     80  1.15  christos tgetflag(const char *id2)
     81   1.1       roy {
     82   1.1       roy 	uint32_t ind;
     83   1.1       roy 	size_t i;
     84   1.1       roy 	TERMUSERDEF *ud;
     85  1.17  christos 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
     86   1.1       roy 
     87   1.1       roy 	if (cur_term == NULL)
     88   1.1       roy 		return 0;
     89   1.1       roy 
     90   1.1       roy 	ind = _t_flaghash((const unsigned char *)id, strlen(id));
     91   1.1       roy 	if (ind <= __arraycount(_ti_cap_flagids)) {
     92   1.1       roy 		if (strcmp(id, _ti_cap_flagids[ind].id) == 0)
     93   1.1       roy 			return cur_term->flags[_ti_cap_flagids[ind].ti];
     94   1.1       roy 	}
     95   1.1       roy 	for (i = 0; i < cur_term->_nuserdefs; i++) {
     96   1.1       roy 		ud = &cur_term->_userdefs[i];
     97   1.1       roy 		if (ud->type == 'f' && strcmp(ud->id, id) == 0)
     98   1.1       roy 			return ud->flag;
     99   1.1       roy 	}
    100   1.1       roy 	return 0;
    101   1.1       roy }
    102   1.1       roy 
    103   1.1       roy int
    104  1.15  christos tgetnum(const char *id2)
    105   1.1       roy {
    106   1.1       roy 	uint32_t ind;
    107   1.1       roy 	size_t i;
    108   1.1       roy 	TERMUSERDEF *ud;
    109   1.1       roy 	const TENTRY *te;
    110  1.17  christos 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
    111   1.1       roy 
    112   1.1       roy 	if (cur_term == NULL)
    113   1.1       roy 		return -1;
    114   1.1       roy 
    115   1.1       roy 	ind = _t_numhash((const unsigned char *)id, strlen(id));
    116   1.1       roy 	if (ind <= __arraycount(_ti_cap_numids)) {
    117   1.1       roy 		te = &_ti_cap_numids[ind];
    118   1.1       roy 		if (strcmp(id, te->id) == 0) {
    119   1.1       roy 			if (!VALID_NUMERIC(cur_term->nums[te->ti]))
    120   1.1       roy 				return ABSENT_NUMERIC;
    121   1.1       roy 			return cur_term->nums[te->ti];
    122   1.1       roy 		}
    123   1.1       roy 	}
    124   1.1       roy 	for (i = 0; i < cur_term->_nuserdefs; i++) {
    125   1.1       roy 		ud = &cur_term->_userdefs[i];
    126   1.1       roy 		if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
    127   1.1       roy 			if (!VALID_NUMERIC(ud->num))
    128   1.1       roy 				return ABSENT_NUMERIC;
    129   1.1       roy 			return ud->num;
    130   1.1       roy 		}
    131   1.1       roy 	}
    132   1.1       roy 	return -1;
    133   1.1       roy }
    134   1.1       roy 
    135   1.1       roy char *
    136  1.15  christos tgetstr(const char *id2, char **area)
    137   1.1       roy {
    138   1.1       roy 	uint32_t ind;
    139   1.1       roy 	size_t i;
    140   1.1       roy 	TERMUSERDEF *ud;
    141   1.1       roy 	const char *str;
    142  1.17  christos 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
    143   1.1       roy 
    144   1.1       roy 	if (cur_term == NULL)
    145   1.1       roy 		return NULL;
    146   1.1       roy 
    147   1.1       roy 	str = NULL;
    148   1.1       roy 	ind = _t_strhash((const unsigned char *)id, strlen(id));
    149   1.1       roy 	if (ind <= __arraycount(_ti_cap_strids)) {
    150   1.1       roy 		if (strcmp(id, _ti_cap_strids[ind].id) == 0) {
    151   1.1       roy 			str = cur_term->strs[_ti_cap_strids[ind].ti];
    152   1.1       roy 			if (str == NULL)
    153   1.1       roy 				return NULL;
    154   1.1       roy 		}
    155   1.1       roy 	}
    156   1.1       roy 	if (str != NULL)
    157   1.1       roy 		for (i = 0; i < cur_term->_nuserdefs; i++) {
    158   1.1       roy 			ud = &cur_term->_userdefs[i];
    159   1.1       roy 			if (ud->type == 's' && strcmp(ud->id, id) == 0)
    160   1.1       roy 				str = ud->str;
    161   1.1       roy 		}
    162   1.1       roy 
    163   1.1       roy 	/* XXX: FXIXME
    164   1.1       roy 	 * We should fix sgr0(me) as it has a slightly different meaning
    165   1.1       roy 	 * for termcap. */
    166   1.1       roy 
    167   1.1       roy 	if (str != NULL && area != NULL && *area != NULL) {
    168   1.1       roy 		char *s;
    169   1.1       roy 		s = *area;
    170   1.1       roy 		strcpy(*area, str);
    171   1.1       roy 		*area += strlen(*area) + 1;
    172   1.1       roy 		return s;
    173   1.1       roy 	}
    174   1.1       roy 
    175   1.1       roy 	return __UNCONST(str);
    176   1.1       roy }
    177   1.1       roy 
    178   1.1       roy char *
    179   1.1       roy tgoto(const char *cm, int destcol, int destline)
    180   1.1       roy {
    181   1.1       roy 	_DIAGASSERT(cm != NULL);
    182  1.16       roy 	return tiparm(cm, destline, destcol);
    183   1.1       roy }
    184   1.3       roy 
    185   1.3       roy static const char *
    186   1.3       roy flagname(const char *key)
    187   1.3       roy {
    188   1.3       roy 	uint32_t idx;
    189   1.3       roy 
    190   1.3       roy 	idx = _t_flaghash((const unsigned char *)key, strlen(key));
    191   1.3       roy 	if (idx <= __arraycount(_ti_cap_flagids) &&
    192   1.3       roy 	    strcmp(key, _ti_cap_flagids[idx].id) == 0)
    193   1.3       roy 		return _ti_flagid(_ti_cap_flagids[idx].ti);
    194   1.3       roy 	return key;
    195   1.3       roy }
    196   1.3       roy 
    197   1.3       roy static const char *
    198   1.3       roy numname(const char *key)
    199   1.3       roy {
    200   1.3       roy 	uint32_t idx;
    201   1.3       roy 
    202   1.3       roy 	idx = _t_numhash((const unsigned char *)key, strlen(key));
    203   1.3       roy 	if (idx <= __arraycount(_ti_cap_numids) &&
    204   1.3       roy 	    strcmp(key, _ti_cap_numids[idx].id) == 0)
    205   1.3       roy 		return _ti_numid(_ti_cap_numids[idx].ti);
    206   1.3       roy 	return key;
    207   1.3       roy }
    208   1.3       roy 
    209   1.3       roy static const char *
    210   1.3       roy strname(const char *key)
    211   1.3       roy {
    212   1.3       roy 	uint32_t idx;
    213   1.3       roy 
    214   1.3       roy 	idx = _t_strhash((const unsigned char *)key, strlen(key));
    215   1.3       roy 	if (idx <= __arraycount(_ti_cap_strids) &&
    216   1.3       roy 	    strcmp(key, _ti_cap_strids[idx].id) == 0)
    217   1.3       roy 		return _ti_strid(_ti_cap_strids[idx].ti);
    218   1.3       roy 
    219   1.3       roy 	if (strcmp(key, "tc") == 0)
    220   1.3       roy 		return "use";
    221   1.3       roy 
    222   1.3       roy 	return key;
    223   1.3       roy }
    224   1.3       roy 
    225  1.14       roy /* Print a parameter if needed */
    226  1.14       roy static int
    227  1.14       roy printparam(char **dst, char p, int *nop)
    228  1.14       roy {
    229  1.14       roy 	if (*nop != 0) {
    230  1.14       roy 		*nop = 0;
    231  1.14       roy 		return 0;
    232  1.14       roy 	}
    233  1.14       roy 
    234  1.14       roy 	*(*dst)++ = '%';
    235  1.14       roy 	*(*dst)++ = 'p';
    236  1.14       roy 	*(*dst)++ = '0' + p;
    237  1.14       roy 	return 3;
    238  1.14       roy }
    239  1.14       roy 
    240  1.12       roy /* Convert a termcap character into terminfo equivalents */
    241  1.12       roy static int
    242  1.12       roy printchar(char **dst, const char **src)
    243  1.12       roy {
    244  1.12       roy 	unsigned char v;
    245  1.12       roy 	int l;
    246  1.12       roy 
    247  1.12       roy 	l = 4;
    248  1.12       roy 	v = (unsigned char) *++(*src);
    249  1.12       roy 	if (v == '\\') {
    250  1.12       roy 		v = (unsigned char) *++(*src);
    251  1.12       roy 		switch (v) {
    252  1.12       roy 		case '0':
    253  1.12       roy 		case '1':
    254  1.12       roy 		case '2':
    255  1.12       roy 		case '3':
    256  1.12       roy 			v = 0;
    257  1.12       roy 			while (isdigit((unsigned char) **src))
    258  1.12       roy 				v = 8 * v + ((unsigned char) *(*src)++ - '0');
    259  1.12       roy 			(*src)--;
    260  1.12       roy 			break;
    261  1.12       roy 		case '\0':
    262  1.12       roy 			v = '\\';
    263  1.12       roy 			break;
    264  1.12       roy 		}
    265  1.12       roy 	} else if (v == '^')
    266  1.12       roy 		v = (unsigned char) (*++(*src) & 0x1f);
    267  1.12       roy 	*(*dst)++ = '%';
    268  1.12       roy 	if (isgraph(v) && v != ',' && v != '\'' && v != '\\' && v != ':') {
    269  1.12       roy 		*(*dst)++ = '\'';
    270  1.12       roy 		*(*dst)++ = v;
    271  1.12       roy 		*(*dst)++ = '\'';
    272  1.12       roy 	} else {
    273  1.12       roy 		*(*dst)++ = '{';
    274  1.12       roy 		if (v > 99) {
    275  1.12       roy 			*(*dst)++ = '0'+ v / 100;
    276  1.12       roy 			l++;
    277  1.12       roy 		}
    278  1.12       roy 		if (v > 9) {
    279  1.12       roy 			*(*dst)++ = '0' + ((int) (v / 10)) % 10;
    280  1.12       roy 			l++;
    281  1.12       roy 		}
    282  1.12       roy 		*(*dst)++ = '0' + v % 10;
    283  1.12       roy 		*(*dst)++ = '}';
    284  1.12       roy 	}
    285  1.12       roy 	return l;
    286  1.12       roy }
    287  1.12       roy 
    288  1.12       roy /* Convert termcap commands into terminfo commands */
    289  1.14       roy static const char fmtB[] = "%p0%{10}%/%{16}%*%p0%{10}%m%+";
    290  1.14       roy static const char fmtD[] = "%p0%p0%{2}%*%-";
    291  1.14       roy static const char fmtIf[] = "%p0%p0%?";
    292  1.14       roy static const char fmtThen[] = "%>%t";
    293  1.14       roy static const char fmtElse[] = "%+%;";
    294  1.14       roy 
    295   1.3       roy static char *
    296   1.3       roy strval(const char *val)
    297   1.3       roy {
    298   1.3       roy 	char *info, *ip, c;
    299   1.6       roy 	const char *ps, *pe;
    300  1.12       roy 	int p, nop;
    301  1.10  christos 	size_t len, l;
    302   1.3       roy 
    303   1.3       roy 	len = 1024; /* no single string should be bigger */
    304   1.3       roy 	info = ip = malloc(len);
    305   1.3       roy 	if (info == NULL)
    306   1.3       roy 		return 0;
    307   1.3       roy 
    308   1.6       roy 	/* Move the = */
    309   1.6       roy 	*ip++ = *val++;
    310   1.6       roy 
    311   1.6       roy 	/* Set ps and pe to point to the start and end of the padding */
    312   1.6       roy 	if (isdigit((unsigned char)*val)) {
    313   1.6       roy 		for (ps = pe = val;
    314   1.6       roy 		     isdigit((unsigned char)*val) || *val == '.';
    315   1.6       roy 		     val++)
    316   1.6       roy 			pe++;
    317   1.6       roy 		if (*val == '*') {
    318   1.6       roy 			val++;
    319   1.6       roy 			pe++;
    320   1.6       roy 		}
    321   1.6       roy 	} else
    322   1.6       roy 		ps = pe  = NULL;
    323   1.6       roy 
    324  1.12       roy 	l = nop = 0;
    325   1.3       roy 	p = 1;
    326   1.3       roy 	for (; *val != '\0'; val++) {
    327   1.3       roy 		if (l + 2 > len)
    328   1.3       roy 			goto elen;
    329   1.3       roy 		if (*val != '%') {
    330   1.4       roy 			if (*val == ',') {
    331   1.4       roy 				if (l + 3 > len)
    332   1.4       roy 					goto elen;
    333   1.4       roy 				*ip++ = '\\';
    334   1.4       roy 				l++;
    335   1.4       roy 			}
    336   1.3       roy 			*ip++ = *val;
    337   1.3       roy 			l++;
    338   1.3       roy 			continue;
    339   1.3       roy 		}
    340  1.12       roy 		switch (c = *++(val)) {
    341  1.12       roy 		case 'B':
    342  1.14       roy 			if (l + sizeof(fmtB) > len)
    343  1.12       roy 				goto elen;
    344  1.14       roy 			memcpy(ip, fmtB, sizeof(fmtB) - 1);
    345  1.14       roy 			/* Replace the embedded parameters with real ones */
    346  1.14       roy 			ip[2] += p;
    347  1.14       roy 			ip[19] += p;
    348  1.14       roy 			ip += sizeof(fmtB) - 1;
    349  1.14       roy 			l += sizeof(fmtB) - 1;
    350  1.12       roy 			nop = 1;
    351  1.12       roy 			continue;
    352  1.12       roy 		case 'D':
    353  1.14       roy 			if (l + sizeof(fmtD) > len)
    354  1.12       roy 				goto elen;
    355  1.14       roy 			memcpy(ip, fmtD, sizeof(fmtD) - 1);
    356  1.14       roy 			/* Replace the embedded parameters with real ones */
    357  1.14       roy 			ip[2] += p;
    358  1.14       roy 			ip[5] += p;
    359  1.14       roy 			ip += sizeof(fmtD) - 1;
    360  1.14       roy 			l += sizeof(fmtD) - 1;
    361  1.12       roy 			nop = 1;
    362  1.12       roy 			continue;
    363  1.12       roy 		case 'r':
    364  1.12       roy 			/* non op as switched below */
    365  1.12       roy 			break;
    366  1.12       roy 		case '2': /* FALLTHROUGH */
    367  1.12       roy 		case '3': /* FALLTHROUGH */
    368   1.3       roy 		case 'd':
    369  1.12       roy 			if (l + 7 > len)
    370  1.12       roy 				goto elen;
    371  1.14       roy 			l += printparam(&ip, p, &nop);
    372  1.12       roy 			*ip++ = '%';
    373  1.12       roy 			if (c != 'd') {
    374  1.12       roy 				*ip++ = c;
    375  1.12       roy 				l++;
    376  1.12       roy 			}
    377  1.12       roy 			*ip++ = 'd';
    378  1.12       roy 			l += 2;
    379  1.12       roy 			break;
    380  1.12       roy 		case '+':
    381  1.12       roy 			if (l + 13 > len)
    382  1.12       roy 				goto elen;
    383  1.14       roy 			l += printparam(&ip, p, &nop);
    384  1.12       roy 			l += printchar(&ip, &val);
    385  1.12       roy 			*ip++ = '%';
    386  1.12       roy 			*ip++ = c;
    387  1.12       roy 			*ip++ = '%';
    388  1.12       roy 			*ip++ = 'c';
    389  1.12       roy 			l += 7;
    390  1.12       roy 			break;
    391  1.12       roy 		case '>':
    392  1.14       roy 			if (l + sizeof(fmtIf) + sizeof(fmtThen) +
    393  1.14       roy 			    sizeof(fmtElse) + (6 * 2) > len)
    394   1.3       roy 				goto elen;
    395  1.14       roy 
    396  1.14       roy 			memcpy(ip, fmtIf, sizeof(fmtIf) - 1);
    397  1.14       roy 			/* Replace the embedded parameters with real ones */
    398  1.14       roy 			ip[2] += p;
    399  1.14       roy 			ip[5] += p;
    400  1.14       roy 			ip += sizeof(fmtIf) - 1;
    401  1.14       roy 			l += sizeof(fmtIf) - 1;
    402  1.12       roy 			l += printchar(&ip, &val);
    403  1.14       roy 			memcpy(ip, fmtThen, sizeof(fmtThen) - 1);
    404  1.14       roy 			ip += sizeof(fmtThen) - 1;
    405  1.14       roy 			l += sizeof(fmtThen) - 1;
    406  1.12       roy 			l += printchar(&ip, &val);
    407  1.14       roy 			memcpy(ip, fmtElse, sizeof(fmtElse) - 1);
    408  1.14       roy 			ip += sizeof(fmtElse) - 1;
    409  1.14       roy 			l += sizeof(fmtElse) - 1;
    410  1.12       roy 			l += 16;
    411  1.12       roy 			nop = 1;
    412  1.12       roy 			continue;
    413  1.12       roy 		case '.':
    414  1.12       roy 			if (l + 6 > len)
    415  1.12       roy 				goto elen;
    416  1.14       roy 			l += printparam(&ip, p, &nop);
    417  1.12       roy 			*ip++ = '%';
    418  1.12       roy 			*ip++ = 'c';
    419  1.12       roy 			l += 2;
    420   1.3       roy 			break;
    421   1.3       roy 		default:
    422   1.3       roy 			/* Hope it matches a terminfo command. */
    423   1.3       roy 			*ip++ = '%';
    424   1.3       roy 			*ip++ = c;
    425   1.3       roy 			l += 2;
    426  1.12       roy 			if (c == 'i')
    427  1.12       roy 				continue;
    428   1.3       roy 			break;
    429   1.3       roy 		}
    430  1.12       roy 		/* Swap p1 and p2 */
    431  1.12       roy 		p = 3 - p;
    432   1.3       roy 	}
    433   1.3       roy 
    434   1.5       roy 	/* \E\ is valid termcap.
    435   1.5       roy 	 * We need to escape the final \ for terminfo. */
    436   1.5       roy 	if (l > 2 && info[l - 1] == '\\' &&
    437   1.5       roy 	    (info[l - 2] != '\\' && info[l - 2] != '^'))
    438   1.5       roy 	{
    439   1.5       roy 		if (l + 1 > len)
    440   1.5       roy 			goto elen;
    441   1.5       roy 		*ip++ = '\\';
    442   1.5       roy 	}
    443   1.5       roy 
    444   1.6       roy 	/* Add our padding at the end. */
    445   1.6       roy 	if (ps != NULL) {
    446  1.10  christos 		size_t n = pe - ps;
    447   1.6       roy 		if (l + n + 4 > len)
    448   1.6       roy 			goto elen;
    449   1.6       roy 		*ip++ = '$';
    450   1.6       roy 		*ip++ = '<';
    451   1.6       roy 		strncpy(ip, ps, n);
    452   1.6       roy 		ip += n;
    453   1.6       roy 		*ip++ = '/';
    454   1.6       roy 		*ip++ = '>';
    455   1.6       roy 	}
    456   1.6       roy 
    457   1.3       roy 	*ip = '\0';
    458   1.3       roy 	return info;
    459   1.3       roy 
    460   1.3       roy elen:
    461   1.3       roy 	free(info);
    462   1.3       roy 	errno = ENOMEM;
    463   1.3       roy 	return NULL;
    464   1.3       roy }
    465   1.3       roy 
    466   1.9       roy typedef struct {
    467   1.6       roy 	const char *name;
    468   1.6       roy 	const char *cap;
    469   1.9       roy } DEF_INFO;
    470   1.9       roy 
    471   1.9       roy static DEF_INFO def_infos[] = {
    472   1.6       roy 	{ "bel",	"^G" },
    473   1.6       roy 	{ "cr",		"^M" },
    474   1.6       roy 	{ "cud1",	"^J" },
    475   1.6       roy 	{ "ht",		"^I" },
    476   1.6       roy 	{ "ind",	"^J" },
    477   1.6       roy 	{ "kbs",	"^H" },
    478   1.6       roy 	{ "kcub1",	"^H" },
    479   1.6       roy 	{ "kcud1",	"^J" },
    480   1.6       roy 	{ "nel",	"^M^J" }
    481   1.6       roy };
    482   1.6       roy 
    483   1.3       roy char *
    484   1.3       roy captoinfo(char *cap)
    485   1.3       roy {
    486   1.3       roy 	char *info, *ip, *token, *val, *p, tok[3];
    487   1.3       roy 	const char *name;
    488   1.3       roy 	size_t len, lp, nl, vl, rl;
    489   1.7       roy 	int defs[__arraycount(def_infos)], fv;
    490   1.3       roy 
    491   1.3       roy 	_DIAGASSERT(cap != NULL);
    492   1.3       roy 
    493   1.3       roy 	len = strlen(cap) * 2;
    494   1.6       roy 	len += __arraycount(def_infos) * (5 + 4 + 3); /* reserve for defs */
    495   1.3       roy 	info = ip = malloc(len);
    496   1.3       roy 	if (info == NULL)
    497   1.3       roy 		return NULL;
    498   1.3       roy 
    499   1.6       roy 	memset(defs, 0, sizeof(defs));
    500   1.3       roy 	lp = 0;
    501   1.3       roy 	tok[2] = '\0';
    502   1.5       roy 	for (token = _ti_get_token(&cap, ':');
    503   1.5       roy 	     token != NULL;
    504   1.5       roy 	     token = _ti_get_token(&cap, ':'))
    505   1.5       roy 	{
    506   1.3       roy 		if (token[0] == '\0')
    507   1.3       roy 			continue;
    508   1.3       roy 		name = token;
    509   1.7       roy 		val = p = NULL;
    510   1.7       roy 		fv = nl = 0;
    511   1.3       roy 		if (token[1] != '\0') {
    512   1.3       roy 			tok[0] = token[0];
    513   1.3       roy 			tok[1] = token[1];
    514   1.7       roy 			nl = 1;
    515   1.3       roy 			if (token[2] == '\0') {
    516   1.3       roy 				name = flagname(tok);
    517   1.3       roy 				val = NULL;
    518   1.3       roy 			} else if (token[2] == '#') {
    519   1.3       roy 				name = numname(tok);
    520   1.3       roy 				val = token + 2;
    521   1.3       roy 			} else if (token[2] == '=') {
    522   1.3       roy 				name = strname(tok);
    523   1.3       roy 				val = strval(token + 2);
    524   1.7       roy 				fv = 1;
    525   1.7       roy 			} else
    526   1.7       roy 				nl = 0;
    527   1.7       roy 		}
    528   1.7       roy 		/* If not matched we may need to convert padding still. */
    529   1.7       roy 		if (nl == 0) {
    530   1.7       roy 			p = strchr(name, '=');
    531   1.7       roy 			if (p != NULL) {
    532   1.7       roy 				val = strval(p);
    533   1.7       roy 				*p = '\0';
    534   1.7       roy 				fv = 1;
    535   1.3       roy 			}
    536   1.3       roy 		}
    537   1.6       roy 
    538   1.6       roy 		/* See if this sets a default. */
    539   1.6       roy 		for (nl = 0; nl < __arraycount(def_infos); nl++) {
    540   1.6       roy 			if (strcmp(name, def_infos[nl].name) == 0) {
    541   1.6       roy 				defs[nl] = 1;
    542   1.6       roy 				break;
    543   1.6       roy 			}
    544   1.6       roy 		}
    545   1.6       roy 
    546   1.3       roy 		nl = strlen(name);
    547   1.3       roy 		if (val == NULL)
    548   1.3       roy 			vl = 0;
    549   1.3       roy 		else
    550   1.3       roy 			vl = strlen(val);
    551   1.3       roy 		rl = nl + vl + 3; /* , \0 */
    552   1.3       roy 
    553   1.3       roy 		if (lp + rl > len) {
    554   1.3       roy 			if (rl < 256)
    555   1.3       roy 				len += 256;
    556   1.3       roy 			else
    557   1.3       roy 				len += rl;
    558   1.3       roy 			p = realloc(info, len);
    559  1.18  christos 			if (p == NULL) {
    560  1.18  christos 				if (fv == 1)
    561  1.18  christos 					free(val);
    562   1.3       roy 				return NULL;
    563  1.18  christos 			}
    564   1.3       roy 			info = p;
    565   1.3       roy 		}
    566   1.3       roy 
    567   1.3       roy 		if (ip != info) {
    568   1.3       roy 			*ip++ = ',';
    569   1.3       roy 			*ip++ = ' ';
    570   1.3       roy 		}
    571   1.3       roy 
    572   1.3       roy 		strcpy(ip, name);
    573   1.3       roy 		ip += nl;
    574   1.3       roy 		if (val != NULL) {
    575   1.3       roy 			strcpy(ip, val);
    576   1.3       roy 			ip += vl;
    577   1.7       roy 			if (fv == 1)
    578   1.3       roy 				free(val);
    579   1.3       roy 		}
    580   1.3       roy 	}
    581   1.3       roy 
    582   1.6       roy 	/* Add any defaults not set above. */
    583   1.6       roy 	for (nl = 0; nl < __arraycount(def_infos); nl++) {
    584   1.6       roy 		if (defs[nl] == 0) {
    585   1.6       roy 			*ip++ = ',';
    586   1.6       roy 			*ip++ = ' ';
    587   1.6       roy 			strcpy(ip, def_infos[nl].name);
    588   1.6       roy 			ip += strlen(def_infos[nl].name);
    589   1.6       roy 			*ip++ = '=';
    590   1.6       roy 			strcpy(ip, def_infos[nl].cap);
    591   1.6       roy 			ip += strlen(def_infos[nl].cap);
    592   1.6       roy 		}
    593   1.6       roy 	}
    594   1.6       roy 
    595   1.3       roy 	*ip = '\0';
    596   1.3       roy 	return info;
    597   1.3       roy }
    598   1.3       roy 
    599