Esempio n. 1
0
/*
 * Print SysV echo(1) style escape string
 *	Halts processing string if a \c escape is encountered.
 */
static char *
conv_escape_str(char *str)
{
	int ch;
	char *cp;

	/* convert string into a temporary buffer... */
	STARTSTACKSTR(cp);

	do {
		int c;

		ch = *str++;
		if (ch != '\\')
			continue;

		ch = *str++;
		if (ch == 'c') {
			/* \c as in SYSV echo - abort all processing.... */
			rval |= 0x100;
			ch = 0;
			continue;
		}

		/*
		 * %b string octal constants are not like those in C.
		 * They start with a \0, and are followed by 0, 1, 2,
		 * or 3 octal digits.
		 */
		if (ch == '0') {
			unsigned char i;
			i = 3;
			ch = 0;
			do {
				unsigned k = octtobin(*str);
				if (k > 7)
					break;
				str++;
				ch <<= 3;
				ch += k;
			} while (--i);
			continue;
		}

		/* Finally test for sequences valid in the format string */
		str = conv_escape(str - 1, &c);
		ch = c;
	} while (STPUTC(ch, cp), ch);

	return stackblock();
}
Esempio n. 2
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;
}
Esempio n. 3
0
/*
 * Print SysV echo(1) style escape string 
 *	Halts processing string if a \c escape is encountered.
 */
static void
conv_escape_str(char *str, void (*do_putchar)(int))
{
	int value;
	int ch;
	char c;

	while ((ch = *str++) != '\0') {
		if (ch != '\\') {
			do_putchar(ch);
			continue;
		}

		ch = *str++;
		if (ch == 'c') {
			/* \c as in SYSV echo - abort all processing.... */
			rval |= 0x100;
			break;
		}

		/* 
		 * %b string octal constants are not like those in C.
		 * They start with a \0, and are followed by 0, 1, 2, 
		 * or 3 octal digits. 
		 */
		if (ch == '0') {
			int octnum = 0, i;
			for (i = 0; i < 3; i++) {
				if (!isdigit((unsigned char)*str) || *str > '7')
					break;
				octnum = (octnum << 3) | (*str++ - '0');
			}
			do_putchar(octnum);
			continue;
		}

		/* \[M][^|-]C as defined by vis(3) */
		if (ch == 'M' && *str == '-') {
			do_putchar(0200 | str[1]);
			str += 2;
			continue;
		}
		if (ch == 'M' && *str == '^') {
			str++;
			value = 0200;
			ch = '^';
		} else
			value = 0;
		if (ch == '^') {
			ch = *str++;
			if (ch == '?')
				value |= 0177;
			else
				value |= ch & 037;
			do_putchar(value);
			continue;
		}

		/* Finally test for sequences valid in the format string */
		str = conv_escape(str - 1, &c);
		do_putchar(c);
	}
}
Esempio n. 4
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;
}