subr_prf.c revision 1.16.18.1 1 1.16.18.1 yamt /* $NetBSD: subr_prf.c,v 1.16.18.1 2010/03/11 15:04:22 yamt Exp $ */
2 1.1 pk
3 1.1 pk /*-
4 1.1 pk * Copyright (c) 1993
5 1.1 pk * The Regents of the University of California. All rights reserved.
6 1.1 pk *
7 1.1 pk * Redistribution and use in source and binary forms, with or without
8 1.1 pk * modification, are permitted provided that the following conditions
9 1.1 pk * are met:
10 1.1 pk * 1. Redistributions of source code must retain the above copyright
11 1.1 pk * notice, this list of conditions and the following disclaimer.
12 1.1 pk * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 pk * notice, this list of conditions and the following disclaimer in the
14 1.1 pk * documentation and/or other materials provided with the distribution.
15 1.10 agc * 3. Neither the name of the University nor the names of its contributors
16 1.1 pk * may be used to endorse or promote products derived from this software
17 1.1 pk * without specific prior written permission.
18 1.1 pk *
19 1.1 pk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.1 pk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 pk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 pk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.1 pk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 pk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 pk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 pk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 pk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 pk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 pk * SUCH DAMAGE.
30 1.1 pk *
31 1.1 pk * @(#)printf.c 8.1 (Berkeley) 6/11/93
32 1.1 pk */
33 1.1 pk
34 1.1 pk /*
35 1.1 pk * Scaled down version of printf(3).
36 1.1 pk */
37 1.1 pk
38 1.1 pk #include <sys/cdefs.h>
39 1.1 pk #include <sys/types.h>
40 1.14 uwe #include <sys/stdint.h> /* XXX: for intptr_t */
41 1.1 pk #include <machine/stdarg.h>
42 1.1 pk
43 1.1 pk #include "stand.h"
44 1.1 pk
45 1.16.18.1 yamt #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
46 1.16.18.1 yamt #define INTMAX_T longlong_t
47 1.16.18.1 yamt #define UINTMAX_T u_longlong_t
48 1.16.18.1 yamt #else
49 1.16.18.1 yamt #define INTMAX_T long
50 1.16.18.1 yamt #define UINTMAX_T u_long
51 1.16.18.1 yamt #endif
52 1.16.18.1 yamt
53 1.16.18.1 yamt #if 0 /* XXX: abuse intptr_t until the situation with ptrdiff_t is clear */
54 1.16.18.1 yamt #define PTRDIFF_T ptrdiff_t
55 1.16.18.1 yamt #else
56 1.16.18.1 yamt #define PTRDIFF_T intptr_t
57 1.16.18.1 yamt #endif
58 1.16.18.1 yamt
59 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
60 1.16.18.1 yamt static void kprintn(void (*)(int), UINTMAX_T, int, int, int);
61 1.16.18.1 yamt #else
62 1.16.18.1 yamt static void kprintn(void (*)(int), UINTMAX_T, int);
63 1.16.18.1 yamt #endif
64 1.6 bjh21 static void sputchar(int);
65 1.6 bjh21 static void kdoprnt(void (*)(int), const char *, va_list);
66 1.1 pk
67 1.1 pk static char *sbuf, *ebuf;
68 1.1 pk
69 1.12 jmc const char HEXDIGITS[] = "0123456789ABCDEF";
70 1.11 christos const char hexdigits[] = "0123456789abcdef";
71 1.11 christos
72 1.16.18.1 yamt #define LONG 0x01
73 1.16.18.1 yamt #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
74 1.16.18.1 yamt #define LLONG 0x02
75 1.16.18.1 yamt #endif
76 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
77 1.16.18.1 yamt #define ALT 0x04
78 1.16.18.1 yamt #define SPACE 0x08
79 1.16.18.1 yamt #define LADJUST 0x10
80 1.16.18.1 yamt #define SIGN 0x20
81 1.16.18.1 yamt #define ZEROPAD 0x40
82 1.16.18.1 yamt #define NEGATIVE 0x80
83 1.16.18.1 yamt #define KPRINTN(base) kprintn(put, ul, base, lflag, width)
84 1.16.18.1 yamt #define RZERO() \
85 1.16.18.1 yamt do { \
86 1.16.18.1 yamt if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) { \
87 1.16.18.1 yamt while (width-- > 0) \
88 1.16.18.1 yamt put('0'); \
89 1.16.18.1 yamt } \
90 1.16.18.1 yamt } while (/*CONSTCOND*/0)
91 1.16.18.1 yamt #define RPAD() \
92 1.16.18.1 yamt do { \
93 1.16.18.1 yamt if (lflag & LADJUST) { \
94 1.16.18.1 yamt while (width-- > 0) \
95 1.16.18.1 yamt put(' '); \
96 1.16.18.1 yamt } \
97 1.16.18.1 yamt } while (/*CONSTCOND*/0)
98 1.16.18.1 yamt #define LPAD() \
99 1.16.18.1 yamt do { \
100 1.16.18.1 yamt if ((lflag & (ZEROPAD|LADJUST)) == 0) { \
101 1.16.18.1 yamt while (width-- > 0) \
102 1.16.18.1 yamt put(' '); \
103 1.16.18.1 yamt } \
104 1.16.18.1 yamt } while (/*CONSTCOND*/0)
105 1.16.18.1 yamt #else /* LIBSA_PRINTF_WIDTH_SUPPORT */
106 1.16.18.1 yamt #define KPRINTN(base) kprintn(put, ul, base)
107 1.16.18.1 yamt #define RZERO() /**/
108 1.16.18.1 yamt #define RPAD() /**/
109 1.16.18.1 yamt #define LPAD() /**/
110 1.16.18.1 yamt #endif /* LIBSA_PRINTF_WIDTH_SUPPORT */
111 1.16.18.1 yamt
112 1.16.18.1 yamt #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
113 1.16.18.1 yamt #define KPRINT(base) \
114 1.16.18.1 yamt do { \
115 1.16.18.1 yamt ul = (lflag & LLONG) \
116 1.16.18.1 yamt ? va_arg(ap, u_longlong_t) \
117 1.16.18.1 yamt : (lflag & LONG) \
118 1.16.18.1 yamt ? va_arg(ap, u_long) \
119 1.16.18.1 yamt : va_arg(ap, u_int); \
120 1.16.18.1 yamt KPRINTN(base); \
121 1.16.18.1 yamt } while (/*CONSTCOND*/0)
122 1.16.18.1 yamt #else /* LIBSA_PRINTF_LONGLONG_SUPPORT */
123 1.16.18.1 yamt #define KPRINT(base) \
124 1.16.18.1 yamt do { \
125 1.16.18.1 yamt ul = (lflag & LONG) \
126 1.16.18.1 yamt ? va_arg(ap, u_long) : va_arg(ap, u_int); \
127 1.16.18.1 yamt KPRINTN(base); \
128 1.16.18.1 yamt } while (/*CONSTCOND*/0)
129 1.16.18.1 yamt #endif /* LIBSA_PRINTF_LONGLONG_SUPPORT */
130 1.16.18.1 yamt
131 1.1 pk static void
132 1.6 bjh21 sputchar(int c)
133 1.1 pk {
134 1.6 bjh21
135 1.1 pk if (sbuf < ebuf)
136 1.1 pk *sbuf++ = c;
137 1.1 pk }
138 1.1 pk
139 1.1 pk void
140 1.1 pk vprintf(const char *fmt, va_list ap)
141 1.1 pk {
142 1.1 pk
143 1.1 pk kdoprnt(putchar, fmt, ap);
144 1.1 pk }
145 1.1 pk
146 1.1 pk int
147 1.1 pk vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
148 1.1 pk {
149 1.1 pk
150 1.1 pk sbuf = buf;
151 1.1 pk ebuf = buf + size - 1;
152 1.1 pk kdoprnt(sputchar, fmt, ap);
153 1.1 pk *sbuf = '\0';
154 1.16 isaki return sbuf - buf;
155 1.1 pk }
156 1.1 pk
157 1.5 thorpej static void
158 1.6 bjh21 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
159 1.1 pk {
160 1.3 augustss char *p;
161 1.9 tron int ch;
162 1.16.18.1 yamt UINTMAX_T ul;
163 1.9 tron int lflag;
164 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
165 1.16.18.1 yamt int width;
166 1.16.18.1 yamt char *q;
167 1.16.18.1 yamt #endif
168 1.1 pk
169 1.1 pk for (;;) {
170 1.1 pk while ((ch = *fmt++) != '%') {
171 1.1 pk if (ch == '\0')
172 1.1 pk return;
173 1.1 pk put(ch);
174 1.1 pk }
175 1.1 pk lflag = 0;
176 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
177 1.16.18.1 yamt width = 0;
178 1.16.18.1 yamt #endif
179 1.16 isaki reswitch:
180 1.16 isaki switch (ch = *fmt++) {
181 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
182 1.16.18.1 yamt case '#':
183 1.16.18.1 yamt lflag |= ALT;
184 1.16.18.1 yamt goto reswitch;
185 1.16.18.1 yamt case ' ':
186 1.16.18.1 yamt lflag |= SPACE;
187 1.16.18.1 yamt goto reswitch;
188 1.16.18.1 yamt case '-':
189 1.16.18.1 yamt lflag |= LADJUST;
190 1.16.18.1 yamt goto reswitch;
191 1.16.18.1 yamt case '+':
192 1.16.18.1 yamt lflag |= SIGN;
193 1.16.18.1 yamt goto reswitch;
194 1.16.18.1 yamt case '0':
195 1.16.18.1 yamt lflag |= ZEROPAD;
196 1.16.18.1 yamt goto reswitch;
197 1.16.18.1 yamt case '1': case '2': case '3': case '4': case '5':
198 1.16.18.1 yamt case '6': case '7': case '8': case '9':
199 1.16.18.1 yamt for (;;) {
200 1.16.18.1 yamt width *= 10;
201 1.16.18.1 yamt width += ch - '0';
202 1.16.18.1 yamt ch = *fmt;
203 1.16.18.1 yamt if ((unsigned)ch - '0' > 9)
204 1.16.18.1 yamt break;
205 1.16.18.1 yamt ++fmt;
206 1.16.18.1 yamt }
207 1.16.18.1 yamt #endif
208 1.16.18.1 yamt goto reswitch;
209 1.1 pk case 'l':
210 1.16.18.1 yamt #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
211 1.16.18.1 yamt if (*fmt == 'l') {
212 1.16.18.1 yamt ++fmt;
213 1.16.18.1 yamt lflag |= LLONG;
214 1.16.18.1 yamt } else
215 1.16.18.1 yamt #endif
216 1.16.18.1 yamt lflag |= LONG;
217 1.1 pk goto reswitch;
218 1.14 uwe case 't':
219 1.16.18.1 yamt if (sizeof(PTRDIFF_T) == sizeof(long))
220 1.16.18.1 yamt lflag |= LONG;
221 1.14 uwe goto reswitch;
222 1.14 uwe case 'z':
223 1.16.18.1 yamt if (sizeof(ssize_t) == sizeof(long))
224 1.16.18.1 yamt lflag |= LONG;
225 1.14 uwe goto reswitch;
226 1.1 pk case 'c':
227 1.1 pk ch = va_arg(ap, int);
228 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
229 1.16.18.1 yamt --width;
230 1.16.18.1 yamt #endif
231 1.16.18.1 yamt RPAD();
232 1.16.18.1 yamt put(ch & 0xFF);
233 1.16.18.1 yamt LPAD();
234 1.1 pk break;
235 1.1 pk case 's':
236 1.1 pk p = va_arg(ap, char *);
237 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
238 1.16.18.1 yamt for (q = p; *q; ++q);
239 1.16.18.1 yamt width -= q - p;
240 1.16.18.1 yamt #endif
241 1.16.18.1 yamt RPAD();
242 1.16.18.1 yamt while ((ch = (unsigned char)*p++))
243 1.1 pk put(ch);
244 1.16.18.1 yamt LPAD();
245 1.1 pk break;
246 1.1 pk case 'd':
247 1.16.18.1 yamt ul =
248 1.16.18.1 yamt #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
249 1.16.18.1 yamt (lflag & LLONG) ? va_arg(ap, longlong_t) :
250 1.16.18.1 yamt #endif
251 1.16.18.1 yamt (lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int);
252 1.16.18.1 yamt if ((INTMAX_T)ul < 0) {
253 1.16.18.1 yamt ul = -(INTMAX_T)ul;
254 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
255 1.16.18.1 yamt lflag |= NEGATIVE;
256 1.16.18.1 yamt #else
257 1.1 pk put('-');
258 1.16.18.1 yamt #endif
259 1.1 pk }
260 1.16.18.1 yamt KPRINTN(10);
261 1.1 pk break;
262 1.1 pk case 'o':
263 1.16.18.1 yamt KPRINT(8);
264 1.1 pk break;
265 1.1 pk case 'u':
266 1.16.18.1 yamt KPRINT(10);
267 1.1 pk break;
268 1.1 pk case 'p':
269 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
270 1.16.18.1 yamt lflag |= (LONG|ALT);
271 1.16.18.1 yamt #else
272 1.1 pk put('0');
273 1.1 pk put('x');
274 1.16.18.1 yamt #endif
275 1.15 uwe /* FALLTHROUGH */
276 1.1 pk case 'x':
277 1.16.18.1 yamt KPRINT(16);
278 1.1 pk break;
279 1.1 pk default:
280 1.7 bjh21 if (ch == '\0')
281 1.7 bjh21 return;
282 1.1 pk put(ch);
283 1.16 isaki break;
284 1.1 pk }
285 1.1 pk }
286 1.1 pk }
287 1.1 pk
288 1.1 pk static void
289 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
290 1.16.18.1 yamt kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width)
291 1.16.18.1 yamt #else
292 1.16.18.1 yamt kprintn(void (*put)(int), UINTMAX_T ul, int base)
293 1.16.18.1 yamt #endif
294 1.1 pk {
295 1.16.18.1 yamt /* hold a INTMAX_T in base 8 */
296 1.16.18.1 yamt char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */];
297 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
298 1.16.18.1 yamt char *q;
299 1.16.18.1 yamt #endif
300 1.1 pk
301 1.1 pk p = buf;
302 1.1 pk do {
303 1.11 christos *p++ = hexdigits[ul % base];
304 1.1 pk } while (ul /= base);
305 1.16.18.1 yamt #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
306 1.16.18.1 yamt q = p;
307 1.16.18.1 yamt if (lflag & ALT && *(p - 1) != '0') {
308 1.16.18.1 yamt if (base == 8) {
309 1.16.18.1 yamt *p++ = '0';
310 1.16.18.1 yamt } else if (base == 16) {
311 1.16.18.1 yamt *p++ = 'x';
312 1.16.18.1 yamt *p++ = '0';
313 1.16.18.1 yamt }
314 1.16.18.1 yamt }
315 1.16.18.1 yamt if (lflag & NEGATIVE)
316 1.16.18.1 yamt *p++ = '-';
317 1.16.18.1 yamt else if (lflag & SIGN)
318 1.16.18.1 yamt *p++ = '+';
319 1.16.18.1 yamt else if (lflag & SPACE)
320 1.16.18.1 yamt *p++ = ' ';
321 1.16.18.1 yamt width -= p - buf;
322 1.16.18.1 yamt if ((lflag & LADJUST) == 0) {
323 1.16.18.1 yamt while (p > q)
324 1.16.18.1 yamt put(*--p);
325 1.16.18.1 yamt }
326 1.16.18.1 yamt #endif
327 1.16.18.1 yamt RPAD();
328 1.16.18.1 yamt RZERO();
329 1.1 pk do {
330 1.1 pk put(*--p);
331 1.1 pk } while (p > buf);
332 1.16.18.1 yamt LPAD();
333 1.1 pk }
334