xref: /netbsd-src/sys/lib/libsa/subr_prf.c (revision df0caa2637da0538ecdf6b878c4d08e684b43d8f)
1 /*	$NetBSD: subr_prf.c,v 1.12 2005/05/23 19:05:00 jmc Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)printf.c	8.1 (Berkeley) 6/11/93
32  */
33 
34 /*
35  * Scaled down version of printf(3).
36  */
37 
38 #include <sys/cdefs.h>
39 #include <sys/types.h>
40 #include <machine/stdarg.h>
41 
42 #include "stand.h"
43 
44 static void kprintn(void (*)(int), u_long, int);
45 static void sputchar(int);
46 static void kdoprnt(void (*)(int), const char *, va_list);
47 
48 static char *sbuf, *ebuf;
49 
50 const char HEXDIGITS[] = "0123456789ABCDEF";
51 const char hexdigits[] = "0123456789abcdef";
52 
53 static void
54 sputchar(int c)
55 {
56 
57 	if (sbuf < ebuf)
58 		*sbuf++ = c;
59 }
60 
61 void
62 vprintf(const char *fmt, va_list ap)
63 {
64 
65 	kdoprnt(putchar, fmt, ap);
66 }
67 
68 int
69 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
70 {
71 
72 	sbuf = buf;
73 	ebuf = buf + size - 1;
74 	kdoprnt(sputchar, fmt, ap);
75 	*sbuf = '\0';
76 	return (sbuf - buf);
77 }
78 
79 static void
80 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
81 {
82 	char *p;
83 	int ch;
84 	unsigned long ul;
85 	int lflag;
86 
87 	for (;;) {
88 		while ((ch = *fmt++) != '%') {
89 			if (ch == '\0')
90 				return;
91 			put(ch);
92 		}
93 		lflag = 0;
94 reswitch:	switch (ch = *fmt++) {
95 		case 'l':
96 			lflag = 1;
97 			goto reswitch;
98 		case 'c':
99 			ch = va_arg(ap, int);
100 				put(ch & 0x7f);
101 			break;
102 		case 's':
103 			p = va_arg(ap, char *);
104 			while ((ch = *p++))
105 				put(ch);
106 			break;
107 		case 'd':
108 			ul = lflag ?
109 			    va_arg(ap, long) : va_arg(ap, int);
110 			if ((long)ul < 0) {
111 				put('-');
112 				ul = -(long)ul;
113 			}
114 			kprintn(put, ul, 10);
115 			break;
116 		case 'o':
117 			ul = lflag ?
118 			    va_arg(ap, u_long) : va_arg(ap, u_int);
119 			kprintn(put, ul, 8);
120 			break;
121 		case 'u':
122 			ul = lflag ?
123 			    va_arg(ap, u_long) : va_arg(ap, u_int);
124 			kprintn(put, ul, 10);
125 			break;
126 		case 'p':
127 			put('0');
128 			put('x');
129 			lflag = 1;
130 			/* fall through */
131 		case 'x':
132 			ul = lflag ?
133 			    va_arg(ap, u_long) : va_arg(ap, u_int);
134 			kprintn(put, ul, 16);
135 			break;
136 		default:
137 			put('%');
138 			if (lflag)
139 				put('l');
140 			if (ch == '\0')
141 				return;
142 			put(ch);
143 		}
144 	}
145 }
146 
147 static void
148 kprintn(void (*put)(int), unsigned long ul, int base)
149 {
150 					/* hold a long in base 8 */
151 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
152 
153 	p = buf;
154 	do {
155 		*p++ = hexdigits[ul % base];
156 	} while (ul /= base);
157 	do {
158 		put(*--p);
159 	} while (p > buf);
160 }
161