subr_prf.c revision 1.16.18.1 1 /* $NetBSD: subr_prf.c,v 1.16.18.1 2010/03/11 15:04:22 yamt 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 <sys/stdint.h> /* XXX: for intptr_t */
41 #include <machine/stdarg.h>
42
43 #include "stand.h"
44
45 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
46 #define INTMAX_T longlong_t
47 #define UINTMAX_T u_longlong_t
48 #else
49 #define INTMAX_T long
50 #define UINTMAX_T u_long
51 #endif
52
53 #if 0 /* XXX: abuse intptr_t until the situation with ptrdiff_t is clear */
54 #define PTRDIFF_T ptrdiff_t
55 #else
56 #define PTRDIFF_T intptr_t
57 #endif
58
59 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
60 static void kprintn(void (*)(int), UINTMAX_T, int, int, int);
61 #else
62 static void kprintn(void (*)(int), UINTMAX_T, int);
63 #endif
64 static void sputchar(int);
65 static void kdoprnt(void (*)(int), const char *, va_list);
66
67 static char *sbuf, *ebuf;
68
69 const char HEXDIGITS[] = "0123456789ABCDEF";
70 const char hexdigits[] = "0123456789abcdef";
71
72 #define LONG 0x01
73 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
74 #define LLONG 0x02
75 #endif
76 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
77 #define ALT 0x04
78 #define SPACE 0x08
79 #define LADJUST 0x10
80 #define SIGN 0x20
81 #define ZEROPAD 0x40
82 #define NEGATIVE 0x80
83 #define KPRINTN(base) kprintn(put, ul, base, lflag, width)
84 #define RZERO() \
85 do { \
86 if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) { \
87 while (width-- > 0) \
88 put('0'); \
89 } \
90 } while (/*CONSTCOND*/0)
91 #define RPAD() \
92 do { \
93 if (lflag & LADJUST) { \
94 while (width-- > 0) \
95 put(' '); \
96 } \
97 } while (/*CONSTCOND*/0)
98 #define LPAD() \
99 do { \
100 if ((lflag & (ZEROPAD|LADJUST)) == 0) { \
101 while (width-- > 0) \
102 put(' '); \
103 } \
104 } while (/*CONSTCOND*/0)
105 #else /* LIBSA_PRINTF_WIDTH_SUPPORT */
106 #define KPRINTN(base) kprintn(put, ul, base)
107 #define RZERO() /**/
108 #define RPAD() /**/
109 #define LPAD() /**/
110 #endif /* LIBSA_PRINTF_WIDTH_SUPPORT */
111
112 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
113 #define KPRINT(base) \
114 do { \
115 ul = (lflag & LLONG) \
116 ? va_arg(ap, u_longlong_t) \
117 : (lflag & LONG) \
118 ? va_arg(ap, u_long) \
119 : va_arg(ap, u_int); \
120 KPRINTN(base); \
121 } while (/*CONSTCOND*/0)
122 #else /* LIBSA_PRINTF_LONGLONG_SUPPORT */
123 #define KPRINT(base) \
124 do { \
125 ul = (lflag & LONG) \
126 ? va_arg(ap, u_long) : va_arg(ap, u_int); \
127 KPRINTN(base); \
128 } while (/*CONSTCOND*/0)
129 #endif /* LIBSA_PRINTF_LONGLONG_SUPPORT */
130
131 static void
132 sputchar(int c)
133 {
134
135 if (sbuf < ebuf)
136 *sbuf++ = c;
137 }
138
139 void
140 vprintf(const char *fmt, va_list ap)
141 {
142
143 kdoprnt(putchar, fmt, ap);
144 }
145
146 int
147 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
148 {
149
150 sbuf = buf;
151 ebuf = buf + size - 1;
152 kdoprnt(sputchar, fmt, ap);
153 *sbuf = '\0';
154 return sbuf - buf;
155 }
156
157 static void
158 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
159 {
160 char *p;
161 int ch;
162 UINTMAX_T ul;
163 int lflag;
164 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
165 int width;
166 char *q;
167 #endif
168
169 for (;;) {
170 while ((ch = *fmt++) != '%') {
171 if (ch == '\0')
172 return;
173 put(ch);
174 }
175 lflag = 0;
176 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
177 width = 0;
178 #endif
179 reswitch:
180 switch (ch = *fmt++) {
181 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
182 case '#':
183 lflag |= ALT;
184 goto reswitch;
185 case ' ':
186 lflag |= SPACE;
187 goto reswitch;
188 case '-':
189 lflag |= LADJUST;
190 goto reswitch;
191 case '+':
192 lflag |= SIGN;
193 goto reswitch;
194 case '0':
195 lflag |= ZEROPAD;
196 goto reswitch;
197 case '1': case '2': case '3': case '4': case '5':
198 case '6': case '7': case '8': case '9':
199 for (;;) {
200 width *= 10;
201 width += ch - '0';
202 ch = *fmt;
203 if ((unsigned)ch - '0' > 9)
204 break;
205 ++fmt;
206 }
207 #endif
208 goto reswitch;
209 case 'l':
210 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
211 if (*fmt == 'l') {
212 ++fmt;
213 lflag |= LLONG;
214 } else
215 #endif
216 lflag |= LONG;
217 goto reswitch;
218 case 't':
219 if (sizeof(PTRDIFF_T) == sizeof(long))
220 lflag |= LONG;
221 goto reswitch;
222 case 'z':
223 if (sizeof(ssize_t) == sizeof(long))
224 lflag |= LONG;
225 goto reswitch;
226 case 'c':
227 ch = va_arg(ap, int);
228 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
229 --width;
230 #endif
231 RPAD();
232 put(ch & 0xFF);
233 LPAD();
234 break;
235 case 's':
236 p = va_arg(ap, char *);
237 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
238 for (q = p; *q; ++q);
239 width -= q - p;
240 #endif
241 RPAD();
242 while ((ch = (unsigned char)*p++))
243 put(ch);
244 LPAD();
245 break;
246 case 'd':
247 ul =
248 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
249 (lflag & LLONG) ? va_arg(ap, longlong_t) :
250 #endif
251 (lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int);
252 if ((INTMAX_T)ul < 0) {
253 ul = -(INTMAX_T)ul;
254 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
255 lflag |= NEGATIVE;
256 #else
257 put('-');
258 #endif
259 }
260 KPRINTN(10);
261 break;
262 case 'o':
263 KPRINT(8);
264 break;
265 case 'u':
266 KPRINT(10);
267 break;
268 case 'p':
269 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
270 lflag |= (LONG|ALT);
271 #else
272 put('0');
273 put('x');
274 #endif
275 /* FALLTHROUGH */
276 case 'x':
277 KPRINT(16);
278 break;
279 default:
280 if (ch == '\0')
281 return;
282 put(ch);
283 break;
284 }
285 }
286 }
287
288 static void
289 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
290 kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width)
291 #else
292 kprintn(void (*put)(int), UINTMAX_T ul, int base)
293 #endif
294 {
295 /* hold a INTMAX_T in base 8 */
296 char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */];
297 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
298 char *q;
299 #endif
300
301 p = buf;
302 do {
303 *p++ = hexdigits[ul % base];
304 } while (ul /= base);
305 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
306 q = p;
307 if (lflag & ALT && *(p - 1) != '0') {
308 if (base == 8) {
309 *p++ = '0';
310 } else if (base == 16) {
311 *p++ = 'x';
312 *p++ = '0';
313 }
314 }
315 if (lflag & NEGATIVE)
316 *p++ = '-';
317 else if (lflag & SIGN)
318 *p++ = '+';
319 else if (lflag & SPACE)
320 *p++ = ' ';
321 width -= p - buf;
322 if ((lflag & LADJUST) == 0) {
323 while (p > q)
324 put(*--p);
325 }
326 #endif
327 RPAD();
328 RZERO();
329 do {
330 put(*--p);
331 } while (p > buf);
332 LPAD();
333 }
334