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