vm: fix a null dereference on out-of-memory
[minix.git] / lib / libterminfo / termcap.c
blobe9d422532c7274d3bb02f21b00c64f1bbbaa5f05
1 /* $NetBSD: termcap.c,v 1.10 2010/10/12 12:49:27 christos Exp $ */
3 /*
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Roy Marples.
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.
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.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: termcap.c,v 1.10 2010/10/12 12:49:27 christos Exp $");
33 #include <assert.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdint.h>
37 #include <string.h>
38 #include <term_private.h>
39 #include <term.h>
40 #include <termcap.h>
41 #include <unistd.h>
42 #include <stdio.h>
44 #include "termcap_map.c"
45 #include "termcap_hash.c"
47 char *UP;
48 char *BC;
50 /* ARGSUSED */
51 int
52 tgetent(__unused char *bp, const char *name)
54 int errret;
55 static TERMINAL *last = NULL;
57 _DIAGASSERT(name != NULL);
59 /* Free the old term */
60 if (last != NULL) {
61 del_curterm(last);
62 last = NULL;
64 errret = -1;
65 if (setupterm(name, STDOUT_FILENO, &errret) != 0)
66 return errret;
67 last = cur_term;
69 if (pad_char != NULL)
70 PC = pad_char[0];
71 UP = __UNCONST(cursor_up);
72 BC = __UNCONST(cursor_left);
73 return 1;
76 int
77 tgetflag(const char *id)
79 uint32_t ind;
80 size_t i;
81 TERMUSERDEF *ud;
83 _DIAGASSERT(id != NULL);
85 if (cur_term == NULL)
86 return 0;
88 ind = _t_flaghash((const unsigned char *)id, strlen(id));
89 if (ind <= __arraycount(_ti_cap_flagids)) {
90 if (strcmp(id, _ti_cap_flagids[ind].id) == 0)
91 return cur_term->flags[_ti_cap_flagids[ind].ti];
93 for (i = 0; i < cur_term->_nuserdefs; i++) {
94 ud = &cur_term->_userdefs[i];
95 if (ud->type == 'f' && strcmp(ud->id, id) == 0)
96 return ud->flag;
98 return 0;
102 tgetnum(const char *id)
104 uint32_t ind;
105 size_t i;
106 TERMUSERDEF *ud;
107 const TENTRY *te;
109 _DIAGASSERT(id != NULL);
111 if (cur_term == NULL)
112 return -1;
114 ind = _t_numhash((const unsigned char *)id, strlen(id));
115 if (ind <= __arraycount(_ti_cap_numids)) {
116 te = &_ti_cap_numids[ind];
117 if (strcmp(id, te->id) == 0) {
118 if (!VALID_NUMERIC(cur_term->nums[te->ti]))
119 return ABSENT_NUMERIC;
120 return cur_term->nums[te->ti];
123 for (i = 0; i < cur_term->_nuserdefs; i++) {
124 ud = &cur_term->_userdefs[i];
125 if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
126 if (!VALID_NUMERIC(ud->num))
127 return ABSENT_NUMERIC;
128 return ud->num;
131 return -1;
134 char *
135 tgetstr(const char *id, char **area)
137 uint32_t ind;
138 size_t i;
139 TERMUSERDEF *ud;
140 const char *str;
142 _DIAGASSERT(id != NULL);
144 if (cur_term == NULL)
145 return NULL;
147 str = NULL;
148 ind = _t_strhash((const unsigned char *)id, strlen(id));
149 if (ind <= __arraycount(_ti_cap_strids)) {
150 if (strcmp(id, _ti_cap_strids[ind].id) == 0) {
151 str = cur_term->strs[_ti_cap_strids[ind].ti];
152 if (str == NULL)
153 return NULL;
156 if (str != NULL)
157 for (i = 0; i < cur_term->_nuserdefs; i++) {
158 ud = &cur_term->_userdefs[i];
159 if (ud->type == 's' && strcmp(ud->id, id) == 0)
160 str = ud->str;
163 /* XXX: FXIXME
164 * We should fix sgr0(me) as it has a slightly different meaning
165 * for termcap. */
167 if (str != NULL && area != NULL && *area != NULL) {
168 char *s;
169 s = *area;
170 strcpy(*area, str);
171 *area += strlen(*area) + 1;
172 return s;
175 return __UNCONST(str);
178 char *
179 tgoto(const char *cm, int destcol, int destline)
182 _DIAGASSERT(cm != NULL);
183 return vtparm(cm, destline, destcol);
186 static const char *
187 flagname(const char *key)
189 uint32_t idx;
191 idx = _t_flaghash((const unsigned char *)key, strlen(key));
192 if (idx <= __arraycount(_ti_cap_flagids) &&
193 strcmp(key, _ti_cap_flagids[idx].id) == 0)
194 return _ti_flagid(_ti_cap_flagids[idx].ti);
195 return key;
198 static const char *
199 numname(const char *key)
201 uint32_t idx;
203 idx = _t_numhash((const unsigned char *)key, strlen(key));
204 if (idx <= __arraycount(_ti_cap_numids) &&
205 strcmp(key, _ti_cap_numids[idx].id) == 0)
206 return _ti_numid(_ti_cap_numids[idx].ti);
207 return key;
210 static const char *
211 strname(const char *key)
213 uint32_t idx;
215 idx = _t_strhash((const unsigned char *)key, strlen(key));
216 if (idx <= __arraycount(_ti_cap_strids) &&
217 strcmp(key, _ti_cap_strids[idx].id) == 0)
218 return _ti_strid(_ti_cap_strids[idx].ti);
220 if (strcmp(key, "tc") == 0)
221 return "use";
223 return key;
226 /* We don't currently map %> %B %D
227 * That means no conversion for regent100, hz1500, act4, act5, mime terms. */
228 static char *
229 strval(const char *val)
231 char *info, *ip, c;
232 const char *ps, *pe;
233 int p;
234 size_t len, l;
236 len = 1024; /* no single string should be bigger */
237 info = ip = malloc(len);
238 if (info == NULL)
239 return 0;
241 /* Move the = */
242 *ip++ = *val++;
244 /* Set ps and pe to point to the start and end of the padding */
245 if (isdigit((unsigned char)*val)) {
246 for (ps = pe = val;
247 isdigit((unsigned char)*val) || *val == '.';
248 val++)
249 pe++;
250 if (*val == '*') {
251 val++;
252 pe++;
254 } else
255 ps = pe = NULL;
257 l = 0;
258 p = 1;
259 for (; *val != '\0'; val++) {
260 if (l + 2 > len)
261 goto elen;
262 if (*val != '%') {
263 if (*val == ',') {
264 if (l + 3 > len)
265 goto elen;
266 *ip++ = '\\';
267 l++;
269 *ip++ = *val;
270 l++;
271 continue;
273 switch (c = *(++val)) {
274 case 'd':
275 if (l + 6 > len)
276 goto elen;
277 *ip++ = '%';
278 *ip++ = 'p';
279 *ip++ = '0' + p;
280 *ip++ = '%';
281 *ip++ = 'd';
282 l += 5;
283 /* FALLTHROUGH */
284 case 'r':
285 p = 3 - p;
286 break;
287 default:
288 /* Hope it matches a terminfo command. */
289 *ip++ = '%';
290 *ip++ = c;
291 l += 2;
292 break;
296 /* \E\ is valid termcap.
297 * We need to escape the final \ for terminfo. */
298 if (l > 2 && info[l - 1] == '\\' &&
299 (info[l - 2] != '\\' && info[l - 2] != '^'))
301 if (l + 1 > len)
302 goto elen;
303 *ip++ = '\\';
306 /* Add our padding at the end. */
307 if (ps != NULL) {
308 size_t n = pe - ps;
309 if (l + n + 4 > len)
310 goto elen;
311 *ip++ = '$';
312 *ip++ = '<';
313 strncpy(ip, ps, n);
314 ip += n;
315 *ip++ = '/';
316 *ip++ = '>';
319 *ip = '\0';
320 return info;
322 elen:
323 free(info);
324 errno = ENOMEM;
325 return NULL;
328 typedef struct {
329 const char *name;
330 const char *cap;
331 } DEF_INFO;
333 static DEF_INFO def_infos[] = {
334 { "bel", "^G" },
335 { "cr", "^M" },
336 { "cud1", "^J" },
337 { "ht", "^I" },
338 { "ind", "^J" },
339 { "kbs", "^H" },
340 { "kcub1", "^H" },
341 { "kcud1", "^J" },
342 { "nel", "^M^J" }
345 char *
346 captoinfo(char *cap)
348 char *info, *ip, *token, *val, *p, tok[3];
349 const char *name;
350 size_t len, lp, nl, vl, rl;
351 int defs[__arraycount(def_infos)], fv;
353 _DIAGASSERT(cap != NULL);
355 len = strlen(cap) * 2;
356 len += __arraycount(def_infos) * (5 + 4 + 3); /* reserve for defs */
357 info = ip = malloc(len);
358 if (info == NULL)
359 return NULL;
361 memset(defs, 0, sizeof(defs));
362 lp = 0;
363 tok[2] = '\0';
364 for (token = _ti_get_token(&cap, ':');
365 token != NULL;
366 token = _ti_get_token(&cap, ':'))
368 if (token[0] == '\0')
369 continue;
370 name = token;
371 val = p = NULL;
372 fv = nl = 0;
373 if (token[1] != '\0') {
374 tok[0] = token[0];
375 tok[1] = token[1];
376 nl = 1;
377 if (token[2] == '\0') {
378 name = flagname(tok);
379 val = NULL;
380 } else if (token[2] == '#') {
381 name = numname(tok);
382 val = token + 2;
383 } else if (token[2] == '=') {
384 name = strname(tok);
385 val = strval(token + 2);
386 fv = 1;
387 } else
388 nl = 0;
390 /* If not matched we may need to convert padding still. */
391 if (nl == 0) {
392 p = strchr(name, '=');
393 if (p != NULL) {
394 val = strval(p);
395 *p = '\0';
396 fv = 1;
400 /* See if this sets a default. */
401 for (nl = 0; nl < __arraycount(def_infos); nl++) {
402 if (strcmp(name, def_infos[nl].name) == 0) {
403 defs[nl] = 1;
404 break;
408 nl = strlen(name);
409 if (val == NULL)
410 vl = 0;
411 else
412 vl = strlen(val);
413 rl = nl + vl + 3; /* , \0 */
415 if (lp + rl > len) {
416 if (rl < 256)
417 len += 256;
418 else
419 len += rl;
420 p = realloc(info, len);
421 if (p == NULL)
422 return NULL;
423 info = p;
426 if (ip != info) {
427 *ip++ = ',';
428 *ip++ = ' ';
431 strcpy(ip, name);
432 ip += nl;
433 if (val != NULL) {
434 strcpy(ip, val);
435 ip += vl;
436 if (fv == 1)
437 free(val);
441 /* Add any defaults not set above. */
442 for (nl = 0; nl < __arraycount(def_infos); nl++) {
443 if (defs[nl] == 0) {
444 *ip++ = ',';
445 *ip++ = ' ';
446 strcpy(ip, def_infos[nl].name);
447 ip += strlen(def_infos[nl].name);
448 *ip++ = '=';
449 strcpy(ip, def_infos[nl].cap);
450 ip += strlen(def_infos[nl].cap);
454 *ip = '\0';
455 return info;