Пример #1
0
static void
dump_string(char *val, char *buf)
/* display the value of a string capability */
{
    if (val == ABSENT_STRING)
	_nc_STRCPY(buf, s_absent, MAX_STRING);
    else if (val == CANCELLED_STRING)
	_nc_STRCPY(buf, s_cancel, MAX_STRING);
    else {
	_nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING)
		    "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
    }
}
Пример #2
0
static int
make_db_path(char *dst, const char *src, size_t limit)
{
    int rc = -1;
    const char *top = _nc_tic_dir(0);

    if (src == top || _nc_is_abs_path(src)) {
	if (strlen(src) + 1 <= limit) {
	    _nc_STRCPY(dst, src, limit);
	    rc = 0;
	}
    } else {
	if (strlen(top) + strlen(src) + 2 <= limit) {
	    _nc_SPRINTF(dst, _nc_SLIMIT(limit) "%s/%s", top, src);
	    rc = 0;
	}
    }
#if USE_HASHED_DB
    if (rc == 0) {
	static const char suffix[] = DBM_SUFFIX;
	size_t have = strlen(dst);
	size_t need = strlen(suffix);
	if (have > need && strcmp(dst + (int) (have - need), suffix)) {
	    if (have + need <= limit) {
		_nc_STRCAT(dst, suffix, limit);
	    } else {
		rc = -1;
	    }
	} else if (_nc_is_dir_path(dst)) {
	    rc = -1;
	}
    }
#endif
    return rc;
}
Пример #3
0
static void
dump_numeric(int val, char *buf)
/* display the value of a boolean capability */
{
    switch (val) {
    case ABSENT_NUMERIC:
	_nc_STRCPY(buf, s_absent, MAX_STRING);
	break;
    case CANCELLED_NUMERIC:
	_nc_STRCPY(buf, s_cancel, MAX_STRING);
	break;
    default:
	_nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING) "%d", val);
	break;
    }
}
Пример #4
0
_tracechtype2(int bufnum, chtype ch)
{
    char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);

    if (result != 0) {
	const char *found;
	attr_t attr = ChAttrOf(ch);

	_nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum));
	if ((found = _nc_altcharset_name(attr, ch)) != 0) {
	    (void) _nc_trace_bufcat(bufnum, found);
	    attr &= ~A_ALTCHARSET;
	} else
	    (void) _nc_trace_bufcat(bufnum,
				    _nc_tracechar(CURRENT_SCREEN,
						  (int) ChCharOf(ch)));

	if (attr != A_NORMAL) {
	    (void) _nc_trace_bufcat(bufnum, " | ");
	    (void) _nc_trace_bufcat(bufnum,
				    _traceattr2(bufnum + 20, attr));
	}

	result = _nc_trace_bufcat(bufnum, r_brace);
    }
    return result;
}
Пример #5
0
static void
failed(const char *msg)
{
    char temp[BUFSIZ];
    size_t len = strlen(_nc_progname) + 2;

    if ((int) len < (int) sizeof(temp) - 12) {
	_nc_STRCPY(temp, _nc_progname, sizeof(temp));
	_nc_STRCAT(temp, ": ", sizeof(temp));
    } else {
	_nc_STRCPY(temp, "tset: ", sizeof(temp));
    }
    _nc_STRNCAT(temp, msg, sizeof(temp), sizeof(temp) - strlen(temp) - 2);
    perror(temp);
    exit_error();
    /* NOTREACHED */
}
Пример #6
0
static char *
strmalloc(char *s)
{
    size_t need = strlen(s) + 1;
    char *result = malloc(need);
    if (result == 0)
	failed("strmalloc");
    _nc_STRCPY(result, s, need);
    return result;
}
Пример #7
0
/*
 * Convert a character to visible form.
 */
static char *
visichar(int ch)
{
    static char temp[10];

    ch = UChar(ch);
    assert(ch >= 0 && ch < 256);
    if (ch == '\\') {
	_nc_STRCPY(temp, "\\\\", sizeof(temp));
    } else if (ch == '\033') {
	_nc_STRCPY(temp, "\\E", sizeof(temp));
    } else if (ch < ' ') {
	_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "\\%03o", ch);
    } else if (ch >= 127) {
	_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "\\%03o", ch);
    } else {
	_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "%c", ch);
    }
    return temp;
}
Пример #8
0
static void
add_to_blob(const char *text, size_t limit)
{
    (void) limit;

    if (*text != '\0') {
	char *last = my_blob + strlen(my_blob);
	if (last != my_blob)
	    *last++ = NCURSES_PATHSEP;
	_nc_STRCPY(last, text, limit);
    }
}
Пример #9
0
static char *
canonical_name(char *ptr, char *buf)
/* extract the terminal type's primary name */
{
    char *bp;

    _nc_STRCPY(buf, ptr, NAMESIZE);
    if ((bp = strchr(buf, '|')) != 0)
	*bp = '\0';

    return (buf);
}
Пример #10
0
_nc_strdup(const char *s)
{
    char *result = 0;
    if (s != 0) {
	size_t need = strlen(s);
	result = malloc(need + 1);
	if (result != 0) {
	    _nc_STRCPY(result, s, need);
	}
    }
    return result;
}
Пример #11
0
static char *
force_bar(char *dst, char *src)
{
    if (strchr(src, '|') == 0) {
	size_t len = strlen(src);
	if (len > MAX_NAME_SIZE)
	    len = MAX_NAME_SIZE;
	(void) strncpy(dst, src, len);
	_nc_STRCPY(dst + len, "|", MAX_NAME_SIZE);
	src = dst;
    }
    return src;
}
Пример #12
0
static char *
save_string(char *d, const char *const s)
{
    size_t have = (size_t) (d - my_string);
    size_t need = have + strlen(s) + 2;
    if (need > my_length) {
	my_string = (char *) _nc_doalloc(my_string, my_length = (need + need));
	if (my_string == 0)
	    _nc_err_abort(MSG_NO_MEMORY);
	d = my_string + have;
    }
    _nc_STRCPY(d, s, my_length - have);
    return d + strlen(d);
}
Пример #13
0
static char *
color_of(int c)
{
    if (c != my_cached) {
	my_cached = c;
	my_select = !my_select;
	if (isDefaultColor(c))
	    _nc_STRCPY(my_buffer[my_select], "default",
		       COLOR_BUF_SIZE(my_select));
	else
	    _nc_SPRINTF(my_buffer[my_select],
			_nc_SLIMIT(COLOR_BUF_SIZE(my_select))
			"color%d", c);
    }
    return my_buffer[my_select];
}
Пример #14
0
static char *
save_tc_char(char *bufptr, int c1)
{
    char temp[80];

    if (is7bits(c1) && isprint(c1)) {
	if (c1 == ':' || c1 == '\\')
	    bufptr = save_char(bufptr, '\\');
	bufptr = save_char(bufptr, c1);
    } else {
	if (c1 == (c1 & 0x1f))	/* iscntrl() returns T on 255 */
	    _nc_STRCPY(temp, unctrl((chtype) c1), sizeof(temp));
	else
	    _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "\\%03o", c1);
	bufptr = save_string(bufptr, temp);
    }
    return bufptr;
}
Пример #15
0
/*
 * Improve similar_sgr a little by moving the attr-string from the beginning
 * to the end of the s-string.
 */
static bool
rewrite_sgr(char *s, char *attr)
{
    if (s != 0) {
	if (PRESENT(attr)) {
	    size_t len_s = strlen(s);
	    size_t len_a = strlen(attr);

	    if (len_s > len_a && !strncmp(attr, s, len_a)) {
		unsigned n;
		TR(TRACE_DATABASE, ("rewrite:\n\t%s", s));
		for (n = 0; n < len_s - len_a; ++n) {
		    s[n] = s[n + len_a];
		}
		_nc_STRCPY(s + n, attr, strlen(s) + 1);
		TR(TRACE_DATABASE, ("to:\n\t%s", s));
	    }
	}
	return TRUE;
    }
    return FALSE;		/* oops */
}
Пример #16
0
_nc_write_entry(TERMTYPE *const tp)
{
#if USE_HASHED_DB

    char buffer[MAX_ENTRY_SIZE + 1];
    unsigned limit = sizeof(buffer);
    unsigned offset = 0;

#else /* !USE_HASHED_DB */

    struct stat statbuf;
    char filename[PATH_MAX];
    char linkname[PATH_MAX];
#if USE_SYMLINKS
    char symlinkname[PATH_MAX];
#if !HAVE_LINK
#undef HAVE_LINK
#define HAVE_LINK 1
#endif
#endif /* USE_SYMLINKS */

    static int call_count;
    static time_t start_time;	/* time at start of writes */

#endif /* USE_HASHED_DB */

    char name_list[MAX_TERMINFO_LENGTH];
    char *first_name, *other_names;
    char *ptr;
    char *term_names = tp->term_names;
    size_t name_size = strlen(term_names);

    if (name_size == 0) {
	_nc_syserr_abort("no terminal name found.");
    } else if (name_size >= sizeof(name_list) - 1) {
	_nc_syserr_abort("terminal name too long: %s", term_names);
    }

    _nc_STRCPY(name_list, term_names, sizeof(name_list));
    DEBUG(7, ("Name list = '%s'", name_list));

    first_name = name_list;

    ptr = &name_list[name_size - 1];
    other_names = ptr + 1;

    while (ptr > name_list && *ptr != '|')
	ptr--;

    if (ptr != name_list) {
	*ptr = '\0';

	for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++)
	    continue;

	if (*ptr == '\0')
	    other_names = ptr;
	else {
	    *ptr = '\0';
	    other_names = ptr + 1;
	}
    }

    DEBUG(7, ("First name = '%s'", first_name));
    DEBUG(7, ("Other names = '%s'", other_names));

    _nc_set_type(first_name);

#if USE_HASHED_DB
    if (write_object(tp, buffer + 1, &offset, limit - 1) != ERR) {
	DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE);
	DBT key, data;

	if (capdb != 0) {
	    buffer[0] = 0;

	    memset(&key, 0, sizeof(key));
	    key.data = term_names;
	    key.size = name_size;

	    memset(&data, 0, sizeof(data));
	    data.data = buffer;
	    data.size = offset + 1;

	    _nc_db_put(capdb, &key, &data);

	    buffer[0] = 2;

	    key.data = name_list;
	    key.size = strlen(name_list);

	    _nc_STRCPY(buffer + 1,
		       term_names,
		       sizeof(buffer) - 1);
	    data.size = name_size + 1;

	    _nc_db_put(capdb, &key, &data);

	    while (*other_names != '\0') {
		ptr = other_names++;
		assert(ptr < buffer + sizeof(buffer) - 1);
		while (*other_names != '|' && *other_names != '\0')
		    other_names++;

		if (*other_names != '\0')
		    *(other_names++) = '\0';

		key.data = ptr;
		key.size = strlen(ptr);

		_nc_db_put(capdb, &key, &data);
	    }
	}
    }
#else /* !USE_HASHED_DB */
    if (call_count++ == 0) {
	start_time = 0;
    }

    if (strlen(first_name) >= sizeof(filename) - (2 + LEAF_LEN))
	_nc_warning("terminal name too long.");

    _nc_SPRINTF(filename, _nc_SLIMIT(sizeof(filename))
		LEAF_FMT "/%s", first_name[0], first_name);

    /*
     * Has this primary name been written since the first call to
     * write_entry()?  If so, the newer write will step on the older,
     * so warn the user.
     */
    if (start_time > 0 &&
	stat(filename, &statbuf) >= 0
	&& statbuf.st_mtime >= start_time) {
#if HAVE_LINK && !USE_SYMLINKS
	/*
	 * If the file has more than one link, the reason for the previous
	 * write could be that the current primary name used to be an alias for
	 * the previous entry.  In that case, unlink the file so that we will
	 * not modify the previous entry as we write this one.
	 */
	if (statbuf.st_nlink > 1) {
	    _nc_warning("name redefined.");
	    unlink(filename);
	} else {
	    _nc_warning("name multiply defined.");
	}
#else
	_nc_warning("name multiply defined.");
#endif
    }

    check_writeable(first_name[0]);
    write_file(filename, tp);

    if (start_time == 0) {
	if (stat(filename, &statbuf) < 0
	    || (start_time = statbuf.st_mtime) == 0) {
	    _nc_syserr_abort("error obtaining time from %s/%s",
			     _nc_tic_dir(0), filename);
	}
    }
    while (*other_names != '\0') {
	ptr = other_names++;
	while (*other_names != '|' && *other_names != '\0')
	    other_names++;

	if (*other_names != '\0')
	    *(other_names++) = '\0';

	if (strlen(ptr) > sizeof(linkname) - (2 + LEAF_LEN)) {
	    _nc_warning("terminal alias %s too long.", ptr);
	    continue;
	}
	if (strchr(ptr, '/') != 0) {
	    _nc_warning("cannot link alias %s.", ptr);
	    continue;
	}

	check_writeable(ptr[0]);
	_nc_SPRINTF(linkname, _nc_SLIMIT(sizeof(linkname))
		    LEAF_FMT "/%s", ptr[0], ptr);

	if (strcmp(filename, linkname) == 0) {
	    _nc_warning("self-synonym ignored");
	} else if (stat(linkname, &statbuf) >= 0 &&
		   statbuf.st_mtime < start_time) {
	    _nc_warning("alias %s multiply defined.", ptr);
	} else if (_nc_access(linkname, W_OK) == 0)
#if HAVE_LINK
	{
	    int code;
#if USE_SYMLINKS
	    if (first_name[0] == linkname[0])
		strncpy(symlinkname, first_name, sizeof(symlinkname) - 1);
	    else {
		_nc_STRCPY(symlinkname, "../", sizeof(suymlinkname));
		strncat(symlinkname, filename, sizeof(symlinkname) - 4);
	    }
	    symlinkname[sizeof(symlinkname) - 1] = '\0';
#endif /* USE_SYMLINKS */
#if HAVE_REMOVE
	    code = remove(linkname);
#else
	    code = unlink(linkname);
#endif
	    if (code != 0 && errno == ENOENT)
		code = 0;
#if USE_SYMLINKS
	    if (symlink(symlinkname, linkname) < 0)
#else
	    if (link(filename, linkname) < 0)
#endif /* USE_SYMLINKS */
	    {
		/*
		 * If there wasn't anything there, and we cannot
		 * link to the target because it is the same as the
		 * target, then the source must be on a filesystem
		 * that uses caseless filenames, such as Win32, etc.
		 */
		if (code == 0 && errno == EEXIST)
		    _nc_warning("can't link %s to %s", filename, linkname);
		else if (code == 0 && (errno == EPERM || errno == ENOENT))
		    write_file(linkname, tp);
		else {
#if MIXEDCASE_FILENAMES
		    _nc_syserr_abort("can't link %s to %s", filename, linkname);
#else
		    _nc_warning("can't link %s to %s (errno=%d)", filename,
				linkname, errno);
#endif
		}
	    } else {
		DEBUG(1, ("Linked %s", linkname));
	    }
	}
#else /* just make copies */
	    write_file(linkname, tp);
#endif /* HAVE_LINK */
    }
#endif /* USE_HASHED_DB */
}
Пример #17
0
_tracecchar_t2(int bufnum, const cchar_t *ch)
{
    char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);

    if (result != 0) {
	_nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum));
	if (ch != 0) {
	    const char *found;
	    attr_t attr = AttrOfD(ch);

	    if ((found = _nc_altcharset_name(attr, (chtype) CharOfD(ch))) != 0) {
		(void) _nc_trace_bufcat(bufnum, found);
		attr &= ~A_ALTCHARSET;
	    } else if (isWidecExt(CHDEREF(ch))) {
		(void) _nc_trace_bufcat(bufnum, "{NAC}");
		attr &= ~A_CHARTEXT;
	    } else {
		PUTC_DATA;
		int n;

		(void) _nc_trace_bufcat(bufnum, "{ ");
		for (PUTC_i = 0; PUTC_i < CCHARW_MAX; ++PUTC_i) {
		    PUTC_ch = ch->chars[PUTC_i];
		    if (PUTC_ch == L'\0') {
			if (PUTC_i == 0)
			    (void) _nc_trace_bufcat(bufnum, "\\000");
			break;
		    }
		    PUTC_INIT;
		    PUTC_n = (int) wcrtomb(PUTC_buf, ch->chars[PUTC_i], &PUT_st);
		    if (PUTC_n <= 0) {
			if (PUTC_ch != L'\0') {
			    /* it could not be a multibyte sequence */
			    (void) _nc_trace_bufcat(bufnum,
						    _nc_tracechar(CURRENT_SCREEN,
								  UChar(ch->chars[PUTC_i])));
			}
			break;
		    } else if (ch->chars[PUTC_i] > 255) {
			char temp[80];
			_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
				    "{%d:\\u%lx}",
				    wcwidth(ch->chars[PUTC_i]),
				    (unsigned long) ch->chars[PUTC_i]);
			(void) _nc_trace_bufcat(bufnum, temp);
			break;
		    }
		    for (n = 0; n < PUTC_n; n++) {
			if (n)
			    (void) _nc_trace_bufcat(bufnum, ", ");
			(void) _nc_trace_bufcat(bufnum,
						_nc_tracechar(CURRENT_SCREEN,
							      UChar(PUTC_buf[n])));
		    }
		}
		(void) _nc_trace_bufcat(bufnum, " }");
	    }
	    if (attr != A_NORMAL) {
		(void) _nc_trace_bufcat(bufnum, " | ");
		(void) _nc_trace_bufcat(bufnum, _traceattr2(bufnum + 20, attr));
	    }
#if NCURSES_EXT_COLORS
	    /*
	     * Just in case the extended color is different from the chtype
	     * value, trace both.
	     */
	    if (ch->ext_color != PairNumber(attr)) {
		char temp[80];
		_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
			    " X_COLOR{%d:%d}", ch->ext_color, PairNumber(attr));
		(void) _nc_trace_bufcat(bufnum, temp);
	    }
#endif
	}

	result = _nc_trace_bufcat(bufnum, r_brace);
    }
    return result;
}
Пример #18
0
_traceattr2(int bufnum, chtype newmode)
{
#define DATA(name) { name, { #name } }
    static const struct {
	unsigned int val;
	const char name[14];
    } names[] =
    {
	DATA(A_STANDOUT),
	    DATA(A_UNDERLINE),
	    DATA(A_REVERSE),
	    DATA(A_BLINK),
	    DATA(A_DIM),
	    DATA(A_BOLD),
	    DATA(A_ALTCHARSET),
	    DATA(A_INVIS),
	    DATA(A_PROTECT),
	    DATA(A_CHARTEXT),
	    DATA(A_NORMAL),
	    DATA(A_COLOR),
#if USE_ITALIC
	    DATA(A_ITALIC),
#endif
    }
#ifndef USE_TERMLIB
    ,
	colors[] =
    {
	DATA(COLOR_BLACK),
	    DATA(COLOR_RED),
	    DATA(COLOR_GREEN),
	    DATA(COLOR_YELLOW),
	    DATA(COLOR_BLUE),
	    DATA(COLOR_MAGENTA),
	    DATA(COLOR_CYAN),
	    DATA(COLOR_WHITE),
    }
#endif /* !USE_TERMLIB */
    ;
#undef DATA
    char *result = _nc_trace_buf(bufnum, (size_t) BUFSIZ);

    if (result != 0) {
	size_t n;
	unsigned save_nc_tracing = _nc_tracing;

	_nc_tracing = 0;

	_nc_STRCPY(result, l_brace, TRACE_BUF_SIZE(bufnum));

	for (n = 0; n < SIZEOF(names); n++) {

	    if ((newmode & names[n].val) != 0) {
		if (result[1] != '\0')
		    (void) _nc_trace_bufcat(bufnum, "|");
		result = _nc_trace_bufcat(bufnum, names[n].name);

		if (names[n].val == A_COLOR) {
		    char temp[80];
		    short pairnum = (short) PairNumber(newmode);
#ifdef USE_TERMLIB
		    /* pair_content lives in libncurses */
		    _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
				"{%d}", pairnum);
#else
		    NCURSES_COLOR_T fg, bg;

		    if (pair_content(pairnum, &fg, &bg) == OK) {
			_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
				    "{%d = {%s, %s}}",
				    pairnum,
				    COLOR_OF(fg),
				    COLOR_OF(bg));
		    } else {
			_nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
				    "{%d}", pairnum);
		    }
#endif
		    result = _nc_trace_bufcat(bufnum, temp);
		}
	    }
	}
	if (ChAttrOf(newmode) == A_NORMAL) {
	    if (result != 0 && result[1] != '\0')
		(void) _nc_trace_bufcat(bufnum, "|");
	    (void) _nc_trace_bufcat(bufnum, "A_NORMAL");
	}

	_nc_tracing = save_nc_tracing;
	result = _nc_trace_bufcat(bufnum, r_brace);
    }
    return result;
}
safe_keyname (SCREEN *sp, int c)
{
	int i;
	char name[20];
	char *p;
	NCURSES_CONST char *result = 0;

	if (c == -1) {
		result = "-1";
	} else {
		for (i = 0; _nc_key_names[i].offset != -1; i++) {
			if (_nc_key_names[i].code == c) {
				result = (NCURSES_CONST char *)key_names + _nc_key_names[i].offset;
				break;
			}
		}

		if (result == 0 && (c >= 0 && c < SIZEOF_TABLE)) {
			if (MyTable == 0)
				MyTable = typeCalloc(char *, SIZEOF_TABLE);

			if (MyTable != 0) {
				int m_prefix = (sp == 0 || sp->_use_meta);

				/* if sense of meta() changed, discard cached data */
				if (MyInit != (m_prefix + 1)) {
					MyInit = m_prefix + 1;
					for (i = 0; i < SIZEOF_TABLE; ++i) {
						if (MyTable[i]) {
							FreeAndNull(MyTable[i]);
						}
					}
				}

				/* create and cache result as needed */
				if (MyTable[c] == 0) {
					int cc = c;
					p = name;
#define P_LIMIT (sizeof(name) - (size_t) (p - name))
					if (cc >= 128 && m_prefix) {
						_nc_STRCPY(p, "M-", P_LIMIT);
						p += 2;
						cc -= 128;
					}
					if (cc < 32)
						_nc_SPRINTF(p, _nc_SLIMIT(P_LIMIT) "^%c", cc + '@');
					else if (cc == 127)
						_nc_STRCPY(p, "^?", P_LIMIT);
					else
						_nc_SPRINTF(p, _nc_SLIMIT(P_LIMIT) "%c", cc);
					MyTable[c] = strdup(name);
				}
				result = MyTable[c];
			}
#if NCURSES_EXT_FUNCS && NCURSES_XNAMES
		} else if (result == 0 && HasTerminal(sp)) {
			int j, k;
			char * bound;
			TERMTYPE *tp = &(TerminalOf(sp)->type);
			unsigned save_trace = _nc_tracing;

			_nc_tracing = 0;	/* prevent recursion via keybound() */
			for (j = 0; (bound = NCURSES_SP_NAME(keybound)(NCURSES_SP_ARGx c, j)) != 0; ++j) {
				for(k = STRCOUNT; k < (int) NUM_STRINGS(tp);  k++) {
					if (tp->Strings[k] != 0 && !strcmp(bound, tp->Strings[k])) {
						result = ExtStrname(tp, k, strnames);
						break;
					}
				}
				free(bound);
				if (result != 0)
					break;
			}
			_nc_tracing = save_trace;
#endif
		}
	}
Пример #20
0
_nc_varargs(const char *fmt, va_list ap)
{
    static char dummy[] = "";

    char buffer[BUFSIZ];
    const char *param;
    int n;

    if (fmt == 0 || *fmt == '\0')
	return dummy;
    if (MyLength == 0)
	MyBuffer = typeMalloc(char, MyLength = BUFSIZ);
    if (MyBuffer == 0)
	return dummy;
    *MyBuffer = '\0';

    while (*fmt != '\0') {
	if (*fmt == '%') {
	    char *pval = 0;	/* avoid const-cast */
	    const char *sval = "";
	    double fval = 0.0;
	    int done = FALSE;
	    int ival = 0;
	    int type = 0;
	    ARGTYPE parm[MAX_PARMS];
	    int parms = 0;
	    ARGTYPE used = atUnknown;

	    while (*++fmt != '\0' && !done) {

		if (*fmt == '*') {
		    VA_INT(int);
		    if (parms < MAX_PARMS)
			parm[parms++] = atInteger;
		} else if (isalpha(UChar(*fmt))) {
		    done = TRUE;
		    switch (*fmt) {
		    case 'Z':	/* FALLTHRU */
		    case 'h':	/* FALLTHRU */
		    case 'l':	/* FALLTHRU */
			done = FALSE;
			type = *fmt;
			break;
		    case 'i':	/* FALLTHRU */
		    case 'd':	/* FALLTHRU */
		    case 'u':	/* FALLTHRU */
		    case 'x':	/* FALLTHRU */
		    case 'X':	/* FALLTHRU */
			if (type == 'l')
			    VA_INT(long);
			else if (type == 'Z')
			    VA_INT(size_t);
			else
			    VA_INT(int);
			used = atInteger;
			break;
		    case 'f':	/* FALLTHRU */
		    case 'e':	/* FALLTHRU */
		    case 'E':	/* FALLTHRU */
		    case 'g':	/* FALLTHRU */
		    case 'G':	/* FALLTHRU */
			VA_FLT(double);
			used = atFloat;
			break;
		    case 'c':
			VA_INT(int);
			used = atInteger;
			break;
		    case 's':
			VA_STR(const char *);
			used = atString;
			break;
		    case 'p':
			VA_PTR(void *);
			used = atPoint;
			break;
		    case 'n':
			VA_PTR(int *);
			used = atPoint;
			break;
		    default:
			break;
		    }
		} else if (*fmt == '%') {
		    done = TRUE;
		}
		if (used != atUnknown && parms < MAX_PARMS) {
		    parm[parms++] = used;
		    for (n = 0; n < parms; ++n) {
			used = parm[n];
			param = buffer;
			switch (used) {
			case atInteger:
			    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
					"%d", ival);
			    break;
			case atFloat:
			    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
					"%f", fval);
			    break;
			case atPoint:
			    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
					"%p", pval);
			    break;
			case atString:
			    param = _nc_visbuf2(1, sval);
			    break;
			case atUnknown:
			default:
			    _nc_STRCPY(buffer, "?", sizeof(buffer));
			    break;
			}
			MyLength += strlen(param) + 2;
			MyBuffer = typeRealloc(char, MyLength, MyBuffer);
			_nc_SPRINTF(MyBuffer + strlen(MyBuffer),
				    _nc_SLIMIT(MyLength - strlen(MyBuffer))
				    ", %s", param);
		    }
		}
		used = atUnknown;
	    }
	} else {