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