Home | History | Annotate | Line # | Download | only in libsa
subr_prf.c revision 1.29
      1 /*	$NetBSD: subr_prf.c,v 1.29 2020/06/06 15:45:47 thorpej 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 			lflag |= ZEROPAD;
    201 			goto reswitch;
    202 		case '1': case '2': case '3': case '4': case '5':
    203 		case '6': case '7': case '8': case '9':
    204 			for (;;) {
    205 				width *= 10;
    206 				width += ch - '0';
    207 				ch = *fmt;
    208 				if ((unsigned)ch - '0' > 9)
    209 					break;
    210 				++fmt;
    211 			}
    212 #endif
    213 		case 'l':
    214 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
    215 			if (*fmt == 'l') {
    216 				++fmt;
    217 				lflag |= LLONG;
    218 			} else
    219 #endif
    220 				lflag |= LONG;
    221 			goto reswitch;
    222 		case 'j':
    223 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
    224 			if (sizeof(intmax_t) == sizeof(long long))
    225 				lflag |= LLONG;
    226 			else
    227 #endif
    228 			if (sizeof(intmax_t) == sizeof(long))
    229 				lflag |= LONG;
    230 			goto reswitch;
    231 		case 't':
    232 			if (sizeof(PTRDIFF_T) == sizeof(long))
    233 				lflag |= LONG;
    234 			goto reswitch;
    235 		case 'z':
    236 			if (sizeof(ssize_t) == sizeof(long))
    237 				lflag |= LONG;
    238 			goto reswitch;
    239 		case 'c':
    240 			ch = va_arg(ap, int);
    241 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    242 			--width;
    243 #endif
    244 			RADJUSTPAD();
    245 			put(ch & 0xFF);
    246 			LADJUSTPAD();
    247 			break;
    248 		case 's':
    249 			p = va_arg(ap, char *);
    250 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    251 			for (q = p; *q != '\0'; ++q)
    252 				continue;
    253 			width -= q - p;
    254 #endif
    255 			RADJUSTPAD();
    256 			while ((ch = (unsigned char)*p++))
    257 				put(ch);
    258 			LADJUSTPAD();
    259 			break;
    260 		case 'd':
    261 			ul =
    262 #ifdef LIBSA_PRINTF_LONGLONG_SUPPORT
    263 			(lflag & LLONG) ? va_arg(ap, longlong_t) :
    264 #endif
    265 			(lflag & LONG) ? va_arg(ap, long) : va_arg(ap, int);
    266 			if ((INTMAX_T)ul < 0) {
    267 				ul = -(INTMAX_T)ul;
    268 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    269 				lflag |= NEGATIVE;
    270 #else
    271 				put('-');
    272 #endif
    273 			}
    274 			KPRINTN(10);
    275 			break;
    276 		case 'o':
    277 			KPRINT(8);
    278 			break;
    279 		case 'u':
    280 			KPRINT(10);
    281 			break;
    282 		case 'p':
    283 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    284 			lflag |= (LONG|ALT);
    285 #else
    286 			put('0');
    287 			put('x');
    288 #endif
    289 			/* FALLTHROUGH */
    290 		case 'x':
    291 			KPRINT(16);
    292 			break;
    293 		default:
    294 			if (ch == '\0')
    295 				return;
    296 			put(ch);
    297 			break;
    298 		}
    299 	}
    300 }
    301 
    302 static void
    303 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    304 kprintn(void (*put)(int), UINTMAX_T ul, int base, int lflag, int width)
    305 #else
    306 kprintn(void (*put)(int), UINTMAX_T ul, int base)
    307 #endif
    308 {
    309 					/* hold a INTMAX_T in base 8 */
    310 	char *p, buf[(sizeof(INTMAX_T) * NBBY / 3) + 1 + 2 /* ALT + SIGN */];
    311 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    312 	char *q;
    313 #endif
    314 
    315 	p = buf;
    316 	do {
    317 		*p++ = hexdigits[ul % base];
    318 	} while (ul /= base);
    319 #ifdef LIBSA_PRINTF_WIDTH_SUPPORT
    320 	q = p;
    321 	if (lflag & ALT && *(p - 1) != '0') {
    322 		if (base == 8) {
    323 			*p++ = '0';
    324 		} else if (base == 16) {
    325 			*p++ = 'x';
    326 			*p++ = '0';
    327 		}
    328 	}
    329 	if (lflag & NEGATIVE)
    330 		*p++ = '-';
    331 	else if (lflag & SIGN)
    332 		*p++ = '+';
    333 	else if (lflag & SPACE)
    334 		*p++ = ' ';
    335 	width -= p - buf;
    336 	if (lflag & ZEROPAD) {
    337 		while (p > q)
    338 			put(*--p);
    339 	}
    340 #endif
    341 	RADJUSTPAD();
    342 	RADJUSTZEROPAD();
    343 	do {
    344 		put(*--p);
    345 	} while (p > buf);
    346 	LADJUSTPAD();
    347 }
    348