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