Пример #1
0
static int std_emit(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *val)
{
	char fmt[32];
	int res = 0;

	make_fmt(fmt, sizeof(fmt), occ);

	switch (occ->conversion) {
		/* Store the number of written characters in the given
		 * int pointer location */
		case 'n': {
			int *num = (int*)val->v_ptr;
			*num = (int)app->written;
			break;
		}

		/* strings are dumped directly, since they can get really big. A
		 * buffer of 128 letters for all other types should be enough. */
		case 's': {
			const char *str = (const char*)val->v_ptr;
			res = lc_arg_append(app, occ, str, strlen(str));
			break;
		}

		default: {
			int len = MAX(128, occ->width + 1);
			char *buf = XMALLOCN(char, len);
			res = dispatch_snprintf(buf, len, fmt, occ->lc_arg_type, val);
			res = lc_appendable_snadd(app, buf, res);
			free(buf);
		}
	}

	return res;
}
Пример #2
0
int lc_appendable_snwadd(lc_appendable_t *app, const char *str, size_t len,
		unsigned int width, int left_just, char pad)
{
	int res = 0;
	size_t i;
	size_t to_pad = width > len ? width - len : 0;

	/* If not left justified, pad left */
	for (i = 0; !left_just && i < to_pad; ++i)
		res += lc_appendable_chadd(app, pad);

	/* Send the visible portion of the string to the output. */
	res += lc_appendable_snadd(app, str, len);

	/* If left justified, pad right. */
	for (i = 0; left_just && i < to_pad; ++i)
		res += lc_appendable_chadd(app, pad);

	return res;
}
Пример #3
0
int lc_evpprintf(const lc_arg_env_t *env, lc_appendable_t *app, const char *fmt,
                 va_list args)
{
	int         res  = 0;
	const char *last = fmt + strlen(fmt);

	/* Find the first % */
	const char *s = strchr(fmt, '%');

	/* Emit the text before the first % was found */
	size_t addlen = (s ? s : last) - fmt;
	lc_appendable_snadd(app, fmt, addlen);
	res += addlen;

	while (s != NULL) {
		lc_arg_value_t val;

		/* We must be at a '%' */
		assert(*s == '%');

		/* Reset the occurrence structure */
		lc_arg_occ_t occ;
		memset(&occ, 0, sizeof(occ));

		/* Eat all flags and set the corresponding flags in the occ struct */
		for (++s; strchr("#0-+", *s); ++s) {
			switch (*s) {
				case '#':
					occ.flag_hash = 1;
					break;
				case '0':
					occ.flag_zero = 1;
					break;
				case '-':
					occ.flag_minus = 1;
					break;
				case '+':
					occ.flag_plus = 1;
					break;
				case ' ':
					occ.flag_space = 1;
					break;
			}
		}

		/* Read the width if given */
		s = read_int(s, &occ.width);

		occ.precision = -1;

		/* read the precision if given */
		if (*s == '.') {
			int precision;
			s = read_int(s + 1, &precision);

			/* Negative or lacking precision after a '.' is treated as
			 * precision 0. */
			occ.precision = MAX(0, precision);
		}

		/*
		 * Now, we can either have:
		 * - a named argument like {node}
		 * - some modifiers followed by a conversion specifier
		 * - or some other character, which ends this format invalidly
		 */
		char            ch  = *s;
		const lc_arg_t *arg = NULL;
		switch (ch) {
			case '%':
				s++;
				lc_appendable_chadd(app, '%');
				++res;
				break;
			case '{': {
				const char *named = ++s;

				/* Read until the closing brace or end of the string. */
				for (ch = *s; ch != '}' && ch != '\0'; ch = *++s) {
				}

				if (s - named) {
					size_t n = s - named;
					char *name;
					lc_arg_t tmp;

					name = (char*) malloc(sizeof(char) * (n + 1));
					MEMCPY(name, named, n);
					name[n] = '\0';
					tmp.name = name;

					arg = set_find(lc_arg_t, env->args, &tmp, sizeof(tmp), hash_str(named));
					occ.modifier = "";
					occ.modifier_length = 0;

					/* Set the conversion specifier of the occurrence to the
					 * letter specified in the argument description. */
					if (arg)
						occ.conversion = arg->letter;

					free(name);

					/* If we ended with a closing brace, move the current
					 * pointer after it, since it is not to be dumped. */
					if (ch == '}')
						s++;
				}
				break;
			}

			default: {
				const char *mod = s;

				/* Read, as long there are letters */
				while (isalpha((unsigned char)ch) && !arg) {
					int              base = 'a';
					lc_arg_t *const *map  = env->lower;

					/* If uppercase, select the uppercase map from the
					 * environment */
					if (isupper((unsigned char)ch)) {
						base = 'A';
						map = env->upper;
					}

					if (map[ch - base] != NULL) {
						occ.modifier = mod;
						occ.modifier_length = s - mod;
						occ.conversion = ch;
						arg = map[ch - base];
					}

					ch = *++s;
				}
			}
		}

		/* Call the handler if an argument was determined */
		if (arg != NULL && arg->handler != NULL) {
			const lc_arg_handler_t *handler = arg->handler;

			/* Let the handler determine the type of the argument based on the
			 * information gathered. */
			occ.lc_arg_type = handler->get_lc_arg_type(&occ);

			/* Store the value according to argument information */
			switch (occ.lc_arg_type) {
#define LC_ARG_TYPE(type,name,va_type) \
			case lc_arg_type_ ## name: val.v_ ## name = va_arg(args, va_type); break;
#include "lc_printf_arg_types.def"
#undef LC_ARG_TYPE
			}

			/* Finally, call the handler. */
			res += handler->emit(app, &occ, &val);
		}

		const char *old = s;
		s = strchr(s, '%');
		size_t addlen = (s ? s : last) - old;
		lc_appendable_snadd(app, old, addlen);
		res += addlen;
	}

	return res;
}