1/*	$NetBSD: subr_prf.c,v 1.157 2015/02/04 07:10:47 msaitoh Exp $	*/
2
3/*-
4 * Copyright (c) 1986, 1988, 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)subr_prf.c	8.4 (Berkeley) 5/4/95
37 */
38
39/*
40 * This is the NetBSD kernel printf code heavily stripped.  Format support
41 * is the same, but the wrappers for calling printf have been reduced
42 * down to:
43 *   + printf
44 *   + snprintf
45 *   + vnsprintf
46 */
47
48#define _BMK_PRINTF_VA
49#include <bmk-core/null.h>
50#include <bmk-core/printf.h>
51#include <bmk-core/string.h>
52
53#define TOBUFONLY	0x01
54#define TOCONS		0x02
55
56#define __UNCONST(x) ((void *)(unsigned long)(x))
57#define KPRINTF_BUFSIZE (sizeof(long long)*8/3 + 2)
58
59/*
60 * local prototypes
61 */
62
63static void	cons_putchar(int, int);
64static int	kprintf(const char *, int, void *, char *, va_list);
65
66/*
67 * globals
68 */
69
70static void
71nullfun(void)
72{
73
74	return;
75}
76
77static void (*v_flush)(void);
78static void (*v_putc)(int);
79
80void
81bmk_printf_init(void (*putc)(int), void (*flush)(void))
82{
83
84	if (putc == NULL)
85		putc = (void *)nullfun;
86	v_putc = putc;
87	if (flush == NULL)
88		flush = nullfun;
89	v_flush = flush;
90}
91
92static const char hexdigits[] = "0123456789abcdef";
93static const char HEXDIGITS[] = "0123456789ABCDEF";
94
95/*
96 * functions
97 */
98
99/* dmesg ring buffer */
100#ifndef BMK_DMESG_SIZE
101#define BMK_DMESG_SIZE (16*1024)
102#endif
103char bmk_dmesg[BMK_DMESG_SIZE];
104static int bmk_dmesgoff;
105
106/*
107 * putchar: print a single character on console or user terminal.
108 *
109 * => if console, then the last MSGBUFS chars are saved in msgbuf
110 *	for inspection later (e.g. dmesg/syslog)
111 * => we must already be in the mutex!
112 */
113static void
114cons_putchar(int c, int flags)
115{
116
117	bmk_dmesg[bmk_dmesgoff] = c;
118	if (++bmk_dmesgoff == sizeof(bmk_dmesg)-1)
119		bmk_dmesgoff = 0;
120	(*v_putc)(c);
121}
122
123static void
124kprintf_lock(void)
125{
126
127	/* XXX */
128}
129
130static void
131kprintf_unlock(void)
132{
133
134	/* XXX */
135}
136
137/*
138 * bmk_printf: print a message to the console
139 */
140void
141bmk_printf(const char *fmt, ...)
142{
143        va_list ap;
144
145        kprintf_lock();
146
147        va_start(ap, fmt);
148        kprintf(fmt, TOCONS, NULL, NULL, ap);
149        va_end(ap);
150
151        kprintf_unlock();
152}
153
154/*
155 * bmk_vprintf: print a message to the console [already have
156 *      va_list]
157 */
158void
159bmk_vprintf(const char *fmt, va_list ap)
160{
161	kprintf_lock();
162
163	kprintf(fmt, TOCONS, NULL, NULL, ap);
164
165	kprintf_unlock();
166}
167
168/*
169 * bmk_snprintf: print a message to a buffer
170 */
171int
172bmk_snprintf(char *bf, unsigned long size, const char *fmt, ...)
173{
174	int retval;
175	va_list ap;
176
177	va_start(ap, fmt);
178	retval = bmk_vsnprintf(bf, size, fmt, ap);
179	va_end(ap);
180
181	return retval;
182}
183
184void bmk_putchar(char c) {
185	cons_putchar(c, 0);
186}
187
188/*
189 * bmk_vsnprintf: print a message to a buffer [already have va_list]
190 */
191int
192bmk_vsnprintf(char *bf, unsigned long size, const char *fmt, va_list ap)
193{
194	int retval;
195	char *p;
196
197	p = bf + size;
198	retval = kprintf(fmt, TOBUFONLY, &p, bf, ap);
199	if (bf && size > 0) {
200		/* nul terminate */
201		if (size <= (unsigned long)retval)
202			bf[size - 1] = '\0';
203		else
204			bf[retval] = '\0';
205	}
206	return retval;
207}
208
209/*
210 * kprintf: scaled down version of printf(3).
211 *
212 * this version based on vfprintf() from libc which was derived from
213 * software contributed to Berkeley by Chris Torek.
214 *
215 * NOTE: The kprintf mutex must be held if we're going TOBUF or TOCONS!
216 */
217
218/*
219 * macros for converting digits to letters and vice versa
220 */
221#define	to_digit(c)	((c) - '0')
222#define is_digit(c)	((unsigned)to_digit(c) <= 9)
223#define	to_char(n)	((n) + '0')
224
225/*
226 * flags used during conversion.
227 */
228#define	ALT		0x001		/* alternate form */
229#define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
230#define	LADJUST		0x004		/* left adjustment */
231#define	LONGDBL		0x008		/* long double; unimplemented */
232#define	LONGINT		0x010		/* long integer */
233#define	QUADINT		0x020		/* quad integer */
234#define	SHORTINT	0x040		/* short integer */
235#define	MAXINT		0x080		/* intmax_t */
236#define	PTRINT		0x100		/* intptr_t */
237#define	SIZEINT		0x200		/* size_t */
238#define	ZEROPAD		0x400		/* zero (as opposed to blank) pad */
239#define FPT		0x800		/* Floating point number */
240
241	/*
242	 * To extend shorts properly, we need both signed and unsigned
243	 * argument extraction methods.
244	 */
245#define	SARG() \
246	(flags&MAXINT ? va_arg(ap, long long) : \
247	    flags&PTRINT ? va_arg(ap, long) : \
248	    flags&SIZEINT ? va_arg(ap, long) : /* XXX */ \
249	    flags&QUADINT ? va_arg(ap, long long) : \
250	    flags&LONGINT ? va_arg(ap, long) : \
251	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
252	    (long)va_arg(ap, int))
253#define	UARG() \
254	(flags&MAXINT ? va_arg(ap, unsigned long long) : \
255	    flags&PTRINT ? va_arg(ap, unsigned long) : \
256	    flags&SIZEINT ? va_arg(ap, unsigned long) : \
257	    flags&QUADINT ? va_arg(ap, unsigned long long) : \
258	    flags&LONGINT ? va_arg(ap, unsigned long) : \
259	    flags&SHORTINT ? (unsigned long)(unsigned long)va_arg(ap, int) : \
260	    (unsigned long)va_arg(ap, unsigned int))
261
262#define KPRINTF_PUTCHAR(C) {						\
263	if (oflags == TOBUFONLY) {					\
264		if (sbuf && ((vp == NULL) || (sbuf < tailp))) 		\
265			*sbuf++ = (C);					\
266	} else {							\
267		cons_putchar((C), oflags);				\
268	}								\
269}
270
271/*
272 * Guts of kernel printf.  Note, we already expect to be in a mutex!
273 */
274static int
275kprintf(const char *fmt0, int oflags, void *vp, char *sbuf, va_list ap)
276{
277	int ret = 0;		/* return value accumulator */
278	const char *fmt;	/* format string */
279	int ch;			/* character from fmt */
280	int n;			/* handy integer (short term usage) */
281	char *cp;		/* handy char pointer (short term usage) */
282	int flags;		/* flags as above */
283	int width;		/* width from format (%8d), or 0 */
284	int prec;		/* precision from format (%.3d), or -1 */
285	char sign;		/* sign prefix (' ', '+', '-', or \0) */
286
287	unsigned long long _uquad; /* integer arguments %[diouxX] */
288	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
289	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
290	int realsz;		/* field size expanded by dprec */
291	int size;		/* size of converted field or string */
292	const char *xdigs;	/* digits for [xX] conversion */
293	char bf[KPRINTF_BUFSIZE]; /* space for %c, %[diouxX] */
294	char *tailp;		/* tail pointer for snprintf */
295
296	if (oflags == TOBUFONLY && (vp != NULL))
297		tailp = *(char **)vp;
298	else
299		tailp = NULL;
300
301	cp = NULL;	/* XXX: shutup gcc */
302	size = 0;	/* XXX: shutup gcc */
303
304	fmt = fmt0;
305	ret = 0;
306
307	xdigs = NULL;		/* XXX: shut up gcc warning */
308
309	/*
310	 * Scan the format for conversions (`%' character).
311	 */
312	for (;;) {
313		for (; *fmt != '%' && *fmt; fmt++) {
314			ret++;
315			KPRINTF_PUTCHAR(*fmt);
316		}
317		if (*fmt == 0)
318			goto done;
319
320		fmt++;		/* skip over '%' */
321
322		flags = 0;
323		dprec = 0;
324		width = 0;
325		prec = -1;
326		sign = '\0';
327
328rflag:		ch = *fmt++;
329reswitch:	switch (ch) {
330		case ' ':
331			/*
332			 * ``If the space and + flags both appear, the space
333			 * flag will be ignored.''
334			 *	-- ANSI X3J11
335			 */
336			if (!sign)
337				sign = ' ';
338			goto rflag;
339		case '#':
340			flags |= ALT;
341			goto rflag;
342		case '*':
343			/*
344			 * ``A negative field width argument is taken as a
345			 * - flag followed by a positive field width.''
346			 *	-- ANSI X3J11
347			 * They don't exclude field widths read from args.
348			 */
349			if ((width = va_arg(ap, int)) >= 0)
350				goto rflag;
351			width = -width;
352			/* FALLTHROUGH */
353		case '-':
354			flags |= LADJUST;
355			goto rflag;
356		case '+':
357			sign = '+';
358			goto rflag;
359		case '.':
360			if ((ch = *fmt++) == '*') {
361				n = va_arg(ap, int);
362				prec = n < 0 ? -1 : n;
363				goto rflag;
364			}
365			n = 0;
366			while (is_digit(ch)) {
367				n = 10 * n + to_digit(ch);
368				ch = *fmt++;
369			}
370			prec = n < 0 ? -1 : n;
371			goto reswitch;
372		case '0':
373			/*
374			 * ``Note that 0 is taken as a flag, not as the
375			 * beginning of a field width.''
376			 *	-- ANSI X3J11
377			 */
378			flags |= ZEROPAD;
379			goto rflag;
380		case '1': case '2': case '3': case '4':
381		case '5': case '6': case '7': case '8': case '9':
382			n = 0;
383			do {
384				n = 10 * n + to_digit(ch);
385				ch = *fmt++;
386			} while (is_digit(ch));
387			width = n;
388			goto reswitch;
389		case 'h':
390			flags |= SHORTINT;
391			goto rflag;
392		case 'j':
393			flags |= MAXINT;
394			goto rflag;
395		case 'l':
396			if (*fmt == 'l') {
397				fmt++;
398				flags |= QUADINT;
399			} else {
400				flags |= LONGINT;
401			}
402			goto rflag;
403		case 'q':
404			flags |= QUADINT;
405			goto rflag;
406		case 't':
407			flags |= PTRINT;
408			goto rflag;
409		case 'z':
410			flags |= SIZEINT;
411			goto rflag;
412		case 'c':
413			*(cp = bf) = va_arg(ap, int);
414			size = 1;
415			sign = '\0';
416			break;
417		case 'D':
418			flags |= LONGINT;
419			/*FALLTHROUGH*/
420		case 'd':
421		case 'i':
422			_uquad = SARG();
423			if ((long long)_uquad < 0) {
424				_uquad = -_uquad;
425				sign = '-';
426			}
427			base = DEC;
428			goto number;
429		case 'n':
430			if (flags & MAXINT)
431				*va_arg(ap, long long *) = ret;
432			else if (flags & PTRINT)
433				*va_arg(ap, long *) = ret;
434			else if (flags & SIZEINT)
435				*va_arg(ap, long *) = ret;
436			else if (flags & QUADINT)
437				*va_arg(ap, long long *) = ret;
438			else if (flags & LONGINT)
439				*va_arg(ap, long *) = ret;
440			else if (flags & SHORTINT)
441				*va_arg(ap, short *) = ret;
442			else
443				*va_arg(ap, int *) = ret;
444			continue;	/* no output */
445		case 'O':
446			flags |= LONGINT;
447			/*FALLTHROUGH*/
448		case 'o':
449			_uquad = UARG();
450			base = OCT;
451			goto nosign;
452		case 'p':
453			/*
454			 * ``The argument shall be a pointer to void.  The
455			 * value of the pointer is converted to a sequence
456			 * of printable characters, in an implementation-
457			 * defined manner.''
458			 *	-- ANSI X3J11
459			 */
460			/* NOSTRICT */
461			_uquad = (unsigned long)va_arg(ap, void *);
462			base = HEX;
463			xdigs = hexdigits;
464			flags |= HEXPREFIX;
465			ch = 'x';
466			goto nosign;
467		case 's':
468			if ((cp = va_arg(ap, char *)) == NULL)
469				/*XXXUNCONST*/
470				cp = __UNCONST("(null)");
471			if (prec >= 0) {
472				/*
473				 * can't use strlen; can only look for the
474				 * NUL in the first `prec' characters, and
475				 * strlen() will go further.
476				 */
477				char *p = bmk_memchr(cp, 0, prec);
478
479				if (p != NULL) {
480					size = p - cp;
481					if (size > prec)
482						size = prec;
483				} else
484					size = prec;
485			} else
486				size = bmk_strlen(cp);
487			sign = '\0';
488			break;
489		case 'U':
490			flags |= LONGINT;
491			/*FALLTHROUGH*/
492		case 'u':
493			_uquad = UARG();
494			base = DEC;
495			goto nosign;
496		case 'X':
497			xdigs = HEXDIGITS;
498			goto hex;
499		case 'x':
500			xdigs = hexdigits;
501hex:			_uquad = UARG();
502			base = HEX;
503			/* leading 0x/X only if non-zero */
504			if (flags & ALT && _uquad != 0)
505				flags |= HEXPREFIX;
506
507			/* unsigned conversions */
508nosign:			sign = '\0';
509			/*
510			 * ``... diouXx conversions ... if a precision is
511			 * specified, the 0 flag will be ignored.''
512			 *	-- ANSI X3J11
513			 */
514number:			if ((dprec = prec) >= 0)
515				flags &= ~ZEROPAD;
516
517			/*
518			 * ``The result of converting a zero value with an
519			 * explicit precision of zero is no characters.''
520			 *	-- ANSI X3J11
521			 */
522			cp = bf + KPRINTF_BUFSIZE;
523			if (_uquad != 0 || prec != 0) {
524				/*
525				 * Unsigned mod is hard, and unsigned mod
526				 * by a constant is easier than that by
527				 * a variable; hence this switch.
528				 */
529				switch (base) {
530				case OCT:
531					do {
532						*--cp = to_char(_uquad & 7);
533						_uquad >>= 3;
534					} while (_uquad);
535					/* handle octal leading 0 */
536					if (flags & ALT && *cp != '0')
537						*--cp = '0';
538					break;
539
540				case DEC:
541					/* many numbers are 1 digit */
542					while (_uquad >= 10) {
543						*--cp = to_char(_uquad % 10);
544						_uquad /= 10;
545					}
546					*--cp = to_char(_uquad);
547					break;
548
549				case HEX:
550					do {
551						*--cp = xdigs[_uquad & 15];
552						_uquad >>= 4;
553					} while (_uquad);
554					break;
555
556				default:
557					/*XXXUNCONST*/
558					cp = __UNCONST("bug in kprintf: bad base");
559					size = bmk_strlen(cp);
560					goto skipsize;
561				}
562			}
563			size = bf + KPRINTF_BUFSIZE - cp;
564		skipsize:
565			break;
566		default:	/* "%?" prints ?, unless ? is NUL */
567			if (ch == '\0')
568				goto done;
569			/* pretend it was %c with argument ch */
570			cp = bf;
571			*cp = ch;
572			size = 1;
573			sign = '\0';
574			break;
575		}
576
577		/*
578		 * All reasonable formats wind up here.  At this point, `cp'
579		 * points to a string which (if not flags&LADJUST) should be
580		 * padded out to `width' places.  If flags&ZEROPAD, it should
581		 * first be prefixed by any sign or other prefix; otherwise,
582		 * it should be blank padded before the prefix is emitted.
583		 * After any left-hand padding and prefixing, emit zeroes
584		 * required by a decimal [diouxX] precision, then print the
585		 * string proper, then emit zeroes required by any leftover
586		 * floating precision; finally, if LADJUST, pad with blanks.
587		 *
588		 * Compute actual size, so we know how much to pad.
589		 * size excludes decimal prec; realsz includes it.
590		 */
591		realsz = dprec > size ? dprec : size;
592		if (sign)
593			realsz++;
594		else if (flags & HEXPREFIX)
595			realsz+= 2;
596
597		/* adjust ret */
598		ret += width > realsz ? width : realsz;
599
600		/* right-adjusting blank padding */
601		if ((flags & (LADJUST|ZEROPAD)) == 0) {
602			n = width - realsz;
603			while (n-- > 0)
604				KPRINTF_PUTCHAR(' ');
605		}
606
607		/* prefix */
608		if (sign) {
609			KPRINTF_PUTCHAR(sign);
610		} else if (flags & HEXPREFIX) {
611			KPRINTF_PUTCHAR('0');
612			KPRINTF_PUTCHAR(ch);
613		}
614
615		/* right-adjusting zero padding */
616		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) {
617			n = width - realsz;
618			while (n-- > 0)
619				KPRINTF_PUTCHAR('0');
620		}
621
622		/* leading zeroes from decimal precision */
623		n = dprec - size;
624		while (n-- > 0)
625			KPRINTF_PUTCHAR('0');
626
627		/* the string or number proper */
628		for (; size--; cp++)
629			KPRINTF_PUTCHAR(*cp);
630		/* left-adjusting padding (always blank) */
631		if (flags & LADJUST) {
632			n = width - realsz;
633			while (n-- > 0)
634				KPRINTF_PUTCHAR(' ');
635		}
636	}
637
638done:
639	if ((oflags == TOBUFONLY) && (vp != NULL))
640		*(char **)vp = sbuf;
641	(*v_flush)();
642
643	return ret;
644}
645