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