^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* -*- linux-c -*- ------------------------------------------------------- *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1991, 1992 Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2007 rPath, Inc. - All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * ----------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Oh, it's a waste of space, but oh-so-yummy for debugging.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int skip_atoi(const char **s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) while (isdigit(**s))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) i = i * 10 + *((*s)++) - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * put_dec_full4 handles numbers in the range 0 <= r < 10000.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * The multiplier 0xccd is round(2^15/10), and the approximation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) void put_dec_full4(char *end, unsigned int r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) for (i = 0; i < 3; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned int q = (r * 0xccd) >> 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *--end = '0' + (r - q * 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) r = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) *--end = '0' + r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* put_dec is copied from lib/vsprintf.c with small modifications */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Call put_dec_full4 on x % 10000, return x / 10000.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * The approximation x/10000 == (x * 0x346DC5D7) >> 43
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * holds for all x < 1,128,869,999. The largest value this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * helper will ever be asked to convert is 1,125,520,955.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * (second call in the put_dec code, assuming n is all-ones).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned int put_dec_helper4(char *end, unsigned int x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned int q = (x * 0x346DC5D7ULL) >> 43;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) put_dec_full4(end, x - q * 10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Based on code by Douglas W. Jones found at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * (with permission from the author).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Performs no 64-bit division and hence should be fast on 32-bit machines.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) char *put_dec(char *end, unsigned long long n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned int d3, d2, d1, q, h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) char *p = end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) h = (n >> 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) d2 = (h ) & 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) d3 = (h >> 16); /* implicit "& 0xffff" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) q = put_dec_helper4(p, q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) p -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) q += 7671 * d3 + 9496 * d2 + 6 * d1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) q = put_dec_helper4(p, q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) p -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) q += 4749 * d3 + 42 * d2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) q = put_dec_helper4(p, q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) p -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) q += 281 * d3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) q = put_dec_helper4(p, q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) p -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) put_dec_full4(p, q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) p -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* strip off the extra 0's we printed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) while (p < end && *p == '0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ++p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) char *number(char *end, unsigned long long num, int base, char locase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * locase = 0 or 0x20. ORing digits or letters with 'locase'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * produces same digits or (maybe lowercased) letters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) switch (base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case 10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (num != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) end = put_dec(end, num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) for (; num != 0; num >>= 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) *--end = '0' + (num & 07);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) for (; num != 0; num >>= 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) *--end = digits[num & 0xf] | locase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unreachable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define ZEROPAD 1 /* pad with zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define SIGN 2 /* unsigned/signed long */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define PLUS 4 /* show plus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define SPACE 8 /* space if plus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define LEFT 16 /* left justified */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define SMALL 32 /* Must be 32 == 0x20 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define SPECIAL 64 /* 0x */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #define WIDE 128 /* UTF-16 string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int get_flags(const char **fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) switch (**fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case '-':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) flags |= LEFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) case '+':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) flags |= PLUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case ' ':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) flags |= SPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case '#':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) flags |= SPECIAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) case '0':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) flags |= ZEROPAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ++(*fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) } while (1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) int get_int(const char **fmt, va_list *ap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (isdigit(**fmt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return skip_atoi(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (**fmt == '*') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ++(*fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* it's the next argument */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return va_arg(*ap, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) unsigned long long get_number(int sign, int qualifier, va_list *ap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (sign) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) switch (qualifier) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case 'L':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return va_arg(*ap, long long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) case 'l':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return va_arg(*ap, long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return (short)va_arg(*ap, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) case 'H':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return (signed char)va_arg(*ap, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return va_arg(*ap, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) switch (qualifier) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case 'L':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return va_arg(*ap, unsigned long long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) case 'l':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return va_arg(*ap, unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return (unsigned short)va_arg(*ap, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) case 'H':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return (unsigned char)va_arg(*ap, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return va_arg(*ap, unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) char get_sign(long long *num, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (!(flags & SIGN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (*num < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *num = -(*num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return '-';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (flags & PLUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return '+';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (flags & SPACE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return ' ';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) size_t len, clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) for (len = 0; len < maxlen && *s16; len += clen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) u16 c0 = *s16++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /* First, get the length for a BMP character */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (len + clen > maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * If this is a high surrogate, and we're already at maxlen, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) * can't include the character if it's a valid surrogate pair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) * Avoid accessing one extra word just to check if it's valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * or not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if ((c0 & 0xfc00) == 0xd800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (len + clen == maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if ((*s16 & 0xfc00) == 0xdc00) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) ++s16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ++clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) u32 utf16_to_utf32(const u16 **s16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) u16 c0, c1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) c0 = *(*s16)++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /* not a surrogate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if ((c0 & 0xf800) != 0xd800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return c0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* invalid: low surrogate instead of high */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (c0 & 0x0400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return 0xfffd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) c1 = **s16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /* invalid: missing low surrogate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if ((c1 & 0xfc00) != 0xdc00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 0xfffd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* valid surrogate pair */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) ++(*s16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) #define PUTC(c) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (pos < size) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) buf[pos] = (c); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) ++pos; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) } while (0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /* The maximum space required is to print a 64-bit number in octal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) long long num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) const char *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) size_t len, pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) char sign;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) int flags; /* flags to number() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int field_width; /* width of output field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) int precision; /* min. # of digits for integers; max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) number of chars for from string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) va_list args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * We want to pass our input va_list to helper functions by reference,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * but there's an annoying edge case. If va_list was originally passed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) * to us by value, we could just pass &ap down to the helpers. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) * the case on, for example, X86_32.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) * However, on X86_64 (and possibly others), va_list is actually a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * size-1 array containing a structure. Our function parameter ap has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * which is what will be expected by a function taking a va_list *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) * One standard way to solve this mess is by creating a copy in a local
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * variable of type va_list and then passing a pointer to that local
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * copy instead, which is what we do here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) va_copy(args, ap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) for (pos = 0; *fmt; ++fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (*fmt != '%' || *++fmt == '%') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) PUTC(*fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) /* process flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) flags = get_flags(&fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* get field width */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) field_width = get_int(&fmt, &args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (field_width < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) field_width = -field_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) flags |= LEFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (flags & LEFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) flags &= ~ZEROPAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) /* get the precision */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) precision = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (*fmt == '.') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) ++fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) precision = get_int(&fmt, &args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (precision >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) flags &= ~ZEROPAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) /* get the conversion qualifier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) qualifier = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (*fmt == 'h' || *fmt == 'l') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) qualifier = *fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) ++fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (qualifier == *fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) qualifier -= 'a'-'A';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) ++fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) sign = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) switch (*fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) case 'c':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) flags &= LEFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) s = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (qualifier == 'l') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) ((u16 *)tmp)[0] = (u16)va_arg(args, unsigned int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) ((u16 *)tmp)[1] = L'\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) precision = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) goto wstring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) tmp[0] = (unsigned char)va_arg(args, int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) precision = len = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) goto output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) case 's':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) flags &= LEFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (precision < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) precision = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) s = va_arg(args, void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (!s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) s = precision < 6 ? "" : "(null)";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) else if (qualifier == 'l') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) wstring:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) flags |= WIDE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) precision = len = utf16s_utf8nlen((const u16 *)s, precision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) goto output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) precision = len = strnlen(s, precision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) goto output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) /* integer number formats - set up the flags and "break" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) case 'o':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) base = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) case 'p':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (precision < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) precision = 2 * sizeof(void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) case 'x':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) flags |= SMALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) case 'X':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) base = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) case 'd':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) case 'i':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) flags |= SIGN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) case 'u':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) flags &= ~SPECIAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) base = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * Bail out if the conversion specifier is invalid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * There's probably a typo in the format string and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * remaining specifiers are unlikely to match up with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * the arguments.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (*fmt == 'p') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) num = (unsigned long)va_arg(args, void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) num = get_number(flags & SIGN, qualifier, &args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) sign = get_sign(&num, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (sign)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) --field_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) s = number(tmp_end, num, base, flags & SMALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) len = tmp_end - s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* default precision is 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) if (precision < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) precision = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) /* precision is minimum number of digits to print */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (precision < len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) precision = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (flags & SPECIAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * For octal, a leading 0 is printed only if necessary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) * i.e. if it's not already there because of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) * precision.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (base == 8 && precision == len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) ++precision;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) * For hexadecimal, the leading 0x is skipped if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * output is empty, i.e. both the number and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * precision are 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (base == 16 && precision > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) field_width -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) flags &= ~SPECIAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) * For zero padding, increase the precision to fill the field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * width.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if ((flags & ZEROPAD) && field_width > precision)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) precision = field_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) output:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) /* Calculate the padding necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) field_width -= precision;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) /* Leading padding with ' ' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (!(flags & LEFT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) while (field_width-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) PUTC(' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) /* sign */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (sign)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) PUTC(sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /* 0x/0X for hexadecimal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (flags & SPECIAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) PUTC('0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) PUTC( 'X' | (flags & SMALL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) /* Zero padding and excess precision */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) while (precision-- > len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) PUTC('0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) /* Actual output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (flags & WIDE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) const u16 *ws = (const u16 *)s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) while (len-- > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) u32 c32 = utf16_to_utf32(&ws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) u8 *s8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) size_t clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (c32 < 0x80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) PUTC(c32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* Number of trailing octets */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) len -= clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) s8 = (u8 *)&buf[pos];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) /* Avoid writing partial character */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) PUTC('\0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) pos += clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (pos >= size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /* Set high bits of leading octet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) *s8 = (0xf00 >> 1) >> clen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) /* Write trailing octets in reverse order */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) for (s8 += clen; clen; --clen, c32 >>= 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) *s8-- = 0x80 | (c32 & 0x3f);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /* Set low bits of leading octet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) *s8 |= c32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) while (len-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) PUTC(*s++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) /* Trailing padding with ' ' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) while (field_width-- > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) PUTC(' ');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) va_end(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) buf[min(pos, size-1)] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) return pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) int snprintf(char *buf, size_t size, const char *fmt, ...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) va_list args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) va_start(args, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) i = vsnprintf(buf, size, fmt, args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) va_end(args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }