Home | History | Annotate | Line # | Download | only in libsa
subr_prf.c revision 1.17
      1 /*	$NetBSD: subr_prf.c,v 1.17 2010/01/19 15:26:45 tsutsui 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