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