xref: /minix/sys/lib/libsa/subr_prf.c (revision 4684ddb6)
1 /*	$NetBSD: subr_prf.c,v 1.21 2011/07/17 20:54:52 joerg 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 #if defined(__minix)
68 /* vsnprintf: add support for returning the amount of characters that would have been
69  * written if the buffer was large enough */
70 static int  scount;
71 #endif /* defined(__minix) */
72 
73 const char hexdigits[16] = "0123456789abcdef";
74 
75 #define LONG		0x01
76 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
77 #define LLONG		0x02
78 #endif
79 
80 #if defined(__minix)
81 #define HEXCAP		0x100
82 #endif /* defined(__minix) */
83 
84 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
85 #define ALT		0x04
86 #define SPACE		0x08
87 #define LADJUST		0x10
88 #define SIGN		0x20
89 #define ZEROPAD		0x40
90 #define NEGATIVE	0x80
91 #define KPRINTN(base)	kprintn(put, ul, base, lflag, width)
92 #define RZERO()							\
93 do {								\
94 	if ((lflag & (ZEROPAD|LADJUST)) == ZEROPAD) {		\
95 		while (width-- > 0)				\
96 			put('0');				\
97 	}							\
98 } while (/*CONSTCOND*/0)
99 #define RPAD()							\
100 do {								\
101 	if (lflag & LADJUST) {					\
102 		while (width-- > 0)				\
103 			put(' ');				\
104 	}							\
105 } while (/*CONSTCOND*/0)
106 #define LPAD()							\
107 do {								\
108 	if ((lflag & (ZEROPAD|LADJUST)) == 0) {			\
109 		while (width-- > 0)				\
110 			put(' ');				\
111 	}							\
112 } while (/*CONSTCOND*/0)
113 #else	/* LIBSA_PRINTF_WIDTH_SUPPORT */
114 #define KPRINTN(base)	kprintn(put, ul, base)
115 #define RZERO()		/**/
116 #define RPAD()		/**/
117 #define LPAD()		/**/
118 #endif	/* LIBSA_PRINTF_WIDTH_SUPPORT */
119 
120 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
121 #define KPRINT(base)						\
122 do {								\
123 	ul = (lflag & LLONG)					\
124 	    ? va_arg(ap, u_longlong_t)				\
125 	    : (lflag & LONG)					\
126 		? va_arg(ap, u_long)				\
127 		: va_arg(ap, u_int);				\
128 	KPRINTN(base);						\
129 } while (/*CONSTCOND*/0)
130 #else	/* LIBSA_PRINTF_LONGLONG_SUPPORT */
131 #define KPRINT(base)						\
132 do {								\
133 	ul = (lflag & LONG)					\
134 	    ? va_arg(ap, u_long) : va_arg(ap, u_int);		\
135 	KPRINTN(base);						\
136 } while (/*CONSTCOND*/0)
137 #endif	/* LIBSA_PRINTF_LONGLONG_SUPPORT */
138 
139 static void
140 sputchar(int c)
141 {
142 #if defined(__minix)
143 	scount++; /* increase scount regardless */
144 	if (!sbuf) return; /* hanlde NULL sbuf  */
145 #endif /* defined(__minix) */
146 	if (sbuf < ebuf)
147 		*sbuf++ = c;
148 }
149 
150 void
151 vprintf(const char *fmt, va_list ap)
152 {
153 
154 	kdoprnt(putchar, fmt, ap);
155 #if defined(__minix) && defined(LIBSA_PRINTF_WIDTH_SUPPORT)
156 	/* BJG: our libminc kputc() relies on a 0 to flush the diag buffer. */
157 	putchar(0);
158 #endif /* defined(__minix) && defined(LIBSA_PRINTF_WIDTH_SUPPORT) */
159 }
160 
161 int
162 vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
163 {
164 
165 	sbuf = buf;
166 	ebuf = buf + size - 1;
167 #if defined(__minix)
168 	scount = 0; /* use scount to keep track of written items */
169 #endif /* defined(__minix) */
170 
171 	kdoprnt(sputchar, fmt, ap);
172 
173 #if defined(__minix)
174 	if (sbuf){ /* handle case where sbuf == NULL */
175 		*sbuf = '\0';
176 	}
177 	return scount;
178 #else /* __minix is not defined */
179 	*sbuf = '\0';
180 	return sbuf - buf;
181 #endif  /* defined(__minix) */
182 }
183 
184 static void
185 kdoprnt(void (*put)(int), const char *fmt, va_list ap)
186 {
187 	char *p;
188 	int ch;
189 	UINTMAX_T ul;
190 	int lflag;
191 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
192 	int width;
193 	char *q;
194 #endif
195 
196 	for (;;) {
197 		while ((ch = *fmt++) != '%') {
198 			if (ch == '\0')
199 				return;
200 			put(ch);
201 		}
202 		lflag = 0;
203 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
204 		width = 0;
205 #endif
206 reswitch:
207 		switch (ch = *fmt++) {
208 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
209 #if defined(__minix)
210 		/* LSC: FIXME: this is a simple hack which ignores the thing for now. */
211 		case '.':
212 			/* eat up digits */
213 			while( ((('1' >= *fmt) && ( *fmt <= '9'))
214 				 || (*fmt == '*')) )
215 				 fmt++;
216 			fmt++;
217 			goto reswitch;
218 #endif /* defined(__minix) */
219 		case '#':
220 			lflag |= ALT;
221 			goto reswitch;
222 		case ' ':
223 			lflag |= SPACE;
224 			goto reswitch;
225 		case '-':
226 			lflag |= LADJUST;
227 			goto reswitch;
228 		case '+':
229 			lflag |= SIGN;
230 			goto reswitch;
231 		case '0':
232 			lflag |= ZEROPAD;
233 			goto reswitch;
234 		case '1': case '2': case '3': case '4': case '5':
235 		case '6': case '7': case '8': case '9':
236 			for (;;) {
237 				width *= 10;
238 				width += ch - '0';
239 				ch = *fmt;
240 				if ((unsigned)ch - '0' > 9)
241 					break;
242 				++fmt;
243 			}
244 #endif
245 			goto reswitch;
246 		case 'l':
247 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
248 			if (*fmt == 'l') {
249 				++fmt;
250 				lflag |= LLONG;
251 			} else
252 #endif
253 				lflag |= LONG;
254 			goto reswitch;
255 		case 't':
256 			if (sizeof(PTRDIFF_T) == sizeof(long))
257 				lflag |= LONG;
258 			goto reswitch;
259 		case 'z':
260 			if (sizeof(ssize_t) == sizeof(long))
261 				lflag |= LONG;
262 			goto reswitch;
263 		case 'c':
264 			ch = va_arg(ap, int);
265 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
266 			--width;
267 #endif
268 			RPAD();
269 			put(ch & 0xFF);
270 			LPAD();
271 			break;
272 		case 's':
273 			p = va_arg(ap, char *);
274 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
275 			for (q = p; *q != '\0'; ++q)
276 				continue;
277 			width -= q - p;
278 #endif
279 			RPAD();
280 			while ((ch = (unsigned char)*p++))
281 				put(ch);
282 			LPAD();
283 			break;
284 		case 'd':
285 			ul =
286 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
287 			(lflag & LLONG) ? va_arg(ap, longlong_t) :
288 #endif
289 			(lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int);
290 			if ((INTMAX_T)ul < 0) {
291 				ul = -(INTMAX_T)ul;
292 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
293 				lflag |= NEGATIVE;
294 #else
295 				put('-');
296 #endif
297 			}
298 			KPRINTN(10);
299 			break;
300 		case 'o':
301 			KPRINT(8);
302 			break;
303 		case 'u':
304 			KPRINT(10);
305 			break;
306 		case 'p':
307 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
308 			lflag |= (LONG|ALT);
309 #else
310 			put('0');
311 			put('x');
312 #endif
313 			/* FALLTHROUGH */
314 		case 'x':
315 			KPRINT(16);
316 			break;
317 #if defined(__minix)
318 		case 'X':
319 			lflag |= HEXCAP;
320 			KPRINT(16);
321 			break;
322 #endif /* defined(__minix) */
323 		default:
324 			if (ch == '\0')
325 				return;
326 			put(ch);
327 			break;
328 		}
329 	}
330 }
331 
332 static void
333 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
334 kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width)
335 #else
336 kprintn(void (*put)(int), UINTMAX_T ul, int base)
337 #endif
338 {
339 					/* hold a INTMAX_T in base 8 */
340 	char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */];
341 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
342 	char *q;
343 #endif
344 
345 	p = buf;
346 	do {
347 		*p++ = hexdigits[ul % base];
348 #if defined(__minix)
349 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
350 		/* LSC: Quick hack to support capital hex printout. */
351 		if ((lflag & HEXCAP) && (*(p-1) >= 'a') && (*(p-1) <= 'z')) {
352 			*(p-1) -= 32;
353 		}
354 #endif
355 #endif /* defined(__minix) */
356 	} while (ul /= base);
357 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
358 	q = p;
359 	if (lflag & ALT && *(p - 1) != '0') {
360 		if (base == 8) {
361 			*p++ = '0';
362 		} else if (base == 16) {
363 			*p++ = 'x';
364 			*p++ = '0';
365 		}
366 	}
367 	if (lflag & NEGATIVE)
368 		*p++ = '-';
369 	else if (lflag & SIGN)
370 		*p++ = '+';
371 	else if (lflag & SPACE)
372 		*p++ = ' ';
373 	width -= p - buf;
374 	if ((lflag & LADJUST) == 0) {
375 		while (p > q)
376 			put(*--p);
377 	}
378 #endif
379 	RPAD();
380 	RZERO();
381 	do {
382 		put(*--p);
383 	} while (p > buf);
384 	LPAD();
385 }
386