Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* -*- linux-c -*- ------------------------------------------------------- *
0003  *
0004  *   Copyright (C) 1991, 1992 Linus Torvalds
0005  *   Copyright 2007 rPath, Inc. - All Rights Reserved
0006  *
0007  * ----------------------------------------------------------------------- */
0008 
0009 /*
0010  * Oh, it's a waste of space, but oh-so-yummy for debugging.
0011  */
0012 
0013 #include <linux/stdarg.h>
0014 
0015 #include <linux/compiler.h>
0016 #include <linux/ctype.h>
0017 #include <linux/kernel.h>
0018 #include <linux/limits.h>
0019 #include <linux/string.h>
0020 #include <linux/types.h>
0021 
0022 static
0023 int skip_atoi(const char **s)
0024 {
0025     int i = 0;
0026 
0027     while (isdigit(**s))
0028         i = i * 10 + *((*s)++) - '0';
0029     return i;
0030 }
0031 
0032 /*
0033  * put_dec_full4 handles numbers in the range 0 <= r < 10000.
0034  * The multiplier 0xccd is round(2^15/10), and the approximation
0035  * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
0036  */
0037 static
0038 void put_dec_full4(char *end, unsigned int r)
0039 {
0040     int i;
0041 
0042     for (i = 0; i < 3; i++) {
0043         unsigned int q = (r * 0xccd) >> 15;
0044         *--end = '0' + (r - q * 10);
0045         r = q;
0046     }
0047     *--end = '0' + r;
0048 }
0049 
0050 /* put_dec is copied from lib/vsprintf.c with small modifications */
0051 
0052 /*
0053  * Call put_dec_full4 on x % 10000, return x / 10000.
0054  * The approximation x/10000 == (x * 0x346DC5D7) >> 43
0055  * holds for all x < 1,128,869,999.  The largest value this
0056  * helper will ever be asked to convert is 1,125,520,955.
0057  * (second call in the put_dec code, assuming n is all-ones).
0058  */
0059 static
0060 unsigned int put_dec_helper4(char *end, unsigned int x)
0061 {
0062     unsigned int q = (x * 0x346DC5D7ULL) >> 43;
0063 
0064     put_dec_full4(end, x - q * 10000);
0065     return q;
0066 }
0067 
0068 /* Based on code by Douglas W. Jones found at
0069  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
0070  * (with permission from the author).
0071  * Performs no 64-bit division and hence should be fast on 32-bit machines.
0072  */
0073 static
0074 char *put_dec(char *end, unsigned long long n)
0075 {
0076     unsigned int d3, d2, d1, q, h;
0077     char *p = end;
0078 
0079     d1  = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
0080     h   = (n >> 32);
0081     d2  = (h      ) & 0xffff;
0082     d3  = (h >> 16); /* implicit "& 0xffff" */
0083 
0084     /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
0085          = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
0086     q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
0087     q = put_dec_helper4(p, q);
0088     p -= 4;
0089 
0090     q += 7671 * d3 + 9496 * d2 + 6 * d1;
0091     q = put_dec_helper4(p, q);
0092     p -= 4;
0093 
0094     q += 4749 * d3 + 42 * d2;
0095     q = put_dec_helper4(p, q);
0096     p -= 4;
0097 
0098     q += 281 * d3;
0099     q = put_dec_helper4(p, q);
0100     p -= 4;
0101 
0102     put_dec_full4(p, q);
0103     p -= 4;
0104 
0105     /* strip off the extra 0's we printed */
0106     while (p < end && *p == '0')
0107         ++p;
0108 
0109     return p;
0110 }
0111 
0112 static
0113 char *number(char *end, unsigned long long num, int base, char locase)
0114 {
0115     /*
0116      * locase = 0 or 0x20. ORing digits or letters with 'locase'
0117      * produces same digits or (maybe lowercased) letters
0118      */
0119 
0120     /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
0121     static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
0122 
0123     switch (base) {
0124     case 10:
0125         if (num != 0)
0126             end = put_dec(end, num);
0127         break;
0128     case 8:
0129         for (; num != 0; num >>= 3)
0130             *--end = '0' + (num & 07);
0131         break;
0132     case 16:
0133         for (; num != 0; num >>= 4)
0134             *--end = digits[num & 0xf] | locase;
0135         break;
0136     default:
0137         unreachable();
0138     }
0139 
0140     return end;
0141 }
0142 
0143 #define ZEROPAD 1       /* pad with zero */
0144 #define SIGN    2       /* unsigned/signed long */
0145 #define PLUS    4       /* show plus */
0146 #define SPACE   8       /* space if plus */
0147 #define LEFT    16      /* left justified */
0148 #define SMALL   32      /* Must be 32 == 0x20 */
0149 #define SPECIAL 64      /* 0x */
0150 #define WIDE    128     /* UTF-16 string */
0151 
0152 static
0153 int get_flags(const char **fmt)
0154 {
0155     int flags = 0;
0156 
0157     do {
0158         switch (**fmt) {
0159         case '-':
0160             flags |= LEFT;
0161             break;
0162         case '+':
0163             flags |= PLUS;
0164             break;
0165         case ' ':
0166             flags |= SPACE;
0167             break;
0168         case '#':
0169             flags |= SPECIAL;
0170             break;
0171         case '0':
0172             flags |= ZEROPAD;
0173             break;
0174         default:
0175             return flags;
0176         }
0177         ++(*fmt);
0178     } while (1);
0179 }
0180 
0181 static
0182 int get_int(const char **fmt, va_list *ap)
0183 {
0184     if (isdigit(**fmt))
0185         return skip_atoi(fmt);
0186     if (**fmt == '*') {
0187         ++(*fmt);
0188         /* it's the next argument */
0189         return va_arg(*ap, int);
0190     }
0191     return 0;
0192 }
0193 
0194 static
0195 unsigned long long get_number(int sign, int qualifier, va_list *ap)
0196 {
0197     if (sign) {
0198         switch (qualifier) {
0199         case 'L':
0200             return va_arg(*ap, long long);
0201         case 'l':
0202             return va_arg(*ap, long);
0203         case 'h':
0204             return (short)va_arg(*ap, int);
0205         case 'H':
0206             return (signed char)va_arg(*ap, int);
0207         default:
0208             return va_arg(*ap, int);
0209         };
0210     } else {
0211         switch (qualifier) {
0212         case 'L':
0213             return va_arg(*ap, unsigned long long);
0214         case 'l':
0215             return va_arg(*ap, unsigned long);
0216         case 'h':
0217             return (unsigned short)va_arg(*ap, int);
0218         case 'H':
0219             return (unsigned char)va_arg(*ap, int);
0220         default:
0221             return va_arg(*ap, unsigned int);
0222         }
0223     }
0224 }
0225 
0226 static
0227 char get_sign(long long *num, int flags)
0228 {
0229     if (!(flags & SIGN))
0230         return 0;
0231     if (*num < 0) {
0232         *num = -(*num);
0233         return '-';
0234     }
0235     if (flags & PLUS)
0236         return '+';
0237     if (flags & SPACE)
0238         return ' ';
0239     return 0;
0240 }
0241 
0242 static
0243 size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
0244 {
0245     size_t len, clen;
0246 
0247     for (len = 0; len < maxlen && *s16; len += clen) {
0248         u16 c0 = *s16++;
0249 
0250         /* First, get the length for a BMP character */
0251         clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
0252         if (len + clen > maxlen)
0253             break;
0254         /*
0255          * If this is a high surrogate, and we're already at maxlen, we
0256          * can't include the character if it's a valid surrogate pair.
0257          * Avoid accessing one extra word just to check if it's valid
0258          * or not.
0259          */
0260         if ((c0 & 0xfc00) == 0xd800) {
0261             if (len + clen == maxlen)
0262                 break;
0263             if ((*s16 & 0xfc00) == 0xdc00) {
0264                 ++s16;
0265                 ++clen;
0266             }
0267         }
0268     }
0269 
0270     return len;
0271 }
0272 
0273 static
0274 u32 utf16_to_utf32(const u16 **s16)
0275 {
0276     u16 c0, c1;
0277 
0278     c0 = *(*s16)++;
0279     /* not a surrogate */
0280     if ((c0 & 0xf800) != 0xd800)
0281         return c0;
0282     /* invalid: low surrogate instead of high */
0283     if (c0 & 0x0400)
0284         return 0xfffd;
0285     c1 = **s16;
0286     /* invalid: missing low surrogate */
0287     if ((c1 & 0xfc00) != 0xdc00)
0288         return 0xfffd;
0289     /* valid surrogate pair */
0290     ++(*s16);
0291     return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
0292 }
0293 
0294 #define PUTC(c) \
0295 do {                \
0296     if (pos < size)     \
0297         buf[pos] = (c); \
0298     ++pos;          \
0299 } while (0);
0300 
0301 int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
0302 {
0303     /* The maximum space required is to print a 64-bit number in octal */
0304     char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
0305     char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
0306     long long num;
0307     int base;
0308     const char *s;
0309     size_t len, pos;
0310     char sign;
0311 
0312     int flags;      /* flags to number() */
0313 
0314     int field_width;    /* width of output field */
0315     int precision;      /* min. # of digits for integers; max
0316                    number of chars for from string */
0317     int qualifier;      /* 'h', 'hh', 'l' or 'll' for integer fields */
0318 
0319     va_list args;
0320 
0321     /*
0322      * We want to pass our input va_list to helper functions by reference,
0323      * but there's an annoying edge case. If va_list was originally passed
0324      * to us by value, we could just pass &ap down to the helpers. This is
0325      * the case on, for example, X86_32.
0326      * However, on X86_64 (and possibly others), va_list is actually a
0327      * size-1 array containing a structure. Our function parameter ap has
0328      * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
0329      * which is what will be expected by a function taking a va_list *
0330      * parameter.
0331      * One standard way to solve this mess is by creating a copy in a local
0332      * variable of type va_list and then passing a pointer to that local
0333      * copy instead, which is what we do here.
0334      */
0335     va_copy(args, ap);
0336 
0337     for (pos = 0; *fmt; ++fmt) {
0338         if (*fmt != '%' || *++fmt == '%') {
0339             PUTC(*fmt);
0340             continue;
0341         }
0342 
0343         /* process flags */
0344         flags = get_flags(&fmt);
0345 
0346         /* get field width */
0347         field_width = get_int(&fmt, &args);
0348         if (field_width < 0) {
0349             field_width = -field_width;
0350             flags |= LEFT;
0351         }
0352 
0353         if (flags & LEFT)
0354             flags &= ~ZEROPAD;
0355 
0356         /* get the precision */
0357         precision = -1;
0358         if (*fmt == '.') {
0359             ++fmt;
0360             precision = get_int(&fmt, &args);
0361             if (precision >= 0)
0362                 flags &= ~ZEROPAD;
0363         }
0364 
0365         /* get the conversion qualifier */
0366         qualifier = -1;
0367         if (*fmt == 'h' || *fmt == 'l') {
0368             qualifier = *fmt;
0369             ++fmt;
0370             if (qualifier == *fmt) {
0371                 qualifier -= 'a'-'A';
0372                 ++fmt;
0373             }
0374         }
0375 
0376         sign = 0;
0377 
0378         switch (*fmt) {
0379         case 'c':
0380             flags &= LEFT;
0381             s = tmp;
0382             if (qualifier == 'l') {
0383                 ((u16 *)tmp)[0] = (u16)va_arg(args, unsigned int);
0384                 ((u16 *)tmp)[1] = L'\0';
0385                 precision = INT_MAX;
0386                 goto wstring;
0387             } else {
0388                 tmp[0] = (unsigned char)va_arg(args, int);
0389                 precision = len = 1;
0390             }
0391             goto output;
0392 
0393         case 's':
0394             flags &= LEFT;
0395             if (precision < 0)
0396                 precision = INT_MAX;
0397             s = va_arg(args, void *);
0398             if (!s)
0399                 s = precision < 6 ? "" : "(null)";
0400             else if (qualifier == 'l') {
0401         wstring:
0402                 flags |= WIDE;
0403                 precision = len = utf16s_utf8nlen((const u16 *)s, precision);
0404                 goto output;
0405             }
0406             precision = len = strnlen(s, precision);
0407             goto output;
0408 
0409             /* integer number formats - set up the flags and "break" */
0410         case 'o':
0411             base = 8;
0412             break;
0413 
0414         case 'p':
0415             if (precision < 0)
0416                 precision = 2 * sizeof(void *);
0417             fallthrough;
0418         case 'x':
0419             flags |= SMALL;
0420             fallthrough;
0421         case 'X':
0422             base = 16;
0423             break;
0424 
0425         case 'd':
0426         case 'i':
0427             flags |= SIGN;
0428             fallthrough;
0429         case 'u':
0430             flags &= ~SPECIAL;
0431             base = 10;
0432             break;
0433 
0434         default:
0435             /*
0436              * Bail out if the conversion specifier is invalid.
0437              * There's probably a typo in the format string and the
0438              * remaining specifiers are unlikely to match up with
0439              * the arguments.
0440              */
0441             goto fail;
0442         }
0443         if (*fmt == 'p') {
0444             num = (unsigned long)va_arg(args, void *);
0445         } else {
0446             num = get_number(flags & SIGN, qualifier, &args);
0447         }
0448 
0449         sign = get_sign(&num, flags);
0450         if (sign)
0451             --field_width;
0452 
0453         s = number(tmp_end, num, base, flags & SMALL);
0454         len = tmp_end - s;
0455         /* default precision is 1 */
0456         if (precision < 0)
0457             precision = 1;
0458         /* precision is minimum number of digits to print */
0459         if (precision < len)
0460             precision = len;
0461         if (flags & SPECIAL) {
0462             /*
0463              * For octal, a leading 0 is printed only if necessary,
0464              * i.e. if it's not already there because of the
0465              * precision.
0466              */
0467             if (base == 8 && precision == len)
0468                 ++precision;
0469             /*
0470              * For hexadecimal, the leading 0x is skipped if the
0471              * output is empty, i.e. both the number and the
0472              * precision are 0.
0473              */
0474             if (base == 16 && precision > 0)
0475                 field_width -= 2;
0476             else
0477                 flags &= ~SPECIAL;
0478         }
0479         /*
0480          * For zero padding, increase the precision to fill the field
0481          * width.
0482          */
0483         if ((flags & ZEROPAD) && field_width > precision)
0484             precision = field_width;
0485 
0486 output:
0487         /* Calculate the padding necessary */
0488         field_width -= precision;
0489         /* Leading padding with ' ' */
0490         if (!(flags & LEFT))
0491             while (field_width-- > 0)
0492                 PUTC(' ');
0493         /* sign */
0494         if (sign)
0495             PUTC(sign);
0496         /* 0x/0X for hexadecimal */
0497         if (flags & SPECIAL) {
0498             PUTC('0');
0499             PUTC( 'X' | (flags & SMALL));
0500         }
0501         /* Zero padding and excess precision */
0502         while (precision-- > len)
0503             PUTC('0');
0504         /* Actual output */
0505         if (flags & WIDE) {
0506             const u16 *ws = (const u16 *)s;
0507 
0508             while (len-- > 0) {
0509                 u32 c32 = utf16_to_utf32(&ws);
0510                 u8 *s8;
0511                 size_t clen;
0512 
0513                 if (c32 < 0x80) {
0514                     PUTC(c32);
0515                     continue;
0516                 }
0517 
0518                 /* Number of trailing octets */
0519                 clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
0520 
0521                 len -= clen;
0522                 s8 = (u8 *)&buf[pos];
0523 
0524                 /* Avoid writing partial character */
0525                 PUTC('\0');
0526                 pos += clen;
0527                 if (pos >= size)
0528                     continue;
0529 
0530                 /* Set high bits of leading octet */
0531                 *s8 = (0xf00 >> 1) >> clen;
0532                 /* Write trailing octets in reverse order */
0533                 for (s8 += clen; clen; --clen, c32 >>= 6)
0534                     *s8-- = 0x80 | (c32 & 0x3f);
0535                 /* Set low bits of leading octet */
0536                 *s8 |= c32;
0537             }
0538         } else {
0539             while (len-- > 0)
0540                 PUTC(*s++);
0541         }
0542         /* Trailing padding with ' ' */
0543         while (field_width-- > 0)
0544             PUTC(' ');
0545     }
0546 fail:
0547     va_end(args);
0548 
0549     if (size)
0550         buf[min(pos, size-1)] = '\0';
0551 
0552     return pos;
0553 }
0554 
0555 int snprintf(char *buf, size_t size, const char *fmt, ...)
0556 {
0557     va_list args;
0558     int i;
0559 
0560     va_start(args, fmt);
0561     i = vsnprintf(buf, size, fmt, args);
0562     va_end(args);
0563     return i;
0564 }