/*
 * printf.c
 */

/*
 * For indirecting and incrementing argument pointer.
 */
#define ind(p, t)	(*((t *) p))
#define inc(t1, t2)	((sizeof(t2 *)+sizeof(t1)-1) / sizeof(t1))

/*
 * Table for printing out digits.
 */
char digtab[] ={
	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
	'8',	'9',	'A',	'B',	'C',	'D',	'E',	'F'
};

/*
 * A simple printf.
 */
printf(fp, a1)
register char *fp;
{
	char * cp;
	register int c;
	register unsigned *ap;
	int lflag;

	ap = (char *)&a1;
	for (;;) {
		while ((c=*fp++) != '%') {
			if (c == '\0')
				return;
			putchar(c);
		}

		lflag = 0;
		if ( *fp == 'l' ) {
			lflag = 1;
			fp++;
		}

		switch ( c = *fp++ ) {

		case 'c':
			putchar(*ap++);
			continue;

		case 'd':
			if ( lflag == 0 ) {
				if ( ((int)(*ap)) < 0 ) {
					putchar('-');
					printn( -((long) ((int)(*ap))), 10 );
				}
				else
					printn( ((long)(*ap)), 10 );
				ap++;
				continue;
			}
			/* fall through */
		case 'D':
			if ( *((long *)(ap)) < 0 ) {
				putchar('-');
				printn( - *((long *)(ap)), 10 );
			}
			else
				printn(   *((long *)(ap)), 10 );

			((long *)(ap))++;
			continue;

		case 'o':
			if ( lflag == 0 ) {
				printn( ((long)(*ap)), 8);
				ap++;
				continue;
			}
			/* fall through */
		case 'O':
			printf( *((long *)(ap)), 8 );
			((long *)(ap))++;
			continue;

		case 'r':
			ap = *((int **) ap);
			fp = ind(ap, char *);
			ap += inc(int, char *);
			continue;

		case 's':
			cp = ind(ap, char *);
			ap += inc(int, char *);
			while ((c=*cp++) != '\0')
				putchar(c);
			continue;

		case 'x':
			if ( lflag == 0 ) {
				printn( ((long)(*ap)), 16 );
				ap++;
				continue;
			}
			/* fall through */
		case 'X':
			printn( *((long *)(ap)), 16 );
			((long *)(ap))++;
			continue;

		case 'u':
			if ( lflag == 0 ) {
				printn( ((long)(*ap)), 10);
				ap++;
				continue;
			}
			/* fall through */
		case 'U':
			printn( *((long *)(ap)), 10 );
			((long *)(ap))++;
			continue;

		case 'p':
			if (sizeof(char *) > sizeof(int)) {
				printn( ((long)(*ap)), 16);
				putchar(':');
				ap++;
			}
			printn( ((long)(*ap)), 16);
			ap++;
			continue;

		default:
			putchar(c);
			continue;
		}
	}
}

/*
 * Print out the unsigned long `v' in the base `b'.
 */
printn( v, b )
unsigned long v;
{
	unsigned long n;

	if (n=v/b)
		printn(n, b);

	putchar(digtab[v%b]);
}
