Exemple #1
0
int
ti_getnum(const TERMINAL *term, const char *id)
{
	ssize_t ind;
	size_t i;
	TERMUSERDEF *ud;

	_DIAGASSERT(term != NULL);
	_DIAGASSERT(id != NULL);

	ind = _ti_numindex(id);
	if (ind != -1) {
		if (!VALID_NUMERIC(term->nums[ind]))
			return ABSENT_NUMERIC;
		return term->nums[ind];
	}
	for (i = 0; i < term->_nuserdefs; i++) {
		ud = &term->_userdefs[i];
		if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
			if (!VALID_NUMERIC(ud->num))
			    return ABSENT_NUMERIC;
			return ud->num;
		}
	}
	return CANCELLED_NUMERIC;
}
Exemple #2
0
int
tgetnum(const char *id2)
{
	uint32_t ind;
	size_t i;
	TERMUSERDEF *ud;
	const TENTRY *te;
	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };

	if (cur_term == NULL)
		return -1;

	ind = _t_numhash((const unsigned char *)id, strlen(id));
	if (ind <= __arraycount(_ti_cap_numids)) {
		te = &_ti_cap_numids[ind];
		if (strcmp(id, te->id) == 0) {
			if (!VALID_NUMERIC(cur_term->nums[te->ti]))
				return ABSENT_NUMERIC;
			return cur_term->nums[te->ti];
		}
	}
	for (i = 0; i < cur_term->_nuserdefs; i++) {
		ud = &cur_term->_userdefs[i];
		if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
			if (!VALID_NUMERIC(ud->num))
				return ABSENT_NUMERIC;
			return ud->num;
		}
	}
	return -1;
}
Exemple #3
0
NCURSES_SP_NAME(tgetnum) (NCURSES_SP_DCLx NCURSES_CONST char *id)
{
    int result = ABSENT_NUMERIC;
    int i, j;

    T((T_CALLED("tgetnum(%p, %s)"), (void *) SP_PARM, id));
    if (HasTInfoTerminal(SP_PARM)) {
	TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
	struct name_table_entry const *entry_ptr;

	entry_ptr = _nc_find_type_entry(id, NUMBER, TRUE);
	if (entry_ptr != 0) {
	    j = entry_ptr->nte_index;
	}
#if NCURSES_XNAMES
	else {
	    j = -1;
	    for_each_ext_number(i, tp) {
		const char *capname = ExtNumname(tp, i, numcodes);
		if (same_tcname(id, capname)) {
		    j = i;
		    break;
		}
	    }
	}
#endif
	if (j >= 0) {
	    if (VALID_NUMERIC(tp->Numbers[j]))
		result = tp->Numbers[j];
	}
    }
    returnCode(result);
}
Exemple #4
0
NCURSES_SP_NAME(has_colors) (NCURSES_SP_DCL0)
{
    int code;

    (void) SP_PARM;
    T((T_CALLED("has_colors()")));
#ifdef USE_TERM_DRIVER
    code = HasColor;
#else
    code = ((VALID_NUMERIC(max_colors) && VALID_NUMERIC(max_pairs)
	     && (((set_foreground != NULL)
		  && (set_background != NULL))
		 || ((set_a_foreground != NULL)
		     && (set_a_background != NULL))
		 || set_color_pair)) ? TRUE : FALSE);
#endif
    returnCode(code);
}
Exemple #5
0
NCURSES_SP_NAME(tigetnum) (NCURSES_SP_DCLx NCURSES_CONST char *str)
{
    int j = -1;
    int result = CANCELLED_NUMERIC;	/* Solaris returns a -1 on error */

    T((T_CALLED("tigetnum(%p, %s)"), (void *) SP_PARM, str));

    if (HasTInfoTerminal(SP_PARM)) {
	TERMTYPE *tp = &(TerminalOf(SP_PARM)->type);
	struct name_table_entry const *entry_ptr;

	entry_ptr = _nc_find_type_entry(str, NUMBER, FALSE);
	if (entry_ptr != 0) {
	    j = entry_ptr->nte_index;
	}
#if NCURSES_XNAMES
	else {
	    int i;
	    for_each_ext_number(i, tp) {
		const char *capname = ExtNumname(tp, i, numnames);
		if (same_name(str, capname)) {
		    j = i;
		    break;
		}
	    }
	}
#endif
	if (j >= 0) {
	    if (VALID_NUMERIC(tp->Numbers[j]))
		result = tp->Numbers[j];
	    else
		result = ABSENT_NUMERIC;
	}
    }

    returnCode(result);
}
Exemple #6
0
/*
 * Set the hardware tabs on the terminal, using the 'ct' (clear all tabs),
 * 'st' (set one tab) and 'ch' (horizontal cursor addressing) capabilities.
 * This is done before 'if' and 'is', so they can recover in case of error.
 *
 * Return TRUE if we set any tab stops, FALSE if not.
 */
static bool
reset_tabstops(int wide)
{
    if ((init_tabs != 8)
	&& VALID_NUMERIC(init_tabs)
	&& VALID_STRING(set_tab)
	&& VALID_STRING(clear_all_tabs)) {
	int c;

	to_left_margin();
	tputs(clear_all_tabs, 0, out_char);
	if (init_tabs > 1) {
	    if (init_tabs > wide)
		init_tabs = (short) wide;
	    for (c = init_tabs; c < wide; c += init_tabs) {
		fprintf(my_file, "%*s", init_tabs, " ");
		tputs(set_tab, 0, out_char);
	    }
	    to_left_margin();
	}
	return (TRUE);
    }
    return (FALSE);
}
Exemple #7
0
TIC *
_ti_compile(char *cap, int flags)
{
	char *token, *p, *e, *name, *desc, *alias;
	signed char flag;
	long cnum;
	short num;
	ssize_t ind;
	size_t len;
	TBUF buf;
	TIC *tic;

	_DIAGASSERT(cap != NULL);	

	name = _ti_get_token(&cap, ',');
	if (name == NULL) {
		dowarn(flags, "no seperator found: %s", cap);
		return NULL;
	}
	desc = strrchr(name, '|');
	if (desc != NULL)
		*desc++ = '\0';
	alias = strchr(name, '|');
	if (alias != NULL)
		*alias++ = '\0';

	tic = calloc(sizeof(*tic), 1);
	if (tic == NULL)
		return NULL;

	buf.buf = NULL;
	buf.buflen = 0;

	tic->name = strdup(name);
	if (tic->name == NULL)
		goto error;
	if (alias != NULL && flags & TIC_ALIAS) {
		tic->alias = strdup(alias);
		if (tic->alias == NULL)
			goto error;
	}
	if (desc != NULL && flags & TIC_DESCRIPTION) {
		tic->desc = strdup(desc);
		if (tic->desc == NULL)
			goto error;
	}

	for (token = _ti_get_token(&cap, ',');
	     token != NULL && *token != '\0';
	     token = _ti_get_token(&cap, ','))
	{
		/* Skip commented caps */
		if (!(flags & TIC_COMMENT) && token[0] == '.')
			continue;

		/* Obsolete entries */
		if (token[0] == 'O' && token[1] == 'T') {
			if (!(flags & TIC_EXTRA))
				continue;
			token += 2;
		}

		/* str cap */
		p = strchr(token, '=');
		if (p != NULL) {
			*p++ = '\0';
			/* Don't use the string if we already have it */
			ind = _ti_strindex(token);
			if (ind != -1 &&
			    _ti_find_cap(&tic->strs, 's', ind) != NULL)
				continue;

			/* Encode the string to our scratch buffer */
			buf.bufpos = 0;
			if (encode_string(tic->name, token,
				&buf, p, flags) == -1)
				goto error;
			if (buf.bufpos > UINT16_T_MAX) {
				dowarn(flags, "%s: %s: string is too long",
				    tic->name, token);
				continue;
			}
			if (!VALID_STRING(buf.buf)) {
				dowarn(flags, "%s: %s: invalid string",
				    tic->name, token);
				continue;
			}

			if (ind == -1)
				_ti_store_extra(tic, 1, token, 's', -1, -2,
				    buf.buf, buf.bufpos, flags);
			else {
				if (!_ti_grow_tbuf(&tic->strs,
					(sizeof(uint16_t) * 2) + buf.bufpos))
					goto error;
				le16enc(tic->strs.buf + tic->strs.bufpos, ind);
				tic->strs.bufpos += sizeof(uint16_t);
				le16enc(tic->strs.buf + tic->strs.bufpos,
				    buf.bufpos);
				tic->strs.bufpos += sizeof(uint16_t);
				memcpy(tic->strs.buf + tic->strs.bufpos,
				    buf.buf, buf.bufpos);
				tic->strs.bufpos += buf.bufpos;
				tic->strs.entries++;
			}
			continue;
		}

		/* num cap */
		p = strchr(token, '#');
		if (p != NULL) {
			*p++ = '\0';
			/* Don't use the number if we already have it */
			ind = _ti_numindex(token);
			if (ind != -1 &&
			    _ti_find_cap(&tic->nums, 'n', ind) != NULL)
				continue;

			cnum = strtol(p, &e, 0);
			if (*e != '\0') {
				dowarn(flags, "%s: %s: not a number",
				    tic->name, token);
				continue;
			}
			if (!VALID_NUMERIC(cnum)) {
				dowarn(flags, "%s: %s: number out of range",
				    tic->name, token);
				continue;
			}
			num = (short)cnum;
			if (ind == -1)
				_ti_store_extra(tic, 1, token, 'n', -1,
				    num, NULL, 0, flags);
			else {
				if (_ti_grow_tbuf(&tic->nums,
					sizeof(uint16_t) * 2) == NULL)
					goto error;
				le16enc(tic->nums.buf + tic->nums.bufpos, ind);
				tic->nums.bufpos += sizeof(uint16_t);
				le16enc(tic->nums.buf + tic->nums.bufpos, num);
				tic->nums.bufpos += sizeof(uint16_t);
				tic->nums.entries++;
			}
			continue;
		}

		flag = 1;
		len = strlen(token) - 1;
		if (token[len] == '@') {
			flag = CANCELLED_BOOLEAN;
			token[len] = '\0';
		}
		ind = _ti_flagindex(token);
		if (ind == -1 && flag == CANCELLED_BOOLEAN) {
			if ((ind = _ti_numindex(token)) != -1) {
				if (_ti_find_cap(&tic->nums, 'n', ind) != NULL)
					continue;
				if (_ti_grow_tbuf(&tic->nums,
					sizeof(uint16_t) * 2) == NULL)
					goto error;
				le16enc(tic->nums.buf + tic->nums.bufpos, ind);
				tic->nums.bufpos += sizeof(uint16_t);
				le16enc(tic->nums.buf + tic->nums.bufpos,
					(uint16_t)CANCELLED_NUMERIC);
				tic->nums.bufpos += sizeof(uint16_t);
				tic->nums.entries++;
				continue;
			} else if ((ind = _ti_strindex(token)) != -1) {
				if (_ti_find_cap(&tic->strs, 's', ind) != NULL)
					continue;
				if (_ti_grow_tbuf(&tic->strs,
					(sizeof(uint16_t) * 2) + 1) == NULL)
					goto error;
				le16enc(tic->strs.buf + tic->strs.bufpos, ind);
				tic->strs.bufpos += sizeof(uint16_t);
				le16enc(tic->strs.buf + tic->strs.bufpos, 0);
				tic->strs.bufpos += sizeof(uint16_t);
				tic->strs.entries++;
				continue;
			}
		}
		if (ind == -1)
			_ti_store_extra(tic, 1, token, 'f', flag, 0, NULL, 0,
			    flags);
		else if (_ti_find_cap(&tic->flags, 'f', ind) == NULL) {
			if (_ti_grow_tbuf(&tic->flags, sizeof(uint16_t) + 1)
			    == NULL)
				goto error;
			le16enc(tic->flags.buf + tic->flags.bufpos, ind);
			tic->flags.bufpos += sizeof(uint16_t);
			tic->flags.buf[tic->flags.bufpos++] = flag;
			tic->flags.entries++;
		}
	}

	free(buf.buf);
	return tic;

error:
	free(buf.buf);
	_ti_freetic(tic);
	return NULL;
}
SCREEN *
newterm(NCURSES_CONST char *name, FILE * ofp, FILE * ifp)
{
    int errret;
    int slk_format = _nc_slk_format;
    SCREEN *current;
#ifdef TRACE
    int t = _nc_getenv_num("NCURSES_TRACE");

    if (t >= 0)
	trace(t);
#endif

    T((T_CALLED("newterm(\"%s\",%p,%p)"), name, ofp, ifp));

    /* this loads the capability entry, then sets LINES and COLS */
    if (setupterm(name, fileno(ofp), &errret) == ERR)
	return 0;

    /* implement filter mode */
    if (filter_mode) {
	LINES = 1;

	if (VALID_NUMERIC(init_tabs))
	    TABSIZE = init_tabs;
	else
	    TABSIZE = 8;

	T(("TABSIZE = %d", TABSIZE));

	clear_screen = 0;
	cursor_down = parm_down_cursor = 0;
	cursor_address = 0;
	cursor_up = parm_up_cursor = 0;
	row_address = 0;

	cursor_home = carriage_return;
    }

    /* If we must simulate soft labels, grab off the line to be used.
       We assume that we must simulate, if it is none of the standard
       formats (4-4  or 3-2-3) for which there may be some hardware
       support. */
    if (num_labels <= 0 || !SLK_STDFMT(slk_format))
	if (slk_format) {
	    if (ERR == _nc_ripoffline(-SLK_LINES(slk_format),
		    _nc_slk_initialize))
		return 0;
	}
    /* this actually allocates the screen structure, and saves the
     * original terminal settings.
     */
    current = SP;
    _nc_set_screen(0);
    if (_nc_setupscreen(LINES, COLS, ofp) == ERR) {
	_nc_set_screen(current);
	return 0;
    }

    /* if the terminal type has real soft labels, set those up */
    if (slk_format && num_labels > 0 && SLK_STDFMT(slk_format))
	_nc_slk_initialize(stdscr, COLS);

    SP->_ifd = fileno(ifp);
    SP->_checkfd = fileno(ifp);
    typeahead(fileno(ifp));
#ifdef TERMIOS
    SP->_use_meta = ((cur_term->Ottyb.c_cflag & CSIZE) == CS8 &&
	!(cur_term->Ottyb.c_iflag & ISTRIP));
#else
    SP->_use_meta = FALSE;
#endif
    SP->_endwin = FALSE;

    /* Check whether we can optimize scrolling under dumb terminals in case
     * we do not have any of these capabilities, scrolling optimization
     * will be useless.
     */
    SP->_scrolling = ((scroll_forward && scroll_reverse) ||
	((parm_rindex || parm_insert_line || insert_line) &&
	    (parm_index || parm_delete_line || delete_line)));

    baudrate();			/* sets a field in the SP structure */

    SP->_keytry = 0;

    /*
     * Check for mismatched graphic-rendition capabilities.  Most SVr4
     * terminfo trees contain entries that have rmul or rmso equated to
     * sgr0 (Solaris curses copes with those entries).  We do this only for
     * curses, since many termcap applications assume that smso/rmso and
     * smul/rmul are paired, and will not function properly if we remove
     * rmso or rmul.  Curses applications shouldn't be looking at this
     * detail.
     */
#define SGR0_TEST(mode) (mode != 0) && (exit_attribute_mode == 0 || strcmp(mode, exit_attribute_mode))
    SP->_use_rmso = SGR0_TEST(exit_standout_mode);
    SP->_use_rmul = SGR0_TEST(exit_underline_mode);

#if USE_WIDEC_SUPPORT
    /*
     * XFree86 xterm can be configured to support UTF-8 based on environment
     * variable settings.
     */
    {
	char *s;
	s = getenv("LC_ALL");
	if (s == NULL || *s == '\0') {
	    s = getenv("LC_CTYPE");
	    if (s == NULL || *s == '\0') {
		s = getenv("LANG");
	    }
	}
	if (s != NULL && *s != '\0' && strstr(s, "UTF-8") != NULL) {
	    SP->_outch = _nc_utf8_outch;
	}
    }
#endif

    /* compute movement costs so we can do better move optimization */
    _nc_mvcur_init();

    /* initialize terminal to a sane state */
    _nc_screen_init();

    /* Initialize the terminal line settings. */
    _nc_initscr();

    _nc_signal_handler(TRUE);

    T((T_RETURN("%p"), SP));
    return (SP);
}
Exemple #9
0
static int
use_predicate(unsigned type, PredIdx idx)
/* predicate function to use for use decompilation */
{
    ENTRY *ep;

    switch (type) {
    case BOOLEAN:
	{
	    int is_set = FALSE;

	    /*
	     * This assumes that multiple use entries are supposed
	     * to contribute the logical or of their boolean capabilities.
	     * This is true if we take the semantics of multiple uses to
	     * be 'each capability gets the first non-default value found
	     * in the sequence of use entries'.
	     *
	     * Note that cancelled or absent booleans are stored as FALSE,
	     * unlike numbers and strings, whose cancelled/absent state is
	     * recorded in the terminfo database.
	     */
	    for (ep = &entries[1]; ep < entries + termcount; ep++)
		if (ep->tterm.Booleans[idx] == TRUE) {
		    is_set = entries[0].tterm.Booleans[idx];
		    break;
		}
	    if (is_set != entries[0].tterm.Booleans[idx])
		return (!is_set);
	    else
		return (FAIL);
	}

    case NUMBER:
	{
	    int value = ABSENT_NUMERIC;

	    /*
	     * We take the semantics of multiple uses to be 'each
	     * capability gets the first non-default value found
	     * in the sequence of use entries'.
	     */
	    for (ep = &entries[1]; ep < entries + termcount; ep++)
		if (VALID_NUMERIC(ep->tterm.Numbers[idx])) {
		    value = ep->tterm.Numbers[idx];
		    break;
		}

	    if (value != entries[0].tterm.Numbers[idx])
		return (value != ABSENT_NUMERIC);
	    else
		return (FAIL);
	}

    case STRING:
	{
	    char *termstr, *usestr = ABSENT_STRING;

	    termstr = entries[0].tterm.Strings[idx];

	    /*
	     * We take the semantics of multiple uses to be 'each
	     * capability gets the first non-default value found
	     * in the sequence of use entries'.
	     */
	    for (ep = &entries[1]; ep < entries + termcount; ep++)
		if (ep->tterm.Strings[idx]) {
		    usestr = ep->tterm.Strings[idx];
		    break;
		}

	    if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
		return (FAIL);
	    else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
		return (TRUE);
	    else
		return (FAIL);
	}
    }

    return (FALSE);		/* pacify compiler */
}
Exemple #10
0
static void
_nc_get_screensize(int *linep, int *colp)
/* Obtain lines/columns values from the environment and/or terminfo entry */
{
    /* figure out the size of the screen */
    T(("screen size: terminfo lines = %d columns = %d", lines, columns));

    if (!_use_env) {
	*linep = (int) lines;
	*colp = (int) columns;
    } else {			/* usually want to query LINES and COLUMNS from environment */
	int value;

	*linep = *colp = 0;

	/* first, look for environment variables */
	if ((value = _nc_getenv_num("LINES")) > 0) {
	    *linep = value;
	}
	if ((value = _nc_getenv_num("COLUMNS")) > 0) {
	    *colp = value;
	}
	T(("screen size: environment LINES = %d COLUMNS = %d", *linep, *colp));

#ifdef __EMX__
	if (*linep <= 0 || *colp <= 0) {
	    int screendata[2];
	    _scrsize(screendata);
	    *colp = screendata[0];
	    *linep = screendata[1];
	    T(("EMX screen size: environment LINES = %d COLUMNS = %d",
	       *linep, *colp));
	}
#endif
#if HAVE_SIZECHANGE
	/* if that didn't work, maybe we can try asking the OS */
	if (*linep <= 0 || *colp <= 0) {
	    if (isatty(cur_term->Filedes)) {
		STRUCT_WINSIZE size;

		errno = 0;
		do {
		    if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) < 0
			&& errno != EINTR)
			goto failure;
		} while
		    (errno == EINTR);

		/*
		 * Solaris lets users override either dimension with an
		 * environment variable.
		 */
		if (*linep <= 0)
		    *linep = WINSIZE_ROWS(size);
		if (*colp <= 0)
		    *colp = WINSIZE_COLS(size);
	    }
	    /* FALLTHRU */
	  failure:;
	}
#endif /* HAVE_SIZECHANGE */

	/* if we can't get dynamic info about the size, use static */
	if (*linep <= 0) {
	    *linep = (int) lines;
	}
	if (*colp <= 0) {
	    *colp = (int) columns;
	}

	/* the ultimate fallback, assume fixed 24x80 size */
	if (*linep <= 0) {
	    *linep = 24;
	}
	if (*colp <= 0) {
	    *colp = 80;
	}

	/*
	 * Put the derived values back in the screen-size caps, so
	 * tigetnum() and tgetnum() will do the right thing.
	 */
	lines = (short) (*linep);
	columns = (short) (*colp);
    }

    T(("screen size is %dx%d", *linep, *colp));

    if (VALID_NUMERIC(init_tabs))
	TABSIZE = (int) init_tabs;
    else
	TABSIZE = 8;
    T(("TABSIZE = %d", TABSIZE));

}
Exemple #11
0
static int
_ti_readterm(TERMINAL *term, const char *cap, size_t caplen, int flags)
{
    uint8_t ver;
    uint16_t ind, num;
    size_t len;
    TERMUSERDEF *ud;

    ver = *cap++;
    /* Only read version 1 structures */
    if (ver != 1) {
        errno = EINVAL;
        return -1;
    }


    if (allocset(&term->flags, 0, TIFLAGMAX + 1, sizeof(*term->flags)) == -1)
        return -1;

    if (allocset(&term->nums, -1, TINUMMAX + 1, sizeof(*term->nums)) == -1)
        return -1;

    if (allocset(&term->strs, 0, TISTRMAX + 1, sizeof(*term->strs)) == -1)
        return -1;

    if (term->_arealen != caplen) {
        term->_arealen = caplen;
        term->_area = realloc(term->_area, term->_arealen);
        if (term->_area == NULL)
            return -1;
    }
    memcpy(term->_area, cap, term->_arealen);

    cap = term->_area;
    len = le16dec(cap);
    cap += sizeof(uint16_t);
    term->name = cap;
    cap += len;
    len = le16dec(cap);
    cap += sizeof(uint16_t);
    if (len == 0)
        term->_alias = NULL;
    else {
        term->_alias = cap;
        cap += len;
    }
    len = le16dec(cap);
    cap += sizeof(uint16_t);
    if (len == 0)
        term->desc = NULL;
    else {
        term->desc = cap;
        cap += len;
    }

    num = le16dec(cap);
    cap += sizeof(uint16_t);
    if (num != 0) {
        num = le16dec(cap);
        cap += sizeof(uint16_t);
        for (; num != 0; num--) {
            ind = le16dec(cap);
            cap += sizeof(uint16_t);
            term->flags[ind] = *cap++;
            if (flags == 0 && !VALID_BOOLEAN(term->flags[ind]))
                term->flags[ind] = 0;
        }
    }

    num = le16dec(cap);
    cap += sizeof(uint16_t);
    if (num != 0) {
        num = le16dec(cap);
        cap += sizeof(uint16_t);
        for (; num != 0; num--) {
            ind = le16dec(cap);
            cap += sizeof(uint16_t);
            term->nums[ind] = le16dec(cap);
            if (flags == 0 && !VALID_NUMERIC(term->nums[ind]))
                term->nums[ind] = ABSENT_NUMERIC;
            cap += sizeof(uint16_t);
        }
    }

    num = le16dec(cap);
    cap += sizeof(uint16_t);
    if (num != 0) {
        num = le16dec(cap);
        cap += sizeof(uint16_t);
        for (; num != 0; num--) {
            ind = le16dec(cap);
            cap += sizeof(uint16_t);
            len = le16dec(cap);
            cap += sizeof(uint16_t);
            if (len > 0)
                term->strs[ind] = cap;
            else if (flags == 0)
                term->strs[ind] = ABSENT_STRING;
            else
                term->strs[ind] = CANCELLED_STRING;
            cap += len;
        }
    }

    num = le16dec(cap);
    cap += sizeof(uint16_t);
    if (num != 0) {
        num = le16dec(cap);
        cap += sizeof(uint16_t);
        if (num != term->_nuserdefs) {
            free(term->_userdefs);
            term->_userdefs = NULL;
            term->_nuserdefs = num;
        }
        if (allocset(&term->_userdefs, 0, term->_nuserdefs,
                     sizeof(*term->_userdefs)) == -1)
            return -1;
        for (num = 0; num < term->_nuserdefs; num++) {
            ud = &term->_userdefs[num];
            len = le16dec(cap);
            cap += sizeof(uint16_t);
            ud->id = cap;
            cap += len;
            ud->type = *cap++;
            switch (ud->type) {
            case 'f':
                ud->flag = *cap++;
                if (flags == 0 &&
                        !VALID_BOOLEAN(ud->flag))
                    ud->flag = 0;
                ud->num = ABSENT_NUMERIC;
                ud->str = ABSENT_STRING;
                break;
            case 'n':
                ud->flag = ABSENT_BOOLEAN;
                ud->num = le16dec(cap);
                if (flags == 0 &&
                        !VALID_NUMERIC(ud->num))
                    ud->num = ABSENT_NUMERIC;
                ud->str = ABSENT_STRING;
                cap += sizeof(uint16_t);
                break;
            case 's':
                ud->flag = ABSENT_BOOLEAN;
                ud->num = ABSENT_NUMERIC;
                len = le16dec(cap);
                cap += sizeof(uint16_t);
                if (len > 0)
                    ud->str = cap;
                else if (flags == 0)
                    ud->str = ABSENT_STRING;
                else
                    ud->str = CANCELLED_STRING;
                cap += len;
                break;
            default:
                errno = EINVAL;
                return -1;
            }
        }
    } else {
        term->_nuserdefs = 0;
        if (term->_userdefs) {
            free(term->_userdefs);
            term->_userdefs = NULL;
        }
    }

    return 1;
}