#include <ctype.h>

/*
 * No floating conversion (yet).
 */

static char ascnum[] = "0123456789ABCDEF";

static short
ltoo (p, lval)
  register char *p;
  register unsigned long lval;
  {
	register unsigned long n;
	register short depth = 0;

	if ((n = lval / 8) != 0)
		p += depth = ltoo (p, n);
	*p++ = ascnum[lval - (n * 8)];
	*p = '\0';
	return depth + 1;
}

static short
ltox (p, lval)
  register char *p;
  register unsigned long lval;
  {
	register unsigned long n;
	register short depth = 0;

	if ((n = lval / 16) != 0)
		p += depth = ltox (p, n);
	*p++ = ascnum[lval - (n * 16)];
	*p = '\0';
	return depth + 1;
}

static short
ultod (p, lval)
  register char *p;
  register unsigned long lval;
  {
	register unsigned long n;
	register short depth = 0;

	if ((n = lval / 10) != 0)
		p += depth = ultod (p, n);
	*p++ = ascnum[lval - (n * 10)];
	*p = '\0';
	return depth + 1;
}

static
ltod (p, lval)
  register char *p;
  register long lval;
  {
	if (lval < 0) {
		*p++ = '-';
		lval = -lval;
	}
	ultod (p, (unsigned long)lval);
}

static short
itoo (p, val)
  register char *p;
  register unsigned val;
  {
	register unsigned n;
	register short depth = 0;

	if ((n = val / 8) != 0)
		p += depth = itoo (p, n);
	*p++ = ascnum[val - (n * 8)];
	*p = '\0';
	return depth + 1;
}

static short
itox (p, val)
  register char *p;
  register unsigned val;
  {
	register unsigned n;
	register short depth = 0;

	if ((n = val / 16) != 0)
		p += depth = itox (p, n);
	*p++ = ascnum[val - (n * 16)];
	*p = '\0';
	return depth + 1;
}

static short
utod (p, val)
  register char *p;
  register unsigned val;
  {
	register unsigned n;
	register short depth = 0;

	if ((n = val / 10) != 0)
		p += depth = utod (p, n);
	*p++ = ascnum[val - (n * 10)];
	*p = '\0';
	return depth + 1;
}

static
itod (p, val)
  register char *p;
  register int val;
  {
	if (val < 0) {
		*p++ = '-';
		val = -val;
	}
	utod (p, (unsigned)val);
}

_doprnt (fmt, argp, outbuf)
  register char *fmt;
  register int *argp;
  register char *outbuf;
  {
	register char *p, c;
	register int count, pad, prec;
	register char left, fill;
	char buf[16];
	extern char *_strout();

	for (;;) {
		/* process format string first */
		p = fmt;
		count = 0;
		while ((c = *fmt++) != '%') {
			/* ordinary (non-%) character */
			if (c == '\0')
				break;
			count++;
		}
		if (count)
			outbuf = _strout (p, count, 0, outbuf, ' ');
		if (c == '\0')
			return;
		/* check for a leading - sign */
		left = 0;
		if (*fmt == '-') {
			left++;
			fmt++;
		}
		/* a '0' may follow the - sign */
		/* this is the requested fill character */
		fill = ' ';
		if (*fmt == '0') {
			fill = '0';
			fmt++;
		}

		/* Now comes a digit string which may be a '*' */
		if (*fmt == '*') {
			pad = *argp++;
			if (pad < 0) {
				pad = -pad;
				left = !left;
			}
			fmt++;
		} else {
			pad = 0;
			while (*fmt >= '0'  &&  *fmt <= '9')
				pad = pad * 10 + (*fmt++ - '0');
		}

		/* maybe a decimal point followed by more digits (or '*') */
		prec = 0;
		if (*fmt == '.') {
			if (*++fmt == '*') {
				prec = *argp++;
				fmt++;
			} else {
				while (*fmt >= '0'  &&  *fmt <= '9')
					prec = prec * 10 + (*fmt++ - '0');
			}
		}
		
		/*
		 * At this point, "left" is nonzero if there was
		 * a sign, "fill" is '0' if there was a leading
		 * zero and ' ' otherwise, "pad" and "prec"
		 * contain numbers corresponding to the digit
		 * strings before and after the decimal point,
		 * respectively, and "fmt" addresses the next
		 * character after the whole mess.
		 */

		p = buf;
		switch (c = *fmt++) {
		  case '\0':
			return;
		  case 'l':
		  case 'L':
			if ((c = *fmt++) == '\0')
				return;
			if (islower (c))
				c = toupper (c);
		}
		switch (c) {
		  case 'D': ltod (p, *(long *)argp++); goto siz;
		  case 'U': ultod (p, *(long *)argp++); goto siz;
		  case 'X': ltox (p, *(long *)argp++); goto siz;
		  case 'O': ltoo (p, *(long *)argp++); goto siz;
		  case 'd': itod (p, *argp++); goto siz;
		  case 'u': utod (p, *argp++); goto siz;
		  case 'x': itox (p, *argp++); goto siz;
		  case 'o': itoo (p, *argp++); goto siz;

		  case 's':
			if ((count = strlen (p = *(char **)argp++)) > prec  &&
			    prec > 0)
				count = prec;
			break;

		  case 'c':
/*
 * COMPILER BUG (RPH)	*p = (char)(*argp++);
 */
			*p = (char)(*argp);
			argp++;
/*
 * END BUGFIX (RPH)
 */
			count = 1;
			break;

		  default:
			*p = c;
			count = 1;
			break;
  siz:
			count = strlen (p);
		}
		if (pad) {
			if ((pad -= count) < 0)
				pad = 0;
			else if (!left)
				pad = -pad;
		}
		if (c == '\0')
			return;
		outbuf = _strout (p, count, pad, outbuf, fill);
	}
}
