hexdump.c revision 70240
1230837Sdelphij/*-
2230837Sdelphij * Copyright (c) 1986, 1988, 1991, 1993
3230837Sdelphij *	The Regents of the University of California.  All rights reserved.
4230837Sdelphij * (c) UNIX System Laboratories, Inc.
5230837Sdelphij * All or some portions of this file are derived from material licensed
6230837Sdelphij * to the University of California by American Telephone and Telegraph
7230837Sdelphij * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8230837Sdelphij * the permission of UNIX System Laboratories, Inc.
9230837Sdelphij *
10230837Sdelphij * Redistribution and use in source and binary forms, with or without
11230837Sdelphij * modification, are permitted provided that the following conditions
12230837Sdelphij * are met:
13230837Sdelphij * 1. Redistributions of source code must retain the above copyright
14230837Sdelphij *    notice, this list of conditions and the following disclaimer.
15230837Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
16230837Sdelphij *    notice, this list of conditions and the following disclaimer in the
17230837Sdelphij *    documentation and/or other materials provided with the distribution.
18230837Sdelphij * 3. All advertising materials mentioning features or use of this software
19230837Sdelphij *    must display the following acknowledgement:
20230837Sdelphij *	This product includes software developed by the University of
21230837Sdelphij *	California, Berkeley and its contributors.
22230837Sdelphij * 4. Neither the name of the University nor the names of its contributors
23230837Sdelphij *    may be used to endorse or promote products derived from this software
24230837Sdelphij *    without specific prior written permission.
25230837Sdelphij *
26230837Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27230837Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28230837Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29230837Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30230837Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31230837Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32230837Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33230837Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34230837Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35230837Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36230837Sdelphij * SUCH DAMAGE.
37230837Sdelphij *
38230837Sdelphij *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
39230837Sdelphij * $FreeBSD: head/sys/kern/subr_prf.c 70240 2000-12-20 22:07:59Z phk $
40230837Sdelphij */
41230837Sdelphij
42230837Sdelphij#include <sys/param.h>
43230837Sdelphij#include <sys/systm.h>
44230837Sdelphij#include <sys/kernel.h>
45230837Sdelphij#include <sys/msgbuf.h>
46230837Sdelphij#include <sys/malloc.h>
47230837Sdelphij#include <sys/proc.h>
48230837Sdelphij#include <sys/tty.h>
49230837Sdelphij#include <sys/syslog.h>
50230837Sdelphij#include <sys/cons.h>
51230837Sdelphij#include <sys/uio.h>
52230837Sdelphij
53230837Sdelphij/*
54230837Sdelphij * Note that stdarg.h and the ANSI style va_start macro is used for both
55230837Sdelphij * ANSI and traditional C compilers.
56230837Sdelphij */
57230837Sdelphij#include <machine/stdarg.h>
58230837Sdelphij
59230837Sdelphij#define TOCONS	0x01
60230837Sdelphij#define TOTTY	0x02
61230837Sdelphij#define TOLOG	0x04
62230837Sdelphij
63230837Sdelphij/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
64230837Sdelphij#define MAXNBUF	(sizeof(quad_t) * NBBY + 1)
65230837Sdelphij
66230837Sdelphijstruct putchar_arg {
67230837Sdelphij	int	flags;
68230837Sdelphij	int	pri;
69230837Sdelphij	struct	tty *tty;
70230837Sdelphij};
71230837Sdelphij
72230837Sdelphijstruct snprintf_arg {
73230837Sdelphij	char	*str;
74230837Sdelphij	size_t	remain;
75230837Sdelphij};
76230837Sdelphij
77230837Sdelphijextern	int log_open;
78230837Sdelphij
79230837Sdelphijstruct	tty *constty;			/* pointer to console "window" tty */
80230837Sdelphij
81230837Sdelphijstatic void (*v_putc)(int) = cnputc;	/* routine to putc on virtual console */
82230837Sdelphijstatic void  msglogchar(int c, int pri);
83230837Sdelphijstatic void  msgaddchar(int c, void *dummy);
84230837Sdelphijstatic void  putchar __P((int ch, void *arg));
85230837Sdelphijstatic char *ksprintn __P((char *nbuf, u_long num, int base, int *len));
86230837Sdelphijstatic char *ksprintqn __P((char *nbuf, u_quad_t num, int base, int *len));
87230837Sdelphijstatic void  snprintf_func __P((int ch, void *arg));
88230837Sdelphij
89230837Sdelphijstatic int consintr = 1;		/* Ok to handle console interrupts? */
90230837Sdelphijstatic int msgbufmapped;		/* Set when safe to use msgbuf */
91230837Sdelphijint msgbuftrigger;
92230837Sdelphij
93230837Sdelphij/*
94230837Sdelphij * Warn that a system table is full.
95230837Sdelphij */
96230837Sdelphijvoid
97230837Sdelphijtablefull(const char *tab)
98230837Sdelphij{
99230837Sdelphij
100230837Sdelphij	log(LOG_ERR, "%s: table is full\n", tab);
101230837Sdelphij}
102230837Sdelphij
103230837Sdelphij/*
104230837Sdelphij * Uprintf prints to the controlling terminal for the current process.
105230837Sdelphij * It may block if the tty queue is overfull.  No message is printed if
106230837Sdelphij * the queue does not clear in a reasonable time.
107230837Sdelphij */
108230837Sdelphijint
109230837Sdelphijuprintf(const char *fmt, ...)
110230837Sdelphij{
111230837Sdelphij	struct proc *p = curproc;
112230837Sdelphij	va_list ap;
113230837Sdelphij	struct putchar_arg pca;
114230837Sdelphij	int retval = 0;
115230837Sdelphij
116230837Sdelphij	if (p && p != idleproc && p->p_flag & P_CONTROLT &&
117230837Sdelphij	    p->p_session->s_ttyvp) {
118230837Sdelphij		va_start(ap, fmt);
119230837Sdelphij		pca.tty = p->p_session->s_ttyp;
120230837Sdelphij		pca.flags = TOTTY;
121230837Sdelphij		retval = kvprintf(fmt, putchar, &pca, 10, ap);
122230837Sdelphij		va_end(ap);
123230837Sdelphij	}
124230837Sdelphij	return retval;
125230837Sdelphij}
126230837Sdelphij
127230837Sdelphij/*
128230837Sdelphij * tprintf prints on the controlling terminal associated
129230837Sdelphij * with the given session, possibly to the log as well.
130230837Sdelphij */
131230837Sdelphijvoid
132230837Sdelphijtprintf(struct proc *p, int pri, const char *fmt, ...)
133230837Sdelphij{
134230837Sdelphij	struct tty *tp = NULL;
135230837Sdelphij	int flags = 0, shld = 0;
136230837Sdelphij	va_list ap;
137230837Sdelphij	struct putchar_arg pca;
138230837Sdelphij	int retval;
139230837Sdelphij
140230837Sdelphij	if (pri != -1)
141230837Sdelphij		flags |= TOLOG;
142230837Sdelphij	if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
143230837Sdelphij		SESSHOLD(p->p_session);
144230837Sdelphij		shld++;
145230837Sdelphij		if (ttycheckoutq(p->p_session->s_ttyp, 0)) {
146230837Sdelphij			flags |= TOTTY;
147230837Sdelphij			tp = p->p_session->s_ttyp;
148230837Sdelphij		}
149230837Sdelphij	}
150230837Sdelphij	pca.pri = pri;
151230837Sdelphij	pca.tty = tp;
152230837Sdelphij	pca.flags = flags;
153230837Sdelphij	va_start(ap, fmt);
154230837Sdelphij	retval = kvprintf(fmt, putchar, &pca, 10, ap);
155230837Sdelphij	va_end(ap);
156230837Sdelphij	if (shld)
157230837Sdelphij		SESSRELE(p->p_session);
158230837Sdelphij	msgbuftrigger = 1;
159230837Sdelphij}
160230837Sdelphij
161230837Sdelphij/*
162230837Sdelphij * Ttyprintf displays a message on a tty; it should be used only by
163230837Sdelphij * the tty driver, or anything that knows the underlying tty will not
164230837Sdelphij * be revoke(2)'d away.  Other callers should use tprintf.
165230837Sdelphij */
166230837Sdelphijint
167230837Sdelphijttyprintf(struct tty *tp, const char *fmt, ...)
168230837Sdelphij{
169230837Sdelphij	va_list ap;
170230837Sdelphij	struct putchar_arg pca;
171230837Sdelphij	int retval;
172230837Sdelphij
173230837Sdelphij	va_start(ap, fmt);
174230837Sdelphij	pca.tty = tp;
175230837Sdelphij	pca.flags = TOTTY;
176230837Sdelphij	retval = kvprintf(fmt, putchar, &pca, 10, ap);
177230837Sdelphij	va_end(ap);
178230837Sdelphij	return retval;
179230837Sdelphij}
180230837Sdelphij
181230837Sdelphij/*
182230837Sdelphij * Log writes to the log buffer, and guarantees not to sleep (so can be
183230837Sdelphij * called by interrupt routines).  If there is no process reading the
184230837Sdelphij * log yet, it writes to the console also.
185230837Sdelphij */
186230837Sdelphijvoid
187230837Sdelphijlog(int level, const char *fmt, ...)
188230837Sdelphij{
189230837Sdelphij	va_list ap;
190230837Sdelphij	int retval;
191230837Sdelphij	struct putchar_arg pca;
192230837Sdelphij
193230837Sdelphij	pca.tty = NULL;
194230837Sdelphij	pca.pri = level;
195230837Sdelphij	pca.flags = log_open ? TOLOG : TOCONS;
196230837Sdelphij
197230837Sdelphij	va_start(ap, fmt);
198230837Sdelphij	retval = kvprintf(fmt, putchar, &pca, 10, ap);
199230837Sdelphij	va_end(ap);
200230837Sdelphij
201230837Sdelphij	msgbuftrigger = 1;
202230837Sdelphij}
203230837Sdelphij
204230837Sdelphij#define CONSCHUNK 128
205230837Sdelphij
206230837Sdelphijvoid
207230837Sdelphijlog_console(struct uio *uio)
208230837Sdelphij{
209230837Sdelphij	int c, i, error, iovlen, nl;
210230837Sdelphij	struct uio muio;
211230837Sdelphij	struct iovec *miov = NULL;
212230837Sdelphij	char *consbuffer;
213230837Sdelphij	int pri;
214230837Sdelphij
215230837Sdelphij	pri = LOG_INFO | LOG_CONSOLE;
216230837Sdelphij	muio = *uio;
217230837Sdelphij	iovlen = uio->uio_iovcnt * sizeof (struct iovec);
218230837Sdelphij	MALLOC(miov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
219230837Sdelphij	MALLOC(consbuffer, char *, CONSCHUNK, M_TEMP, M_WAITOK);
220230837Sdelphij	bcopy((caddr_t)muio.uio_iov, (caddr_t)miov, iovlen);
221230837Sdelphij	muio.uio_iov = miov;
222230837Sdelphij	uio = &muio;
223230837Sdelphij
224230837Sdelphij	nl = 0;
225230837Sdelphij	while (uio->uio_resid > 0) {
226230837Sdelphij		c = imin(uio->uio_resid, CONSCHUNK);
227230837Sdelphij		error = uiomove(consbuffer, c, uio);
228230837Sdelphij		if (error != 0)
229230837Sdelphij			return;
230230837Sdelphij		for (i = 0; i < c; i++) {
231230837Sdelphij			msglogchar(consbuffer[i], pri);
232230837Sdelphij			if (consbuffer[i] == '\n')
233230837Sdelphij				nl = 1;
234230837Sdelphij			else
235230837Sdelphij				nl = 0;
236230837Sdelphij		}
237230837Sdelphij	}
238230837Sdelphij	if (!nl)
239230837Sdelphij		msglogchar('\n', pri);
240230837Sdelphij	msgbuftrigger = 1;
241230837Sdelphij	FREE(miov, M_TEMP);
242230837Sdelphij	FREE(consbuffer, M_TEMP);
243230837Sdelphij	return;
244230837Sdelphij}
245230837Sdelphij
246230837Sdelphijint
247230837Sdelphijprintf(const char *fmt, ...)
248230837Sdelphij{
249230837Sdelphij	va_list ap;
250230837Sdelphij	int savintr;
251230837Sdelphij	struct putchar_arg pca;
252230837Sdelphij	int retval;
253230837Sdelphij
254230837Sdelphij	savintr = consintr;		/* disable interrupts */
255230837Sdelphij	consintr = 0;
256230837Sdelphij	va_start(ap, fmt);
257230837Sdelphij	pca.tty = NULL;
258230837Sdelphij	pca.flags = TOCONS | TOLOG;
259230837Sdelphij	pca.pri = -1;
260230837Sdelphij	retval = kvprintf(fmt, putchar, &pca, 10, ap);
261230837Sdelphij	va_end(ap);
262230837Sdelphij	if (!panicstr)
263230837Sdelphij		msgbuftrigger = 1;
264230837Sdelphij	consintr = savintr;		/* reenable interrupts */
265230837Sdelphij	return retval;
266230837Sdelphij}
267230837Sdelphij
268230837Sdelphijint
269230837Sdelphijvprintf(const char *fmt, va_list ap)
270230837Sdelphij{
271230837Sdelphij	int savintr;
272230837Sdelphij	struct putchar_arg pca;
273230837Sdelphij	int retval;
274230837Sdelphij
275230837Sdelphij	savintr = consintr;		/* disable interrupts */
276230837Sdelphij	consintr = 0;
277230837Sdelphij	pca.tty = NULL;
278230837Sdelphij	pca.flags = TOCONS | TOLOG;
279230837Sdelphij	pca.pri = -1;
280230837Sdelphij	retval = kvprintf(fmt, putchar, &pca, 10, ap);
281230837Sdelphij	if (!panicstr)
282230837Sdelphij		msgbuftrigger = 1;
283230837Sdelphij	consintr = savintr;		/* reenable interrupts */
284230837Sdelphij	return retval;
285230837Sdelphij}
286230837Sdelphij
287230837Sdelphij/*
288230837Sdelphij * Print a character on console or users terminal.  If destination is
289230837Sdelphij * the console then the last bunch of characters are saved in msgbuf for
290230837Sdelphij * inspection later.
291230837Sdelphij */
292230837Sdelphijstatic void
293230837Sdelphijputchar(int c, void *arg)
294230837Sdelphij{
295230837Sdelphij	struct putchar_arg *ap = (struct putchar_arg*) arg;
296230837Sdelphij	int flags = ap->flags;
297230837Sdelphij	struct tty *tp = ap->tty;
298230837Sdelphij	if (panicstr)
299230837Sdelphij		constty = NULL;
300230837Sdelphij	if ((flags & TOCONS) && tp == NULL && constty) {
301230837Sdelphij		tp = constty;
302230837Sdelphij		flags |= TOTTY;
303230837Sdelphij	}
304230837Sdelphij	if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
305230837Sdelphij	    (flags & TOCONS) && tp == constty)
306230837Sdelphij		constty = NULL;
307230837Sdelphij	if ((flags & TOLOG))
308230837Sdelphij		msglogchar(c, ap->pri);
309230837Sdelphij	if ((flags & TOCONS) && constty == NULL && c != '\0')
310230837Sdelphij		(*v_putc)(c);
311230837Sdelphij}
312230837Sdelphij
313230837Sdelphij/*
314230837Sdelphij * Scaled down version of sprintf(3).
315230837Sdelphij */
316230837Sdelphijint
317230837Sdelphijsprintf(char *buf, const char *cfmt, ...)
318230837Sdelphij{
319230837Sdelphij	int retval;
320230837Sdelphij	va_list ap;
321230837Sdelphij
322230837Sdelphij	va_start(ap, cfmt);
323230837Sdelphij	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
324230837Sdelphij	buf[retval] = '\0';
325230837Sdelphij	va_end(ap);
326230837Sdelphij	return retval;
327230837Sdelphij}
328230837Sdelphij
329230837Sdelphij/*
330230837Sdelphij * Scaled down version of vsprintf(3).
331230837Sdelphij */
332230837Sdelphijint
333230837Sdelphijvsprintf(char *buf, const char *cfmt, va_list ap)
334230837Sdelphij{
335230837Sdelphij	int retval;
336230837Sdelphij
337230837Sdelphij	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
338230837Sdelphij	buf[retval] = '\0';
339230837Sdelphij	return retval;
340230837Sdelphij}
341230837Sdelphij
342230837Sdelphij/*
343230837Sdelphij * Scaled down version of snprintf(3).
344230837Sdelphij */
345230837Sdelphijint
346230837Sdelphijsnprintf(char *str, size_t size, const char *format, ...)
347230837Sdelphij{
348230837Sdelphij	int retval;
349230837Sdelphij	va_list ap;
350230837Sdelphij
351230837Sdelphij	va_start(ap, format);
352230837Sdelphij	retval = vsnprintf(str, size, format, ap);
353230837Sdelphij	va_end(ap);
354230837Sdelphij	return(retval);
355230837Sdelphij}
356230837Sdelphij
357230837Sdelphij/*
358230837Sdelphij * Scaled down version of vsnprintf(3).
359230837Sdelphij */
360230837Sdelphijint
361230837Sdelphijvsnprintf(char *str, size_t size, const char *format, va_list ap)
362230837Sdelphij{
363230837Sdelphij	struct snprintf_arg info;
364230837Sdelphij	int retval;
365230837Sdelphij
366230837Sdelphij	info.str = str;
367230837Sdelphij	info.remain = size;
368230837Sdelphij	retval = kvprintf(format, snprintf_func, &info, 10, ap);
369230837Sdelphij	if (info.remain >= 1)
370230837Sdelphij		*info.str++ = '\0';
371230837Sdelphij	return retval;
372230837Sdelphij}
373230837Sdelphij
374230837Sdelphijstatic void
375230837Sdelphijsnprintf_func(int ch, void *arg)
376230837Sdelphij{
377230837Sdelphij	struct snprintf_arg *const info = arg;
378230837Sdelphij
379230837Sdelphij	if (info->remain >= 2) {
380230837Sdelphij		*info->str++ = ch;
381230837Sdelphij		info->remain--;
382230837Sdelphij	}
383230837Sdelphij}
384230837Sdelphij
385230837Sdelphij/*
386230837Sdelphij * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
387230837Sdelphij * order; return an optional length and a pointer to the last character
388230837Sdelphij * written in the buffer (i.e., the first character of the string).
389230837Sdelphij * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
390230837Sdelphij */
391230837Sdelphijstatic char *
392230837Sdelphijksprintn(nbuf, ul, base, lenp)
393230837Sdelphij	char *nbuf;
394230837Sdelphij	u_long ul;
395230837Sdelphij	int base, *lenp;
396230837Sdelphij{
397230837Sdelphij	char *p;
398230837Sdelphij
399230837Sdelphij	p = nbuf;
400230837Sdelphij	*p = '\0';
401230837Sdelphij	do {
402230837Sdelphij		*++p = hex2ascii(ul % base);
403230837Sdelphij	} while (ul /= base);
404230837Sdelphij	if (lenp)
405230837Sdelphij		*lenp = p - nbuf;
406230837Sdelphij	return (p);
407230837Sdelphij}
408230837Sdelphij/* ksprintn, but for a quad_t. */
409230837Sdelphijstatic char *
410230837Sdelphijksprintqn(nbuf, uq, base, lenp)
411230837Sdelphij	char *nbuf;
412230837Sdelphij	u_quad_t uq;
413230837Sdelphij	int base, *lenp;
414230837Sdelphij{
415230837Sdelphij	char *p;
416230837Sdelphij
417230837Sdelphij	p = nbuf;
418230837Sdelphij	*p = '\0';
419230837Sdelphij	do {
420230837Sdelphij		*++p = hex2ascii(uq % base);
421230837Sdelphij	} while (uq /= base);
422230837Sdelphij	if (lenp)
423230837Sdelphij		*lenp = p - nbuf;
424230837Sdelphij	return (p);
425230837Sdelphij}
426230837Sdelphij
427230837Sdelphij/*
428230837Sdelphij * Scaled down version of printf(3).
429230837Sdelphij *
430230837Sdelphij * Two additional formats:
431230837Sdelphij *
432230837Sdelphij * The format %b is supported to decode error registers.
433230837Sdelphij * Its usage is:
434230837Sdelphij *
435230837Sdelphij *	printf("reg=%b\n", regval, "<base><arg>*");
436230837Sdelphij *
437230837Sdelphij * where <base> is the output base expressed as a control character, e.g.
438230837Sdelphij * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
439230837Sdelphij * the first of which gives the bit number to be inspected (origin 1), and
440230837Sdelphij * the next characters (up to a control character, i.e. a character <= 32),
441230837Sdelphij * give the name of the register.  Thus:
442230837Sdelphij *
443230837Sdelphij *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
444230837Sdelphij *
445230837Sdelphij * would produce output:
446230837Sdelphij *
447230837Sdelphij *	reg=3<BITTWO,BITONE>
448230837Sdelphij *
449230837Sdelphij * XXX:  %D  -- Hexdump, takes pointer and separator string:
450230837Sdelphij *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
451230837Sdelphij *		("%*D", len, ptr, " " -> XX XX XX XX ...
452230837Sdelphij */
453230837Sdelphijint
454230837Sdelphijkvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
455230837Sdelphij{
456230837Sdelphij#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
457230837Sdelphij	char nbuf[MAXNBUF];
458230837Sdelphij	char *p, *q, *d;
459230837Sdelphij	u_char *up;
460230837Sdelphij	int ch, n;
461230837Sdelphij	u_long ul;
462230837Sdelphij	u_quad_t uq;
463230837Sdelphij	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
464230837Sdelphij	int dwidth;
465230837Sdelphij	char padc;
466230837Sdelphij	int retval = 0;
467230837Sdelphij
468230837Sdelphij	ul = 0;
469230837Sdelphij	uq = 0;
470230837Sdelphij	if (!func)
471230837Sdelphij		d = (char *) arg;
472230837Sdelphij	else
473230837Sdelphij		d = NULL;
474230837Sdelphij
475230837Sdelphij	if (fmt == NULL)
476230837Sdelphij		fmt = "(fmt null)\n";
477230837Sdelphij
478230837Sdelphij	if (radix < 2 || radix > 36)
479230837Sdelphij		radix = 10;
480230837Sdelphij
481230837Sdelphij	for (;;) {
482230837Sdelphij		padc = ' ';
483230837Sdelphij		width = 0;
484230837Sdelphij		while ((ch = (u_char)*fmt++) != '%') {
485230837Sdelphij			if (ch == '\0')
486230837Sdelphij				return retval;
487230837Sdelphij			PCHAR(ch);
488230837Sdelphij		}
489230837Sdelphij		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
490230837Sdelphij		sign = 0; dot = 0; dwidth = 0;
491230837Sdelphijreswitch:	switch (ch = (u_char)*fmt++) {
492230837Sdelphij		case '.':
493230837Sdelphij			dot = 1;
494230837Sdelphij			goto reswitch;
495230837Sdelphij		case '#':
496230837Sdelphij			sharpflag = 1;
497230837Sdelphij			goto reswitch;
498230837Sdelphij		case '+':
499230837Sdelphij			sign = 1;
500230837Sdelphij			goto reswitch;
501230837Sdelphij		case '-':
502230837Sdelphij			ladjust = 1;
503230837Sdelphij			goto reswitch;
504230837Sdelphij		case '%':
505230837Sdelphij			PCHAR(ch);
506230837Sdelphij			break;
507230837Sdelphij		case '*':
508230837Sdelphij			if (!dot) {
509230837Sdelphij				width = va_arg(ap, int);
510230837Sdelphij				if (width < 0) {
511230837Sdelphij					ladjust = !ladjust;
512230837Sdelphij					width = -width;
513230837Sdelphij				}
514230837Sdelphij			} else {
515230837Sdelphij				dwidth = va_arg(ap, int);
516230837Sdelphij			}
517230837Sdelphij			goto reswitch;
518230837Sdelphij		case '0':
519230837Sdelphij			if (!dot) {
520230837Sdelphij				padc = '0';
521230837Sdelphij				goto reswitch;
522230837Sdelphij			}
523230837Sdelphij		case '1': case '2': case '3': case '4':
524230837Sdelphij		case '5': case '6': case '7': case '8': case '9':
525230837Sdelphij				for (n = 0;; ++fmt) {
526230837Sdelphij					n = n * 10 + ch - '0';
527230837Sdelphij					ch = *fmt;
528230837Sdelphij					if (ch < '0' || ch > '9')
529230837Sdelphij						break;
530230837Sdelphij				}
531230837Sdelphij			if (dot)
532230837Sdelphij				dwidth = n;
533230837Sdelphij			else
534230837Sdelphij				width = n;
535230837Sdelphij			goto reswitch;
536230837Sdelphij		case 'b':
537230837Sdelphij			ul = va_arg(ap, int);
538230837Sdelphij			p = va_arg(ap, char *);
539230837Sdelphij			for (q = ksprintn(nbuf, ul, *p++, NULL); *q;)
540230837Sdelphij				PCHAR(*q--);
541230837Sdelphij
542230837Sdelphij			if (!ul)
543230837Sdelphij				break;
544230837Sdelphij
545230837Sdelphij			for (tmp = 0; *p;) {
546230837Sdelphij				n = *p++;
547230837Sdelphij				if (ul & (1 << (n - 1))) {
548230837Sdelphij					PCHAR(tmp ? ',' : '<');
549230837Sdelphij					for (; (n = *p) > ' '; ++p)
550230837Sdelphij						PCHAR(n);
551230837Sdelphij					tmp = 1;
552230837Sdelphij				} else
553230837Sdelphij					for (; *p > ' '; ++p)
554230837Sdelphij						continue;
555230837Sdelphij			}
556230837Sdelphij			if (tmp)
557230837Sdelphij				PCHAR('>');
558230837Sdelphij			break;
559230837Sdelphij		case 'c':
560230837Sdelphij			PCHAR(va_arg(ap, int));
561230837Sdelphij			break;
562230837Sdelphij		case 'D':
563230837Sdelphij			up = va_arg(ap, u_char *);
564230837Sdelphij			p = va_arg(ap, char *);
565230837Sdelphij			if (!width)
566230837Sdelphij				width = 16;
567230837Sdelphij			while(width--) {
568230837Sdelphij				PCHAR(hex2ascii(*up >> 4));
569230837Sdelphij				PCHAR(hex2ascii(*up & 0x0f));
570230837Sdelphij				up++;
571230837Sdelphij				if (width)
572230837Sdelphij					for (q=p;*q;q++)
573230837Sdelphij						PCHAR(*q);
574230837Sdelphij			}
575230837Sdelphij			break;
576230837Sdelphij		case 'd':
577230837Sdelphij			if (qflag)
578230837Sdelphij				uq = va_arg(ap, quad_t);
579230837Sdelphij			else if (lflag)
580230837Sdelphij				ul = va_arg(ap, long);
581230837Sdelphij			else
582230837Sdelphij				ul = va_arg(ap, int);
583230837Sdelphij			sign = 1;
584230837Sdelphij			base = 10;
585230837Sdelphij			goto number;
586230837Sdelphij		case 'l':
587230837Sdelphij			if (lflag) {
588230837Sdelphij				lflag = 0;
589230837Sdelphij				qflag = 1;
590230837Sdelphij			} else
591230837Sdelphij				lflag = 1;
592230837Sdelphij			goto reswitch;
593230837Sdelphij		case 'o':
594230837Sdelphij			if (qflag)
595230837Sdelphij				uq = va_arg(ap, u_quad_t);
596230837Sdelphij			else if (lflag)
597230837Sdelphij				ul = va_arg(ap, u_long);
598230837Sdelphij			else
599230837Sdelphij				ul = va_arg(ap, u_int);
600230837Sdelphij			base = 8;
601230837Sdelphij			goto nosign;
602230837Sdelphij		case 'p':
603230837Sdelphij			ul = (uintptr_t)va_arg(ap, void *);
604230837Sdelphij			base = 16;
605230837Sdelphij			sharpflag = (width == 0);
606230837Sdelphij			goto nosign;
607230837Sdelphij		case 'q':
608230837Sdelphij			qflag = 1;
609230837Sdelphij			goto reswitch;
610230837Sdelphij		case 'n':
611230837Sdelphij		case 'r':
612230837Sdelphij			if (qflag)
613230837Sdelphij				uq = va_arg(ap, u_quad_t);
614230837Sdelphij			else if (lflag)
615230837Sdelphij				ul = va_arg(ap, u_long);
616230837Sdelphij			else
617230837Sdelphij				ul = sign ?
618230837Sdelphij				    (u_long)va_arg(ap, int) : va_arg(ap, u_int);
619230837Sdelphij			base = radix;
620230837Sdelphij			goto number;
621230837Sdelphij		case 's':
622230837Sdelphij			p = va_arg(ap, char *);
623230837Sdelphij			if (p == NULL)
624230837Sdelphij				p = "(null)";
625230837Sdelphij			if (!dot)
626230837Sdelphij				n = strlen (p);
627230837Sdelphij			else
628230837Sdelphij				for (n = 0; n < dwidth && p[n]; n++)
629230837Sdelphij					continue;
630230837Sdelphij
631230837Sdelphij			width -= n;
632230837Sdelphij
633230837Sdelphij			if (!ladjust && width > 0)
634230837Sdelphij				while (width--)
635230837Sdelphij					PCHAR(padc);
636230837Sdelphij			while (n--)
637230837Sdelphij				PCHAR(*p++);
638230837Sdelphij			if (ladjust && width > 0)
639230837Sdelphij				while (width--)
640230837Sdelphij					PCHAR(padc);
641230837Sdelphij			break;
642230837Sdelphij		case 'u':
643230837Sdelphij			if (qflag)
644230837Sdelphij				uq = va_arg(ap, u_quad_t);
645230837Sdelphij			else if (lflag)
646230837Sdelphij				ul = va_arg(ap, u_long);
647230837Sdelphij			else
648230837Sdelphij				ul = va_arg(ap, u_int);
649230837Sdelphij			base = 10;
650230837Sdelphij			goto nosign;
651230837Sdelphij		case 'x':
652230837Sdelphij		case 'X':
653230837Sdelphij			if (qflag)
654230837Sdelphij				uq = va_arg(ap, u_quad_t);
655230837Sdelphij			else if (lflag)
656230837Sdelphij				ul = va_arg(ap, u_long);
657230837Sdelphij			else
658230837Sdelphij				ul = va_arg(ap, u_int);
659230837Sdelphij			base = 16;
660230837Sdelphij			goto nosign;
661230837Sdelphij		case 'z':
662230837Sdelphij			if (qflag)
663230837Sdelphij				uq = va_arg(ap, u_quad_t);
664230837Sdelphij			else if (lflag)
665230837Sdelphij				ul = va_arg(ap, u_long);
666230837Sdelphij			else
667230837Sdelphij				ul = sign ?
668230837Sdelphij				    (u_long)va_arg(ap, int) : va_arg(ap, u_int);
669230837Sdelphij			base = 16;
670230837Sdelphij			goto number;
671230837Sdelphijnosign:			sign = 0;
672number:
673			if (qflag) {
674				if (sign && (quad_t)uq < 0) {
675					neg = 1;
676					uq = -(quad_t)uq;
677				}
678				p = ksprintqn(nbuf, uq, base, &tmp);
679			} else {
680				if (sign && (long)ul < 0) {
681					neg = 1;
682					ul = -(long)ul;
683				}
684				p = ksprintn(nbuf, ul, base, &tmp);
685			}
686			if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
687				if (base == 8)
688					tmp++;
689				else if (base == 16)
690					tmp += 2;
691			}
692			if (neg)
693				tmp++;
694
695			if (!ladjust && width && (width -= tmp) > 0)
696				while (width--)
697					PCHAR(padc);
698			if (neg)
699				PCHAR('-');
700			if (sharpflag && (qflag ? uq != 0 : ul != 0)) {
701				if (base == 8) {
702					PCHAR('0');
703				} else if (base == 16) {
704					PCHAR('0');
705					PCHAR('x');
706				}
707			}
708
709			while (*p)
710				PCHAR(*p--);
711
712			if (ladjust && width && (width -= tmp) > 0)
713				while (width--)
714					PCHAR(padc);
715
716			break;
717		default:
718			PCHAR('%');
719			if (lflag)
720				PCHAR('l');
721			PCHAR(ch);
722			break;
723		}
724	}
725#undef PCHAR
726}
727
728/*
729 * Put character in log buffer with a particular priority.
730 */
731static void
732msglogchar(int c, int pri)
733{
734	static int lastpri = -1;
735	static int dangling;
736	char nbuf[MAXNBUF];
737	char *p;
738
739	if (!msgbufmapped)
740		return;
741	if (c == '\0' || c == '\r')
742		return;
743	if (pri != -1 && pri != lastpri) {
744		if (dangling) {
745			msgaddchar('\n', NULL);
746			dangling = 0;
747		}
748		msgaddchar('<', NULL);
749		for (p = ksprintn(nbuf, (u_long)pri, 10, NULL); *p;)
750			msgaddchar(*p--, NULL);
751		msgaddchar('>', NULL);
752		lastpri = pri;
753	}
754	msgaddchar(c, NULL);
755	if (c == '\n') {
756		dangling = 0;
757		lastpri = -1;
758	} else {
759		dangling = 1;
760	}
761}
762
763/*
764 * Put char in log buffer
765 */
766static void
767msgaddchar(int c, void *dummy)
768{
769	struct msgbuf *mbp;
770
771	if (!msgbufmapped)
772		return;
773	mbp = msgbufp;
774	mbp->msg_ptr[mbp->msg_bufx++] = c;
775	if (mbp->msg_bufx >= mbp->msg_size)
776		mbp->msg_bufx = 0;
777	/* If the buffer is full, keep the most recent data. */
778	if (mbp->msg_bufr == mbp->msg_bufx) {
779		if (++mbp->msg_bufr >= mbp->msg_size)
780			mbp->msg_bufr = 0;
781	}
782}
783
784static void
785msgbufcopy(struct msgbuf *oldp)
786{
787	int pos;
788
789	pos = oldp->msg_bufr;
790	while (pos != oldp->msg_bufx) {
791		msglogchar(oldp->msg_ptr[pos], -1);
792		if (++pos >= oldp->msg_size)
793			pos = 0;
794	}
795}
796
797void
798msgbufinit(void *ptr, size_t size)
799{
800	char *cp;
801	static struct msgbuf *oldp = NULL;
802
803	cp = (char *)ptr;
804	msgbufp = (struct msgbuf *) (cp + size - sizeof(*msgbufp));
805	if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_ptr != cp) {
806		bzero(cp, size);
807		msgbufp->msg_magic = MSG_MAGIC;
808		msgbufp->msg_size = (char *)msgbufp - cp;
809		msgbufp->msg_ptr = cp;
810	}
811	if (msgbufmapped && oldp != msgbufp)
812		msgbufcopy(oldp);
813	msgbufmapped = 1;
814	oldp = msgbufp;
815}
816
817#include "opt_ddb.h"
818#ifdef DDB
819#include <ddb/ddb.h>
820
821DB_SHOW_COMMAND(msgbuf, db_show_msgbuf)
822{
823	int i, j;
824
825	if (!msgbufmapped) {
826		db_printf("msgbuf not mapped yet\n");
827		return;
828	}
829	db_printf("msgbufp = %p\n", msgbufp);
830	db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n",
831	    msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr,
832	    msgbufp->msg_bufx, msgbufp->msg_ptr);
833	for (i = 0; i < msgbufp->msg_size; i++) {
834		j = (i + msgbufp->msg_bufr) % msgbufp->msg_size;
835		db_printf("%c", msgbufp->msg_ptr[j]);
836	}
837	db_printf("\n");
838}
839
840#endif /* DDB */
841