/* PRINT FORMATTED
 * "C Letter", V2 No 2 pp7-10 (April 1981), and V2 No 3 pp8-11 (August 1981)
 */
#include <std.h>

#define DBUF   24
#define INTNO  0
#define LNGNO  1
#define DBLNO  2
#define NOSKIP 3

VOID cprint(pfn, arg, f, pp)
  COUNT (*pfn)();
  TEXT *arg;
  FAST TEXT *f;
  FAST TEXT **pp;
  {
  FAST TEXT *q;
  BOOL rjust;
  COUNT n, n2, prec, tyarg, width;
  TEXT buf[DBUF], buf2[DBUF], *s;

  for (; ; f = q + 1)
    {
    for (tyarg = INTNO, rjust = YES, q = f; *q && *q != '%'; ++q)
      ;
    if (f < q)
      (*pfn)(arg, f, q - f); /* put normal text */
    if (!*q++) /* end of format */
      return;
    if (*q == '-')
      rjust = NO, ++q;
    for (width = 0; isdigit(*q); ++q)
      width = width * 10 + *q - '0';
    prec = 0;
    if (*q == '.')
      for (++q; isdigit(*q); ++q)
	prec = prec * 10 + *q - '0';
    if (*q == '1')
      tyarg = LNGNO, ++q;
    switch(*q)
      {
    case 'd':	/* decimal output */
	if (tyarg == LNGNO)
	  n = ltob(s = buf, *(LONG *)pp, -10);
	else
	  n = itob(s = buf, *(ARGINT *)pp, -10);
	break;
    case 'u':	/* decimal unsigned */
	if (tyarg == LNGNO)
	    n = ltob(s = buf, *(LONG *)pp, 10);
	else
	  n = itob(s = buf, *(ARGINT *)pp, 10);
	break;
    case 'o':	/* octal output */
	if (tyarg == LNGNO)
	    n = ltob(s = buf, *(LONG *)pp, 8);
	else
	  n = itob(s = buf, *(ARGINT *)pp, 8);
	break;
    case 'x':	/* hexadecimal output */
	if (tyarg == LNGNO)
	  n = ltob(s = buf, *(LONG *)pp, 16);
	else
	  n = itob(s = buf, *(ARGINT *)pp, 16);
	break;
    case 'c':	/* character output */
	s = pp, n = 1;
	break;
    case 's':	/* string output */
	s = *pp;
	n = lenstr(s);
	if (prec)
	  n = min(n, prec);
	break;
    case 'e':	/* exponential format */
	n = dtoe(s = buf, *(DOUBLE *)pp, 1, min(DBUF - 7, prec));
	tyarg = DBLNO;
	break;
    case 'f':	/* floating point format */
	n = dtof(s = buf, *(DOUBLE *)pp, (DBUF - 2) - prec, prec);
	tyarg = DBLNO;
	break;
    case 'g':	/* the shorter of %e or %f */
	n = dtoe(s = buf, *(DOUBLE *)pp, 1, min(DBUF - 7, prec));
	n2 = dtof(buf2, *(DOUBLE *)pp, (DBUF - 2) - prec, prec);
	if (n2 <= n)
	  n = n2, s = buf2;
	tyarg = DBLNO;
	break;
    default:
	s = q, n = 1;
	tyarg = NOSKIP;
	}
    if (tyarg == INTNO)
      pp = (ARGINT *)pp + 1;
    else if (tyarg == LNGNO)
      pp = (LONG *)pp + 1;
    else if (tyarg == DBLNO)
      pp = (DOUBLE *)pp + 1;
    if (rjust)
      for (; n < width; --width)
	(*pfn)(arg, " ", 1);
    if (0 < n)
      (*pfn)(arg, s, n);
    if (!rjust)
      for (; n < width; --width)
	(*pfn)(arg, " ", 1);
    }
  }
