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