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