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