xref: /csrg-svn/sys/kern/subr_prf.c (revision 51768)
149062Sbostic /*-
249062Sbostic  * Copyright (c) 1986, 1988, 1991 The Regents of the University of California.
349062Sbostic  * All rights reserved.
423381Smckusick  *
549062Sbostic  * %sccs.include.redist.c%
649062Sbostic  *
7*51768Smarc  *	@(#)subr_prf.c	7.33 (Berkeley) 11/20/91
823381Smckusick  */
931Sbill 
10*51768Smarc #include <sys/param.h>
11*51768Smarc #include <sys/systm.h>
12*51768Smarc #include <sys/buf.h>
13*51768Smarc #include <sys/conf.h>
14*51768Smarc #include <sys/reboot.h>
15*51768Smarc #include <sys/msgbuf.h>
16*51768Smarc #include <sys/proc.h>
17*51768Smarc #include <sys/ioctl.h>
18*51768Smarc #include <sys/vnode.h>
19*51768Smarc #include <sys/file.h>
20*51768Smarc #include <sys/tty.h>
21*51768Smarc #include <sys/tprintf.h>
22*51768Smarc #include <sys/syslog.h>
23*51768Smarc #include <sys/malloc.h>
2431Sbill 
2549062Sbostic /*
2649062Sbostic  * Note that stdarg.h and the ANSI style va_start macro is used for both
2749062Sbostic  * ANSI and traditional C compilers.
2849062Sbostic  */
2949062Sbostic #include <machine/stdarg.h>
3049062Sbostic 
3135282Skarels #ifdef KADB
3237496Smckusick #include "machine/kdbparam.h"
3330625Skarels #endif
3430625Skarels 
3549062Sbostic #define TOCONS	0x01
3649062Sbostic #define TOTTY	0x02
3749062Sbostic #define TOLOG	0x04
3816724Sralph 
3930549Skarels struct	tty *constty;			/* pointer to console "window" tty */
4030549Skarels 
4140808Smarc #ifdef KADB
4240808Smarc extern	cngetc();			/* standard console getc */
4349062Sbostic int	(*v_getc)() = cngetc;		/* "" getc from virtual console */
4440808Smarc extern	cnpoll();
4540808Smarc int	(*v_poll)() = cnpoll;		/* kdb hook to enable input polling */
4640808Smarc #endif
4749062Sbostic extern	cnputc();			/* standard console putc */
4849953Sbostic int	(*v_putc)() = cnputc;		/* routine to putc on virtual console */
4940808Smarc 
50*51768Smarc void  logpri __P((int level));
5149908Sbostic static void  putchar __P((int ch, int flags, struct tty *tp));
5249908Sbostic static char *ksprintn __P((u_long num, int base, int *len));
53*51768Smarc void kprintf __P((const char *fmt, int flags, struct tty *tp, va_list ap, ...));
5449062Sbostic 
55*51768Smarc int consintr = 1;			/* Ok to handle console interrupts? */
56*51768Smarc 
5731Sbill /*
58*51768Smarc  * Variable panicstr contains argument to first call to panic; used as flag
59*51768Smarc  * to indicate that the kernel has already called panic.
6031Sbill  */
61*51768Smarc const char *panicstr;
6229946Skarels 
6349062Sbostic /*
6449062Sbostic  * Panic is called on unresolvable fatal errors.  It prints "panic: mesg",
6549062Sbostic  * and then reboots.  If we are called twice, then we avoid trying to sync
6649062Sbostic  * the disks as this often leads to recursive panics.
6749062Sbostic  */
6849062Sbostic void
69*51768Smarc #ifdef __STDC__
70*51768Smarc panic(const char *fmt, ...)
71*51768Smarc #else
72*51768Smarc panic(fmt /*, va_alist */)
73*51768Smarc 	char *fmt;
74*51768Smarc #endif
7549062Sbostic {
76*51768Smarc 	int bootopt, savintr;
77*51768Smarc 	va_list ap;
7848426Skarels 
79*51768Smarc 	bootopt = RB_AUTOBOOT | RB_DUMP;
8049062Sbostic 	if (panicstr)
8149062Sbostic 		bootopt |= RB_NOSYNC;
8249062Sbostic 	else
83*51768Smarc 		panicstr = fmt;
84*51768Smarc 
85*51768Smarc 	savintr = consintr;		/* disable interrupts */
86*51768Smarc 	consintr = 0;
87*51768Smarc 
88*51768Smarc 	va_start(ap, fmt);
89*51768Smarc 	kprintf("panic: ", TOCONS | TOLOG, NULL, ap);
90*51768Smarc 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
91*51768Smarc 	va_end(ap);
92*51768Smarc 
93*51768Smarc 	consintr = savintr;		/* reenable interrupts */
94*51768Smarc 
9549062Sbostic #ifdef KGDB
9649062Sbostic 	kgdb_panic();
9749062Sbostic #endif
9849062Sbostic #ifdef KADB
9949062Sbostic 	if (boothowto & RB_KDB) {
10050268Sbostic 		int s;
10150268Sbostic 
10250268Sbostic 		s = splnet();	/* below kdb pri */
10349062Sbostic 		setsoftkdb();
10449062Sbostic 		splx(s);
10549062Sbostic 	}
10649062Sbostic #endif
10749062Sbostic 	boot(bootopt);
10849062Sbostic }
10949062Sbostic 
11049062Sbostic /*
11149062Sbostic  * Warn that a system table is full.
11249062Sbostic  */
11349062Sbostic void
11449062Sbostic tablefull(tab)
11549062Sbostic 	char *tab;
11631Sbill {
117285Sbill 
11849062Sbostic 	log(LOG_ERR, "%s: table is full\n", tab);
119285Sbill }
120285Sbill 
1212377Swnj /*
12239560Smarc  * Uprintf prints to the controlling terminal for the current process.
12349062Sbostic  * It may block if the tty queue is overfull.  No message is printed if
12449062Sbostic  * the queue does not clear in a reasonable time.
1252377Swnj  */
12649062Sbostic void
12749062Sbostic #ifdef __STDC__
12849062Sbostic uprintf(const char *fmt, ...)
12949062Sbostic #else
13051767Smarc uprintf(fmt, va_alist)
1312781Swnj 	char *fmt;
13249062Sbostic #endif
133285Sbill {
13447540Skarels 	register struct proc *p = curproc;
13549062Sbostic 	va_list ap;
136285Sbill 
13749953Sbostic 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
13849953Sbostic 		va_start(ap, fmt);
13949062Sbostic 		kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
14049953Sbostic 		va_end(ap);
14149953Sbostic 	}
142285Sbill }
143285Sbill 
14444386Smarc tpr_t
14548426Skarels tprintf_open(p)
14648426Skarels 	register struct proc *p;
14744386Smarc {
14849953Sbostic 
14944386Smarc 	if (p->p_flag & SCTTY && p->p_session->s_ttyvp) {
15044386Smarc 		SESSHOLD(p->p_session);
15148426Skarels 		return ((tpr_t) p->p_session);
15249062Sbostic 	}
15349062Sbostic 	return ((tpr_t) NULL);
15444386Smarc }
15544386Smarc 
15648426Skarels void
15744386Smarc tprintf_close(sess)
15844386Smarc 	tpr_t sess;
15944386Smarc {
16049953Sbostic 
16144386Smarc 	if (sess)
16248426Skarels 		SESSRELE((struct session *) sess);
16344386Smarc }
16444386Smarc 
16518364Skarels /*
16644386Smarc  * tprintf prints on the controlling terminal associated
16749062Sbostic  * with the given session.
16818364Skarels  */
16949062Sbostic void
17049062Sbostic #ifdef __STDC__
17149062Sbostic tprintf(tpr_t tpr, const char *fmt, ...)
17249062Sbostic #else
17351767Smarc tprintf(tpr, fmt, va_alist)
17448426Skarels 	tpr_t tpr;
17516724Sralph 	char *fmt;
17649062Sbostic #endif
17716724Sralph {
17848426Skarels 	register struct session *sess = (struct session *)tpr;
17948426Skarels 	struct tty *tp = NULL;
18044386Smarc 	int flags = TOLOG;
18149062Sbostic 	va_list ap;
18216724Sralph 
18325389Skarels 	logpri(LOG_INFO);
18448426Skarels 	if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
18544386Smarc 		flags |= TOTTY;
18648426Skarels 		tp = sess->s_ttyp;
18748426Skarels 	}
18849062Sbostic 	va_start(ap, fmt);
18949062Sbostic 	kprintf(fmt, flags, tp, ap);
19049062Sbostic 	va_end(ap);
19125389Skarels 	logwakeup();
19216724Sralph }
19316724Sralph 
19449062Sbostic /*
19549062Sbostic  * Ttyprintf displays a message on a tty; it should be used only by
19649062Sbostic  * the tty driver, or anything that knows the underlying tty will not
19749062Sbostic  * be revoke(2)'d away.  Other callers should use tprintf.
19849062Sbostic  */
19949062Sbostic void
20049062Sbostic #ifdef __STDC__
20149062Sbostic ttyprintf(struct tty *tp, const char *fmt, ...)
20249062Sbostic #else
20351767Smarc ttyprintf(tp, fmt, va_alist)
20449062Sbostic 	struct tty *tp;
20549062Sbostic 	char *fmt;
20649062Sbostic #endif
20749062Sbostic {
20849062Sbostic 	va_list ap;
20949062Sbostic 
21049062Sbostic 	va_start(ap, fmt);
21149062Sbostic 	kprintf(fmt, TOTTY, tp, ap);
21249062Sbostic 	va_end(ap);
21349062Sbostic }
21449062Sbostic 
21548426Skarels extern	int log_open;
21644386Smarc 
21716724Sralph /*
21849062Sbostic  * Log writes to the log buffer, and guarantees not to sleep (so can be
21949062Sbostic  * called by interrupt routines).  If there is no process reading the
22049062Sbostic  * log yet, it writes to the console also.
22116724Sralph  */
22249062Sbostic void
22349062Sbostic #ifdef __STDC__
22449062Sbostic log(int level, const char *fmt, ...)
22549062Sbostic #else
22651767Smarc log(level, fmt, va_alist)
22749062Sbostic 	int level;
22816724Sralph 	char *fmt;
22949062Sbostic #endif
23016724Sralph {
23150268Sbostic 	register int s;
23249062Sbostic 	va_list ap;
23316724Sralph 
23450268Sbostic 	s = splhigh();
23525389Skarels 	logpri(level);
23649062Sbostic 	va_start(ap, fmt);
23749062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
23816724Sralph 	splx(s);
23949953Sbostic 	va_end(ap);
24049953Sbostic 	if (!log_open) {
24149953Sbostic 		va_start(ap, fmt);
24249062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
24349953Sbostic 		va_end(ap);
24449953Sbostic 	}
24516724Sralph 	logwakeup();
24616724Sralph }
24716724Sralph 
248*51768Smarc void
24925389Skarels logpri(level)
25025389Skarels 	int level;
25125389Skarels {
25249908Sbostic 	register int ch;
25349908Sbostic 	register char *p;
25425389Skarels 
25549062Sbostic 	putchar('<', TOLOG, NULL);
25649908Sbostic 	for (p = ksprintn((u_long)level, 10, NULL); ch = *p--;)
25749908Sbostic 		putchar(ch, TOLOG, NULL);
25849062Sbostic 	putchar('>', TOLOG, NULL);
25925389Skarels }
26025389Skarels 
26149062Sbostic void
26249062Sbostic #ifdef __STDC__
26349062Sbostic addlog(const char *fmt, ...)
26449062Sbostic #else
26551767Smarc addlog(fmt, va_alist)
26633479Skarels 	char *fmt;
26749062Sbostic #endif
26833479Skarels {
26950268Sbostic 	register int s;
27049062Sbostic 	va_list ap;
27133479Skarels 
27250268Sbostic 	s = splhigh();
27349062Sbostic 	va_start(ap, fmt);
27449062Sbostic 	kprintf(fmt, TOLOG, NULL, ap);
27533479Skarels 	splx(s);
27649953Sbostic 	va_end(ap);
27749953Sbostic 	if (!log_open) {
27849953Sbostic 		va_start(ap, fmt);
27949062Sbostic 		kprintf(fmt, TOCONS, NULL, ap);
28049953Sbostic 		va_end(ap);
28149953Sbostic 	}
28233479Skarels 	logwakeup();
28333479Skarels }
28433479Skarels 
28549062Sbostic void
28649062Sbostic #ifdef __STDC__
28749062Sbostic printf(const char *fmt, ...)
28849062Sbostic #else
28951767Smarc printf(fmt, va_alist)
29049062Sbostic 	char *fmt;
29129946Skarels #endif
29249062Sbostic {
29349953Sbostic 	va_list ap;
29449062Sbostic 	register int savintr;
2952678Swnj 
29649062Sbostic 	savintr = consintr;		/* disable interrupts */
29749062Sbostic 	consintr = 0;
29849062Sbostic 	va_start(ap, fmt);
29949062Sbostic 	kprintf(fmt, TOCONS | TOLOG, NULL, ap);
30049062Sbostic 	va_end(ap);
30149062Sbostic 	if (!panicstr)
30249062Sbostic 		logwakeup();
30349062Sbostic 	consintr = savintr;		/* reenable interrupts */
30431Sbill }
30531Sbill 
3062781Swnj /*
30749062Sbostic  * Scaled down version of printf(3).
30849062Sbostic  *
30949062Sbostic  * Two additional formats:
31049062Sbostic  *
31149062Sbostic  * The format %b is supported to decode error registers.
31249062Sbostic  * Its usage is:
31349062Sbostic  *
314*51768Smarc  *	kprintf("reg=%b\n", regval, "<base><arg>*");
31549062Sbostic  *
31649062Sbostic  * where <base> is the output base expressed as a control character, e.g.
31749062Sbostic  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
31849062Sbostic  * the first of which gives the bit number to be inspected (origin 1), and
31949062Sbostic  * the next characters (up to a control character, i.e. a character <= 32),
32049062Sbostic  * give the name of the register.  Thus:
32149062Sbostic  *
322*51768Smarc  *	kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
32349062Sbostic  *
32449062Sbostic  * would produce output:
32549062Sbostic  *
32649062Sbostic  *	reg=3<BITTWO,BITONE>
32749062Sbostic  *
328*51768Smarc  * The format %r passes an additional format string and argument list
329*51768Smarc  * recursively.  Its usage is:
33049062Sbostic  *
331*51768Smarc  * fn(char *fmt, ...)
33249953Sbostic  * {
33349953Sbostic  *	va_list ap;
33449953Sbostic  *	va_start(ap, fmt);
335*51768Smarc  *	kprintf("prefix: %r: suffix\n", flags, tp, fmt, ap);
33649953Sbostic  *	va_end(ap);
337*51768Smarc  * }
33849908Sbostic  *
33949908Sbostic  * Space or zero padding and a field width are supported for the numeric
34049908Sbostic  * formats only.
3412781Swnj  */
34249909Sbostic void
343*51768Smarc #ifdef __STDC__
344*51768Smarc kprintf(const char *fmt, int flags, struct tty *tp, va_list ap, ...)
345*51768Smarc #else
346*51768Smarc kprintf(fmt, flags, tp)
34749094Sbostic 	register const char *fmt;
34849062Sbostic 	int flags;
34949094Sbostic 	struct tty *tp;
35049062Sbostic 	va_list ap;
351*51768Smarc #endif
35231Sbill {
35349062Sbostic 	register char *p;
35449062Sbostic 	register int ch, n;
35549908Sbostic 	u_long ul;
35649908Sbostic 	int base, lflag, tmp, width;
35749908Sbostic 	char padc;
35831Sbill 
35949062Sbostic 	for (;;) {
36049908Sbostic 		padc = ' ';
36149908Sbostic 		width = 0;
36249919Skarels 		while ((ch = *(u_char *)fmt++) != '%') {
36349062Sbostic 			if (ch == '\0')
36449062Sbostic 				return;
36549094Sbostic 			putchar(ch, flags, tp);
36629946Skarels 		}
36749062Sbostic 		lflag = 0;
36849919Skarels reswitch:	switch (ch = *(u_char *)fmt++) {
36949908Sbostic 		case '0':
37049908Sbostic 			padc = '0';
37149908Sbostic 			goto reswitch;
37249908Sbostic 		case '1': case '2': case '3': case '4':
37349908Sbostic 		case '5': case '6': case '7': case '8': case '9':
37449908Sbostic 			for (width = 0;; ++fmt) {
37549908Sbostic 				width = width * 10 + ch - '0';
37649908Sbostic 				ch = *fmt;
37749908Sbostic 				if (ch < '0' || ch > '9')
37849908Sbostic 					break;
37949908Sbostic 			}
38049908Sbostic 			goto reswitch;
38149062Sbostic 		case 'l':
38249062Sbostic 			lflag = 1;
38349062Sbostic 			goto reswitch;
38449062Sbostic 		case 'b':
38549062Sbostic 			ul = va_arg(ap, int);
38649062Sbostic 			p = va_arg(ap, char *);
38749908Sbostic 			for (p = ksprintn(ul, *p++, NULL); ch = *p--;)
38849908Sbostic 				putchar(ch, flags, tp);
38931Sbill 
39049062Sbostic 			if (!ul)
39149062Sbostic 				break;
3922377Swnj 
39349908Sbostic 			for (tmp = 0; n = *p++;) {
39449062Sbostic 				if (ul & (1 << (n - 1))) {
39549908Sbostic 					putchar(tmp ? ',' : '<', flags, tp);
39649062Sbostic 					for (; (n = *p) > ' '; ++p)
39749094Sbostic 						putchar(n, flags, tp);
39849908Sbostic 					tmp = 1;
39949062Sbostic 				} else
40049062Sbostic 					for (; *p > ' '; ++p);
40149062Sbostic 			}
40249908Sbostic 			if (tmp)
40349094Sbostic 				putchar('>', flags, tp);
40449062Sbostic 			break;
40549062Sbostic 		case 'c':
40649094Sbostic 			putchar(va_arg(ap, int), flags, tp);
40749062Sbostic 			break;
40849062Sbostic 		case 'r':
40949062Sbostic 			p = va_arg(ap, char *);
41049094Sbostic 			kprintf(p, flags, tp, va_arg(ap, va_list));
41149062Sbostic 			break;
41249062Sbostic 		case 's':
41349062Sbostic 			p = va_arg(ap, char *);
41449062Sbostic 			while (ch = *p++)
41549094Sbostic 				putchar(ch, flags, tp);
41649062Sbostic 			break;
41749062Sbostic 		case 'd':
41849908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
41949062Sbostic 			if ((long)ul < 0) {
42049094Sbostic 				putchar('-', flags, tp);
42149062Sbostic 				ul = -(long)ul;
42249062Sbostic 			}
42349908Sbostic 			base = 10;
42449908Sbostic 			goto number;
42549062Sbostic 		case 'o':
42649908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
42749908Sbostic 			base = 8;
42849953Sbostic 			goto number;
42949062Sbostic 		case 'u':
43049908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
43149908Sbostic 			base = 10;
43249908Sbostic 			goto number;
43349062Sbostic 		case 'x':
43449908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
43549908Sbostic 			base = 16;
43649908Sbostic number:			p = ksprintn(ul, base, &tmp);
43749908Sbostic 			if (width && (width -= tmp) > 0)
43849908Sbostic 				while (width--)
43949908Sbostic 					putchar(padc, flags, tp);
44049908Sbostic 			while (ch = *p--)
44149908Sbostic 				putchar(ch, flags, tp);
44249062Sbostic 			break;
44349062Sbostic 		default:
44449094Sbostic 			putchar('%', flags, tp);
44549062Sbostic 			if (lflag)
44649094Sbostic 				putchar('l', flags, tp);
44749908Sbostic 			/* FALLTHROUGH */
44849908Sbostic 		case '%':
44949094Sbostic 			putchar(ch, flags, tp);
45049062Sbostic 		}
45130625Skarels 	}
45231Sbill }
45331Sbill 
4542941Swnj /*
45549062Sbostic  * Print a character on console or users terminal.  If destination is
45649062Sbostic  * the console then the last MSGBUFS characters are saved in msgbuf for
45749062Sbostic  * inspection later.
458285Sbill  */
45949062Sbostic static void
46049094Sbostic putchar(c, flags, tp)
4612377Swnj 	register int c;
46249062Sbostic 	int flags;
46349094Sbostic 	struct tty *tp;
464285Sbill {
46533479Skarels 	extern int msgbufmapped;
46650268Sbostic 	register struct msgbuf *mbp;
467285Sbill 
46830549Skarels 	if (panicstr)
46949062Sbostic 		constty = NULL;
47049094Sbostic 	if ((flags & TOCONS) && tp == NULL && constty) {
47149094Sbostic 		tp = constty;
47230549Skarels 		flags |= TOTTY;
47330549Skarels 	}
47449094Sbostic 	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
47549094Sbostic 	    (flags & TOCONS) && tp == constty)
47649062Sbostic 		constty = NULL;
47749062Sbostic 	if ((flags & TOLOG) &&
47849062Sbostic 	    c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
47950268Sbostic 		mbp = msgbufp;
48045733Smckusick 		if (mbp->msg_magic != MSG_MAGIC) {
48149953Sbostic 			bzero((caddr_t)mbp, sizeof(*mbp));
48245733Smckusick 			mbp->msg_magic = MSG_MAGIC;
4832172Swnj 		}
48445733Smckusick 		mbp->msg_bufc[mbp->msg_bufx++] = c;
48545733Smckusick 		if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
48645733Smckusick 			mbp->msg_bufx = 0;
487285Sbill 	}
48849062Sbostic 	if ((flags & TOCONS) && constty == NULL && c != '\0')
48930549Skarels 		(*v_putc)(c);
490285Sbill }
49149908Sbostic 
49249908Sbostic /*
49349908Sbostic  * Scaled down version of sprintf(3).
49449908Sbostic  */
49549908Sbostic #ifdef __STDC__
49649919Skarels sprintf(char *buf, const char *cfmt, ...)
49749908Sbostic #else
49851767Smarc sprintf(buf, cfmt, va_alist)
49949919Skarels 	char *buf, *cfmt;
50049908Sbostic #endif
50149908Sbostic {
50249919Skarels 	register const char *fmt = cfmt;
50349908Sbostic 	register char *p, *bp;
50449908Sbostic 	register int ch, base;
50549908Sbostic 	u_long ul;
50649908Sbostic 	int lflag;
50749908Sbostic 	va_list ap;
50849908Sbostic 
50949919Skarels 	va_start(ap, cfmt);
51049919Skarels 	for (bp = buf; ; ) {
51149919Skarels 		while ((ch = *(u_char *)fmt++) != '%')
51249908Sbostic 			if ((*bp++ = ch) == '\0')
51349919Skarels 				return ((bp - buf) - 1);
51449919Skarels 
51549908Sbostic 		lflag = 0;
51649919Skarels reswitch:	switch (ch = *(u_char *)fmt++) {
51749908Sbostic 		case 'l':
51849908Sbostic 			lflag = 1;
51949908Sbostic 			goto reswitch;
52049908Sbostic 		case 'c':
52149908Sbostic 			*bp++ = va_arg(ap, int);
52249908Sbostic 			break;
52349908Sbostic 		case 's':
52449908Sbostic 			p = va_arg(ap, char *);
52549919Skarels 			while (*bp++ = *p++)
52649919Skarels 				;
52749908Sbostic 			--bp;
52849908Sbostic 			break;
52949908Sbostic 		case 'd':
53049908Sbostic 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
53149908Sbostic 			if ((long)ul < 0) {
53249908Sbostic 				*bp++ = '-';
53349908Sbostic 				ul = -(long)ul;
53449908Sbostic 			}
53549908Sbostic 			base = 10;
53649908Sbostic 			goto number;
53749908Sbostic 			break;
53849908Sbostic 		case 'o':
53949908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
54049908Sbostic 			base = 8;
54149908Sbostic 			goto number;
54249908Sbostic 			break;
54349908Sbostic 		case 'u':
54449908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
54549908Sbostic 			base = 10;
54649908Sbostic 			goto number;
54749908Sbostic 			break;
54849908Sbostic 		case 'x':
54949908Sbostic 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
55049908Sbostic 			base = 16;
55149908Sbostic number:			for (p = ksprintn(ul, base, NULL); ch = *p--;)
55249908Sbostic 				*bp++ = ch;
55349908Sbostic 			break;
55449908Sbostic 		default:
55549908Sbostic 			*bp++ = '%';
55649908Sbostic 			if (lflag)
55749908Sbostic 				*bp++ = 'l';
55849908Sbostic 			/* FALLTHROUGH */
55949908Sbostic 		case '%':
56049908Sbostic 			*bp++ = ch;
56149908Sbostic 		}
56249908Sbostic 	}
56349908Sbostic 	va_end(ap);
56449908Sbostic }
56549908Sbostic 
56649908Sbostic /*
56749908Sbostic  * Put a number (base <= 16) in a buffer in reverse order; return an
56849908Sbostic  * optional length and a pointer to the NULL terminated (preceded?)
56949908Sbostic  * buffer.
57049908Sbostic  */
57149908Sbostic static char *
57249908Sbostic ksprintn(ul, base, lenp)
57349908Sbostic 	register u_long ul;
57449908Sbostic 	register int base, *lenp;
57549908Sbostic {					/* A long in base 8, plus NULL. */
57649908Sbostic 	static char buf[sizeof(long) * NBBY / 3 + 2];
57749908Sbostic 	register char *p;
57849908Sbostic 
57949908Sbostic 	p = buf;
58049908Sbostic 	do {
58149908Sbostic 		*++p = "0123456789abcdef"[ul % base];
58249908Sbostic 	} while (ul /= base);
58349908Sbostic 	if (lenp)
58449908Sbostic 		*lenp = p - buf;
58549919Skarels 	return (p);
58649908Sbostic }
587