Annotation of src/sys/kern/subr_prf.c, Revision 1.37
1.37 ! thorpej 1: /* $NetBSD: subr_prf.c,v 1.36 1996/10/27 21:55:20 gwr Exp $ */
1.15 cgd 2:
1.12 cgd 3: /*-
4: * Copyright (c) 1986, 1988, 1991, 1993
5: * The Regents of the University of California. All rights reserved.
6: * (c) UNIX System Laboratories, Inc.
7: * All or some portions of this file are derived from material licensed
8: * to the University of California by American Telephone and Telegraph
9: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10: * the permission of UNIX System Laboratories, Inc.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the University of
23: * California, Berkeley and its contributors.
24: * 4. Neither the name of the University nor the names of its contributors
25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
39: *
1.15 cgd 40: * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
1.12 cgd 41: */
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/buf.h>
46: #include <sys/conf.h>
47: #include <sys/reboot.h>
48: #include <sys/msgbuf.h>
49: #include <sys/proc.h>
50: #include <sys/ioctl.h>
51: #include <sys/vnode.h>
52: #include <sys/file.h>
53: #include <sys/tty.h>
54: #include <sys/tprintf.h>
55: #include <sys/syslog.h>
56: #include <sys/malloc.h>
57:
1.20 christos 58: #include <dev/cons.h>
59:
1.12 cgd 60: /*
61: * Note that stdarg.h and the ANSI style va_start macro is used for both
62: * ANSI and traditional C compilers.
1.35 gwr 63: * XXX: This requires that stdarg.h defines: va_alist, va_dcl
1.12 cgd 64: */
65: #include <machine/stdarg.h>
66:
1.32 ws 67: #include "ipkdb.h"
1.28 ws 68:
1.12 cgd 69: #ifdef KADB
70: #include <machine/kdbparam.h>
1.22 christos 71: #endif
72: #ifdef KGDB
73: #include <machine/cpu.h>
1.12 cgd 74: #endif
1.20 christos 75:
1.12 cgd 76: #define TOCONS 0x01
77: #define TOTTY 0x02
78: #define TOLOG 0x04
79:
1.37 ! thorpej 80: /*
! 81: * This is the size of the buffer that should be passed to ksnprintn().
! 82: * It's the length of a long in base 8, plus NULL.
! 83: */
! 84: #define KSNPRINTN_BUFSIZE (sizeof(long) * NBBY / 3 + 2)
! 85:
1.12 cgd 86: struct tty *constty; /* pointer to console "window" tty */
87:
1.20 christos 88: void (*v_putc) __P((int)) = cnputc; /* routine to putc on virtual console */
1.12 cgd 89:
1.20 christos 90: static void putchar __P((int, int, struct tty *));
1.37 ! thorpej 91: static char *ksnprintn __P((u_long, int, int *, char *, size_t));
1.30 christos 92: void kprintf __P((const char *, int, struct tty *, va_list));
1.12 cgd 93:
1.14 cgd 94: int consintr = 1; /* Ok to handle console interrupts? */
1.12 cgd 95:
96: /*
1.14 cgd 97: * Variable panicstr contains argument to first call to panic; used as flag
98: * to indicate that the kernel has already called panic.
1.12 cgd 99: */
1.14 cgd 100: const char *panicstr;
1.12 cgd 101:
102: /*
103: * Panic is called on unresolvable fatal errors. It prints "panic: mesg",
104: * and then reboots. If we are called twice, then we avoid trying to sync
105: * the disks as this often leads to recursive panics.
106: */
1.14 cgd 107: void
1.12 cgd 108: #ifdef __STDC__
109: panic(const char *fmt, ...)
110: #else
1.14 cgd 111: panic(fmt, va_alist)
1.12 cgd 112: char *fmt;
1.20 christos 113: va_dcl
1.12 cgd 114: #endif
115: {
1.14 cgd 116: int bootopt;
1.12 cgd 117: va_list ap;
118:
1.14 cgd 119: bootopt = RB_AUTOBOOT | RB_DUMP;
1.12 cgd 120: if (panicstr)
121: bootopt |= RB_NOSYNC;
122: else
123: panicstr = fmt;
124:
125: va_start(ap, fmt);
1.31 cgd 126: printf("panic: %:\n", fmt, ap);
1.12 cgd 127: va_end(ap);
128:
1.32 ws 129: #if NIPKDB > 0
130: ipkdb_panic();
1.28 ws 131: #endif
1.12 cgd 132: #ifdef KGDB
133: kgdb_panic();
134: #endif
135: #ifdef KADB
1.14 cgd 136: if (boothowto & RB_KDB)
137: kdbpanic();
1.12 cgd 138: #endif
139: #ifdef DDB
140: Debugger();
141: #endif
1.26 mrg 142: boot(bootopt, NULL);
1.12 cgd 143: }
144:
145: /*
146: * Warn that a system table is full.
147: */
148: void
149: tablefull(tab)
150: const char *tab;
151: {
152:
153: log(LOG_ERR, "%s: table is full\n", tab);
154: }
155:
156: /*
157: * Uprintf prints to the controlling terminal for the current process.
158: * It may block if the tty queue is overfull. No message is printed if
159: * the queue does not clear in a reasonable time.
160: */
161: void
162: #ifdef __STDC__
163: uprintf(const char *fmt, ...)
164: #else
1.14 cgd 165: uprintf(fmt, va_alist)
1.12 cgd 166: char *fmt;
1.20 christos 167: va_dcl
1.12 cgd 168: #endif
169: {
170: register struct proc *p = curproc;
171: va_list ap;
172:
173: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
174: va_start(ap, fmt);
1.30 christos 175: kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap);
1.12 cgd 176: va_end(ap);
177: }
178: }
179:
180: tpr_t
181: tprintf_open(p)
182: register struct proc *p;
183: {
184:
185: if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) {
186: SESSHOLD(p->p_session);
187: return ((tpr_t) p->p_session);
188: }
189: return ((tpr_t) NULL);
190: }
191:
192: void
193: tprintf_close(sess)
194: tpr_t sess;
195: {
196:
197: if (sess)
198: SESSRELE((struct session *) sess);
199: }
200:
201: /*
202: * tprintf prints on the controlling terminal associated
203: * with the given session.
204: */
205: void
206: #ifdef __STDC__
207: tprintf(tpr_t tpr, const char *fmt, ...)
208: #else
1.14 cgd 209: tprintf(tpr, fmt, va_alist)
1.12 cgd 210: tpr_t tpr;
211: char *fmt;
1.20 christos 212: va_dcl
1.12 cgd 213: #endif
214: {
215: register struct session *sess = (struct session *)tpr;
216: struct tty *tp = NULL;
217: int flags = TOLOG;
218: va_list ap;
219:
220: logpri(LOG_INFO);
221: if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) {
222: flags |= TOTTY;
223: tp = sess->s_ttyp;
224: }
225: va_start(ap, fmt);
1.30 christos 226: kprintf(fmt, flags, tp, ap);
1.12 cgd 227: va_end(ap);
228: logwakeup();
229: }
230:
231: /*
232: * Ttyprintf displays a message on a tty; it should be used only by
233: * the tty driver, or anything that knows the underlying tty will not
234: * be revoke(2)'d away. Other callers should use tprintf.
235: */
236: void
237: #ifdef __STDC__
238: ttyprintf(struct tty *tp, const char *fmt, ...)
239: #else
1.14 cgd 240: ttyprintf(tp, fmt, va_alist)
1.12 cgd 241: struct tty *tp;
242: char *fmt;
1.20 christos 243: va_dcl
1.12 cgd 244: #endif
245: {
246: va_list ap;
247:
248: va_start(ap, fmt);
1.30 christos 249: kprintf(fmt, TOTTY, tp, ap);
1.12 cgd 250: va_end(ap);
251: }
252:
253: extern int log_open;
254:
255: /*
256: * Log writes to the log buffer, and guarantees not to sleep (so can be
257: * called by interrupt routines). If there is no process reading the
258: * log yet, it writes to the console also.
259: */
260: void
261: #ifdef __STDC__
262: log(int level, const char *fmt, ...)
263: #else
1.14 cgd 264: log(level, fmt, va_alist)
1.12 cgd 265: int level;
266: char *fmt;
1.20 christos 267: va_dcl
1.12 cgd 268: #endif
269: {
270: register int s;
271: va_list ap;
272:
273: s = splhigh();
274: logpri(level);
275: va_start(ap, fmt);
1.30 christos 276: kprintf(fmt, TOLOG, NULL, ap);
1.12 cgd 277: splx(s);
278: va_end(ap);
279: if (!log_open) {
280: va_start(ap, fmt);
1.30 christos 281: kprintf(fmt, TOCONS, NULL, ap);
1.12 cgd 282: va_end(ap);
283: }
284: logwakeup();
285: }
286:
1.13 mycroft 287: void
1.12 cgd 288: logpri(level)
289: int level;
290: {
291: register int ch;
292: register char *p;
1.37 ! thorpej 293: char snbuf[KSNPRINTN_BUFSIZE];
1.12 cgd 294:
295: putchar('<', TOLOG, NULL);
1.37 ! thorpej 296: for (p = ksnprintn((u_long)level, 10, NULL, snbuf, sizeof(snbuf));
! 297: (ch = *p--) != 0;)
1.12 cgd 298: putchar(ch, TOLOG, NULL);
299: putchar('>', TOLOG, NULL);
300: }
301:
302: void
303: #ifdef __STDC__
304: addlog(const char *fmt, ...)
305: #else
1.14 cgd 306: addlog(fmt, va_alist)
1.12 cgd 307: char *fmt;
1.20 christos 308: va_dcl
1.12 cgd 309: #endif
310: {
311: register int s;
312: va_list ap;
313:
314: s = splhigh();
315: va_start(ap, fmt);
1.30 christos 316: kprintf(fmt, TOLOG, NULL, ap);
1.12 cgd 317: splx(s);
318: va_end(ap);
319: if (!log_open) {
320: va_start(ap, fmt);
1.30 christos 321: kprintf(fmt, TOCONS, NULL, ap);
1.12 cgd 322: va_end(ap);
323: }
324: logwakeup();
325: }
326:
327: void
328: #ifdef __STDC__
1.30 christos 329: printf(const char *fmt, ...)
1.12 cgd 330: #else
1.30 christos 331: printf(fmt, va_alist)
1.12 cgd 332: char *fmt;
1.20 christos 333: va_dcl
1.12 cgd 334: #endif
335: {
336: va_list ap;
337: register int savintr;
338:
339: savintr = consintr; /* disable interrupts */
340: consintr = 0;
341: va_start(ap, fmt);
1.30 christos 342: kprintf(fmt, TOCONS | TOLOG, NULL, ap);
1.12 cgd 343: va_end(ap);
344: if (!panicstr)
345: logwakeup();
346: consintr = savintr; /* reenable interrupts */
347: }
348:
349: /*
350: * Scaled down version of printf(3).
351: *
352: * Two additional formats:
353: *
354: * The format %b is supported to decode error registers.
355: * Its usage is:
356: *
1.30 christos 357: * printf("reg=%b\n", regval, "<base><arg>*");
1.12 cgd 358: *
359: * where <base> is the output base expressed as a control character, e.g.
360: * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
361: * the first of which gives the bit number to be inspected (origin 1), and
362: * the next characters (up to a control character, i.e. a character <= 32),
363: * give the name of the register. Thus:
364: *
1.30 christos 365: * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
1.12 cgd 366: *
367: * would produce output:
368: *
369: * reg=3<BITTWO,BITONE>
370: *
1.24 christos 371: * The format %: passes an additional format string and argument list
1.14 cgd 372: * recursively. Its usage is:
1.12 cgd 373: *
1.14 cgd 374: * fn(char *fmt, ...)
1.12 cgd 375: * {
376: * va_list ap;
377: * va_start(ap, fmt);
1.30 christos 378: * printf("prefix: %: suffix\n", fmt, ap);
1.12 cgd 379: * va_end(ap);
1.14 cgd 380: * }
1.12 cgd 381: *
382: * Space or zero padding and a field width are supported for the numeric
383: * formats only.
384: */
385: void
1.30 christos 386: kprintf(fmt, flags, tp, ap)
1.12 cgd 387: register const char *fmt;
388: int flags;
389: struct tty *tp;
390: va_list ap;
391: {
1.14 cgd 392: register char *p, *q;
1.12 cgd 393: register int ch, n;
394: u_long ul;
395: int base, lflag, tmp, width;
1.37 ! thorpej 396: char padc, snbuf[KSNPRINTN_BUFSIZE];
1.12 cgd 397:
398: for (;;) {
399: padc = ' ';
400: width = 0;
1.33 cgd 401: while ((ch = *(const u_char *)fmt++) != '%') {
1.12 cgd 402: if (ch == '\0')
403: return;
404: putchar(ch, flags, tp);
405: }
406: lflag = 0;
1.33 cgd 407: reswitch: switch (ch = *(const u_char *)fmt++) {
1.12 cgd 408: case '0':
1.27 christos 409: case '.':
1.12 cgd 410: padc = '0';
411: goto reswitch;
412: case '1': case '2': case '3': case '4':
413: case '5': case '6': case '7': case '8': case '9':
414: for (width = 0;; ++fmt) {
415: width = width * 10 + ch - '0';
416: ch = *fmt;
417: if (ch < '0' || ch > '9')
418: break;
419: }
420: goto reswitch;
421: case 'l':
422: lflag = 1;
423: goto reswitch;
424: case 'b':
425: ul = va_arg(ap, int);
426: p = va_arg(ap, char *);
1.37 ! thorpej 427: for (q = ksnprintn(ul, *p++, NULL, snbuf,
! 428: sizeof(snbuf)); (ch = *q--) != 0;)
1.12 cgd 429: putchar(ch, flags, tp);
430:
431: if (!ul)
432: break;
433:
1.20 christos 434: for (tmp = 0; (n = *p++) != 0;) {
1.12 cgd 435: if (ul & (1 << (n - 1))) {
436: putchar(tmp ? ',' : '<', flags, tp);
437: for (; (n = *p) > ' '; ++p)
438: putchar(n, flags, tp);
439: tmp = 1;
440: } else
1.14 cgd 441: for (; *p > ' '; ++p)
442: continue;
1.12 cgd 443: }
444: if (tmp)
445: putchar('>', flags, tp);
446: break;
447: case 'c':
448: putchar(va_arg(ap, int), flags, tp);
449: break;
1.24 christos 450: case ':':
1.12 cgd 451: p = va_arg(ap, char *);
1.30 christos 452: kprintf(p, flags, tp, va_arg(ap, va_list));
1.12 cgd 453: break;
454: case 's':
1.16 mycroft 455: if ((p = va_arg(ap, char *)) == NULL)
456: p = "(null)";
1.20 christos 457: while ((ch = *p++) != 0)
1.12 cgd 458: putchar(ch, flags, tp);
459: break;
460: case 'd':
461: ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
462: if ((long)ul < 0) {
463: putchar('-', flags, tp);
464: ul = -(long)ul;
465: }
466: base = 10;
467: goto number;
468: case 'o':
469: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
470: base = 8;
471: goto number;
472: case 'u':
473: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
474: base = 10;
475: goto number;
1.17 mycroft 476: case 'p':
477: putchar('0', flags, tp);
478: putchar('x', flags, tp);
1.18 mycroft 479: ul = (u_long)va_arg(ap, void *);
480: base = 16;
481: goto number;
1.12 cgd 482: case 'x':
483: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
484: base = 16;
1.37 ! thorpej 485: number: p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
1.12 cgd 486: if (width && (width -= tmp) > 0)
487: while (width--)
488: putchar(padc, flags, tp);
1.20 christos 489: while ((ch = *p--) != 0)
1.12 cgd 490: putchar(ch, flags, tp);
491: break;
492: default:
493: putchar('%', flags, tp);
494: if (lflag)
495: putchar('l', flags, tp);
496: /* FALLTHROUGH */
497: case '%':
498: putchar(ch, flags, tp);
499: }
500: }
501: }
502:
503: /*
504: * Print a character on console or users terminal. If destination is
505: * the console then the last MSGBUFS characters are saved in msgbuf for
506: * inspection later.
507: */
508: static void
509: putchar(c, flags, tp)
510: register int c;
511: int flags;
512: struct tty *tp;
513: {
1.14 cgd 514: extern int msgbufmapped;
1.12 cgd 515: register struct msgbuf *mbp;
516:
517: if (panicstr)
518: constty = NULL;
519: if ((flags & TOCONS) && tp == NULL && constty) {
520: tp = constty;
521: flags |= TOTTY;
522: }
523: if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 &&
524: (flags & TOCONS) && tp == constty)
525: constty = NULL;
526: if ((flags & TOLOG) &&
527: c != '\0' && c != '\r' && c != 0177 && msgbufmapped) {
528: mbp = msgbufp;
529: if (mbp->msg_magic != MSG_MAGIC) {
530: bzero((caddr_t)mbp, sizeof(*mbp));
531: mbp->msg_magic = MSG_MAGIC;
532: }
533: mbp->msg_bufc[mbp->msg_bufx++] = c;
534: if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE)
535: mbp->msg_bufx = 0;
536: }
537: if ((flags & TOCONS) && constty == NULL && c != '\0')
538: (*v_putc)(c);
539: }
540:
541: /*
542: * Scaled down version of sprintf(3).
543: */
1.20 christos 544: int
1.12 cgd 545: #ifdef __STDC__
1.30 christos 546: sprintf(char *buf, const char *cfmt, ...)
1.12 cgd 547: #else
1.30 christos 548: sprintf(buf, cfmt, va_alist)
1.34 gwr 549: char *buf;
1.36 gwr 550: const char *cfmt;
1.20 christos 551: va_dcl
1.12 cgd 552: #endif
553: {
1.36 gwr 554: register const char *fmt = cfmt;
1.12 cgd 555: register char *p, *bp;
556: register int ch, base;
557: u_long ul;
1.19 cgd 558: int lflag, tmp, width;
1.12 cgd 559: va_list ap;
1.37 ! thorpej 560: char padc, snbuf[KSNPRINTN_BUFSIZE];
1.12 cgd 561:
562: va_start(ap, cfmt);
563: for (bp = buf; ; ) {
1.19 cgd 564: padc = ' ';
565: width = 0;
1.33 cgd 566: while ((ch = *(const u_char *)fmt++) != '%')
1.12 cgd 567: if ((*bp++ = ch) == '\0')
568: return ((bp - buf) - 1);
569:
570: lflag = 0;
1.33 cgd 571: reswitch: switch (ch = *(const u_char *)fmt++) {
1.19 cgd 572: case '0':
573: padc = '0';
574: goto reswitch;
575: case '1': case '2': case '3': case '4':
576: case '5': case '6': case '7': case '8': case '9':
577: for (width = 0;; ++fmt) {
578: width = width * 10 + ch - '0';
579: ch = *fmt;
580: if (ch < '0' || ch > '9')
581: break;
582: }
583: goto reswitch;
1.12 cgd 584: case 'l':
585: lflag = 1;
586: goto reswitch;
1.19 cgd 587: /* case 'b': ... break; XXX */
1.12 cgd 588: case 'c':
589: *bp++ = va_arg(ap, int);
590: break;
1.19 cgd 591: /* case 'r': ... break; XXX */
1.12 cgd 592: case 's':
593: p = va_arg(ap, char *);
1.20 christos 594: while ((*bp++ = *p++) != 0)
1.14 cgd 595: continue;
1.12 cgd 596: --bp;
597: break;
598: case 'd':
599: ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
600: if ((long)ul < 0) {
601: *bp++ = '-';
602: ul = -(long)ul;
603: }
604: base = 10;
605: goto number;
606: break;
607: case 'o':
608: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
609: base = 8;
610: goto number;
611: break;
612: case 'u':
613: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
614: base = 10;
615: goto number;
616: break;
1.19 cgd 617: case 'p':
618: *bp++ = '0';
619: *bp++ = 'x';
620: ul = (u_long)va_arg(ap, void *);
621: base = 16;
622: goto number;
1.12 cgd 623: case 'x':
624: ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
625: base = 16;
1.37 ! thorpej 626: number: p = ksnprintn(ul, base, &tmp, snbuf, sizeof(snbuf));
1.19 cgd 627: if (width && (width -= tmp) > 0)
628: while (width--)
629: *bp++ = padc;
1.20 christos 630: while ((ch = *p--) != 0)
1.12 cgd 631: *bp++ = ch;
632: break;
633: default:
634: *bp++ = '%';
635: if (lflag)
636: *bp++ = 'l';
637: /* FALLTHROUGH */
638: case '%':
639: *bp++ = ch;
640: }
641: }
642: va_end(ap);
643: }
644:
645: /*
646: * Put a number (base <= 16) in a buffer in reverse order; return an
647: * optional length and a pointer to the NULL terminated (preceded?)
648: * buffer.
649: */
650: static char *
1.37 ! thorpej 651: ksnprintn(ul, base, lenp, buf, buflen)
1.12 cgd 652: register u_long ul;
653: register int base, *lenp;
1.37 ! thorpej 654: char *buf;
! 655: size_t buflen;
! 656: {
1.12 cgd 657: register char *p;
658:
659: p = buf;
1.37 ! thorpej 660: *p = '\0'; /* ensure NULL `termination' */
! 661:
! 662: /*
! 663: * Don't even bother of the buffer's not big enough. No
! 664: * value at all is better than a wrong value, and we
! 665: * have a lot of control over the buffer that's passed
! 666: * to this function, since it's not exported.
! 667: */
! 668: if (buflen < KSNPRINTN_BUFSIZE)
! 669: return (p);
! 670:
1.12 cgd 671: do {
672: *++p = "0123456789abcdef"[ul % base];
673: } while (ul /= base);
674: if (lenp)
675: *lenp = p - buf;
676: return (p);
1.37 ! thorpej 677: }
! 678:
! 679: /*
! 680: * Print a bitmask into the provided buffer, and return a pointer
! 681: * to that buffer.
! 682: */
! 683: char *
! 684: bitmask_snprintf(ul, p, buf, buflen)
! 685: u_long ul;
! 686: const char *p;
! 687: char *buf;
! 688: size_t buflen;
! 689: {
! 690: char *bp, *q;
! 691: size_t left;
! 692: register int n;
! 693: int ch, tmp;
! 694: char snbuf[KSNPRINTN_BUFSIZE];
! 695:
! 696: bp = buf;
! 697: bzero(buf, buflen);
! 698:
! 699: /*
! 700: * Always leave room for the trailing NULL.
! 701: */
! 702: left = buflen - 1;
! 703:
! 704: /*
! 705: * Print the value into the buffer. Abort if there's not
! 706: * enough room.
! 707: */
! 708: if (buflen < KSNPRINTN_BUFSIZE)
! 709: return (buf);
! 710:
! 711: for (q = ksnprintn(ul, *p++, NULL, snbuf, sizeof(snbuf));
! 712: (ch = *q--) != 0;) {
! 713: *bp++ = ch;
! 714: left--;
! 715: }
! 716:
! 717: /*
! 718: * If the value we printed was 0, or if we don't have room for
! 719: * "<x>", we're done.
! 720: */
! 721: if (ul == 0 || left < 3)
! 722: return (buf);
! 723:
! 724: #define PUTBYTE(b, c, l) \
! 725: *(b)++ = (c); \
! 726: if (--(l) == 0) \
! 727: goto out;
! 728:
! 729: for (tmp = 0; (n = *p++) != 0;) {
! 730: if (ul & (1 << (n - 1))) {
! 731: PUTBYTE(bp, tmp ? ',' : '<', left);
! 732: for (; (n = *p) > ' '; ++p) {
! 733: PUTBYTE(bp, n, left);
! 734: }
! 735: tmp = 1;
! 736: } else
! 737: for (; *p > ' '; ++p)
! 738: continue;
! 739: }
! 740: if (tmp)
! 741: *bp = '>';
! 742:
! 743: #undef PUTBYTE
! 744:
! 745: out:
! 746: return (buf);
1.12 cgd 747: }
CVSweb <webmaster@jp.NetBSD.org>