Ejemplo n.º 1
0
int printfcmd(int argc, char *argv[])
{
	char *fmt;
	char *format;
	int ch;

	rval = 0;

	nextopt(nullstr);

	argv = argptr;
	format = *argv;

	if (!format) {
		warnx("usage: printf format [arg ...]");
		goto err;
	}

	gargv = ++argv;

#define SKIP1	"#-+ 0"
#define SKIP2	"*0123456789"
	do {
		/*
		 * Basic algorithm is to scan the format string for conversion
		 * specifications -- once one is found, find out if the field
		 * width or precision is a '*'; if it is, gather up value. 
		 * Note, format strings are reused as necessary to use up the
		 * provided arguments, arguments of zero/null string are 
		 * provided to use up the format string.
		 */

		/* find next format specification */
		for (fmt = format; (ch = *fmt++) ;) {
			char *start;
			char nextch;
			int array[2];
			int *param;

			if (ch == '\\') {
				int c_ch;
				fmt = conv_escape(fmt, &c_ch);
				ch = c_ch;
				goto pc;
			}
			if (ch != '%' || (*fmt == '%' && (++fmt || 1))) {
pc:
				blt_putchar(ch);
				continue;
			}

			/* Ok - we've found a format specification,
			   Save its address for a later blt_printf(). */
			start = fmt - 1;
			param = array;

			/* skip to field width */
			fmt += strspn(fmt, SKIP1);
			if (*fmt == '*')
				*param++ = getintmax();

			/* skip to possible '.', get following precision */
			fmt += strspn(fmt, SKIP2);
			if (*fmt == '.')
				++fmt;
			if (*fmt == '*')
				*param++ = getintmax();

			fmt += strspn(fmt, SKIP2);

			ch = *fmt;
			if (!ch) {
				warnx("missing format character");
				goto err;
			}
			/* null terminate format string to we can use it
			   as an argument to printf. */
			nextch = fmt[1];
			fmt[1] = 0;
			switch (ch) {

			case 'b': {
				int done = conv_escape_str(getstr());
				char *p = stackblock();
				*fmt = 's';
				PF(start, p);
				/* escape if a \c was encountered */
				if (done)
					goto out;
				*fmt = 'b';
				break;
			}
			case 'c': {
				int p = getchr();
				PF(start, p);
				break;
			}
			case 's': {
				char *p = getstr();
				PF(start, p);
				break;
			}
			case 'd':
			case 'i': {
				intmax_t p = getintmax();
				char *f = mklong(start, fmt);
				PF(f, p);
				break;
			}
			case 'o':
			case 'u':
			case 'x':
			case 'X': {
				uintmax_t p = getuintmax();
				char *f = mklong(start, fmt);
				PF(f, p);
				break;
			}
			case 'e':
			case 'E':
			case 'f':
			case 'g':
			case 'G': {
				double p = getdouble();
				PF(start, p);
				break;
			}
			default:
				warnx("%s: invalid directive", start);
				goto err;
			}
			*++fmt = nextch;
		}
	} while (gargv != argv && *gargv);

out:
	return rval;
err:
	return 1;
}
Ejemplo n.º 2
0
int main(int argc, char *argv[])
{
	char *fmt, *start;
	int fieldwidth, precision;
	char nextch;
	char *format;
	int ch;
	int error;

#if !defined(SHELL) && !defined(BUILTIN)
	(void)setlocale (LC_ALL, "");
#endif

	while ((ch = getopt(argc, argv, "")) != -1) {
		switch (ch) {
		case '?':
		default:
			usage();
			return 1;
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 1) {
		usage();
		return 1;
	}

	format = *argv;
	gargv = ++argv;

#define SKIP1	"#-+ 0"
#define SKIP2	"0123456789"
	do {
		/*
		 * Basic algorithm is to scan the format string for conversion
		 * specifications -- once one is found, find out if the field
		 * width or precision is a '*'; if it is, gather up value. 
		 * Note, format strings are reused as necessary to use up the
		 * provided arguments, arguments of zero/null string are 
		 * provided to use up the format string.
		 */

		/* find next format specification */
		for (fmt = format; (ch = *fmt++) != '\0';) {
			if (ch == '\\') {
				char c_ch;
				fmt = conv_escape(fmt, &c_ch);
				putchar(c_ch);
				continue;
			}
			if (ch != '%' || (*fmt == '%' && ++fmt)) {
				(void)putchar(ch);
				continue;
			}

			/* Ok - we've found a format specification,
			   Save its address for a later printf(). */
			start = fmt - 1;

			/* skip to field width */
			fmt += strspn(fmt, SKIP1);
			if (*fmt == '*') {
				fmt++;
				fieldwidth = getwidth();
			} else
				fieldwidth = -1;

			/* skip to possible '.', get following precision */
			fmt += strspn(fmt, SKIP2);
			if (*fmt == '.') {
				fmt++;
				if (*fmt == '*') {
					fmt++;
					precision = getwidth();
				} else
					precision = -1;
			} else
				precision = -1;

			fmt += strspn(fmt, SKIP2);

			ch = *fmt;
			if (!ch) {
				warnx("missing format character");
				return (1);
			}
			/* null terminate format string to we can use it
			   as an argument to printf. */
			nextch = fmt[1];
			fmt[1] = 0;
			switch (ch) {

			case 'B': {
				const char *p = conv_expand(getstr());
				if (p == NULL)
					goto out;
				*fmt = 's';
				PF(start, p);
				if (error < 0)
					goto out;
				break;
			}
			case 'b': {
				/* There has to be a better way to do this,
				 * but the string we generate might have
				 * embedded nulls. */
				static char *a, *t;
				char *cp = getstr();
				/* Free on entry in case shell longjumped out */
				if (a != NULL)
					free(a);
				a = NULL;
				if (t != NULL)
					free(t);
				t = NULL;
				/* Count number of bytes we want to output */
				b_length = 0;
				conv_escape_str(cp, b_count);
				t = malloc(b_length + 1);
				if (t == NULL)
					goto out;
				(void)memset(t, 'x', b_length);
				t[b_length] = 0;
				/* Get printf to calculate the lengths */
				*fmt = 's';
				abort();
/* APF(&a, start, t); */
				if (error == -1)
					goto out;
				b_fmt = a;
				/* Output leading spaces and data bytes */
				conv_escape_str(cp, b_output);
				/* Add any trailing spaces */
				printf("%s", b_fmt);
				break;
			}
			case 'c': {
				char p = getchr();
				PF(start, p);
				if (error < 0)
					goto out;
				break;
			}
			case 's': {
				char *p = getstr();
				PF(start, p);
				if (error < 0)
					goto out;
				break;
			}
			case 'd':
			case 'i': {
				intmax_t p = getintmax();
				char *f = mklong(start, ch);
				PF(f, p);
				if (error < 0)
					goto out;
				break;
			}
			case 'o':
			case 'u':
			case 'x':
			case 'X': {
				uintmax_t p = getuintmax();
				char *f = mklong(start, ch);
				PF(f, p);
				if (error < 0)
					goto out;
				break;
			}
			case 'e':
			case 'E':
			case 'f':
			case 'g':
			case 'G': {
				double p = getdouble();
				PF(start, p);
				if (error < 0)
					goto out;
				break;
			}
			default:
				warnx("%s: invalid directive", start);
				return 1;
			}
			*fmt++ = ch;
			*fmt = nextch;
			/* escape if a \c was encountered */
			if (rval & 0x100)
				return rval & ~0x100;
		}
	} while (gargv != argv && *gargv);

	return rval & ~0x100;
out:
	warn("print failed");
	return 1;
}