Home | History | Annotate | Line # | Download | only in libsa
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