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