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.  This
0011  * version of printf() does not include 64-bit support.  "Live with
0012  * it."
0013  *
0014  */
0015 
0016 #include "boot.h"
0017 
0018 static int skip_atoi(const char **s)
0019 {
0020     int i = 0;
0021 
0022     while (isdigit(**s))
0023         i = i * 10 + *((*s)++) - '0';
0024     return i;
0025 }
0026 
0027 #define ZEROPAD 1       /* pad with zero */
0028 #define SIGN    2       /* unsigned/signed long */
0029 #define PLUS    4       /* show plus */
0030 #define SPACE   8       /* space if plus */
0031 #define LEFT    16      /* left justified */
0032 #define SMALL   32      /* Must be 32 == 0x20 */
0033 #define SPECIAL 64      /* 0x */
0034 
0035 #define __do_div(n, base) ({ \
0036 int __res; \
0037 __res = ((unsigned long) n) % (unsigned) base; \
0038 n = ((unsigned long) n) / (unsigned) base; \
0039 __res; })
0040 
0041 static char *number(char *str, long num, int base, int size, int precision,
0042             int type)
0043 {
0044     /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
0045     static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
0046 
0047     char tmp[66];
0048     char c, sign, locase;
0049     int i;
0050 
0051     /* locase = 0 or 0x20. ORing digits or letters with 'locase'
0052      * produces same digits or (maybe lowercased) letters */
0053     locase = (type & SMALL);
0054     if (type & LEFT)
0055         type &= ~ZEROPAD;
0056     if (base < 2 || base > 16)
0057         return NULL;
0058     c = (type & ZEROPAD) ? '0' : ' ';
0059     sign = 0;
0060     if (type & SIGN) {
0061         if (num < 0) {
0062             sign = '-';
0063             num = -num;
0064             size--;
0065         } else if (type & PLUS) {
0066             sign = '+';
0067             size--;
0068         } else if (type & SPACE) {
0069             sign = ' ';
0070             size--;
0071         }
0072     }
0073     if (type & SPECIAL) {
0074         if (base == 16)
0075             size -= 2;
0076         else if (base == 8)
0077             size--;
0078     }
0079     i = 0;
0080     if (num == 0)
0081         tmp[i++] = '0';
0082     else
0083         while (num != 0)
0084             tmp[i++] = (digits[__do_div(num, base)] | locase);
0085     if (i > precision)
0086         precision = i;
0087     size -= precision;
0088     if (!(type & (ZEROPAD + LEFT)))
0089         while (size-- > 0)
0090             *str++ = ' ';
0091     if (sign)
0092         *str++ = sign;
0093     if (type & SPECIAL) {
0094         if (base == 8)
0095             *str++ = '0';
0096         else if (base == 16) {
0097             *str++ = '0';
0098             *str++ = ('X' | locase);
0099         }
0100     }
0101     if (!(type & LEFT))
0102         while (size-- > 0)
0103             *str++ = c;
0104     while (i < precision--)
0105         *str++ = '0';
0106     while (i-- > 0)
0107         *str++ = tmp[i];
0108     while (size-- > 0)
0109         *str++ = ' ';
0110     return str;
0111 }
0112 
0113 int vsprintf(char *buf, const char *fmt, va_list args)
0114 {
0115     int len;
0116     unsigned long num;
0117     int i, base;
0118     char *str;
0119     const char *s;
0120 
0121     int flags;      /* flags to number() */
0122 
0123     int field_width;    /* width of output field */
0124     int precision;      /* min. # of digits for integers; max
0125                    number of chars for from string */
0126     int qualifier;      /* 'h', 'l', or 'L' for integer fields */
0127 
0128     for (str = buf; *fmt; ++fmt) {
0129         if (*fmt != '%') {
0130             *str++ = *fmt;
0131             continue;
0132         }
0133 
0134         /* process flags */
0135         flags = 0;
0136           repeat:
0137         ++fmt;      /* this also skips first '%' */
0138         switch (*fmt) {
0139         case '-':
0140             flags |= LEFT;
0141             goto repeat;
0142         case '+':
0143             flags |= PLUS;
0144             goto repeat;
0145         case ' ':
0146             flags |= SPACE;
0147             goto repeat;
0148         case '#':
0149             flags |= SPECIAL;
0150             goto repeat;
0151         case '0':
0152             flags |= ZEROPAD;
0153             goto repeat;
0154         }
0155 
0156         /* get field width */
0157         field_width = -1;
0158         if (isdigit(*fmt))
0159             field_width = skip_atoi(&fmt);
0160         else if (*fmt == '*') {
0161             ++fmt;
0162             /* it's the next argument */
0163             field_width = va_arg(args, int);
0164             if (field_width < 0) {
0165                 field_width = -field_width;
0166                 flags |= LEFT;
0167             }
0168         }
0169 
0170         /* get the precision */
0171         precision = -1;
0172         if (*fmt == '.') {
0173             ++fmt;
0174             if (isdigit(*fmt))
0175                 precision = skip_atoi(&fmt);
0176             else if (*fmt == '*') {
0177                 ++fmt;
0178                 /* it's the next argument */
0179                 precision = va_arg(args, int);
0180             }
0181             if (precision < 0)
0182                 precision = 0;
0183         }
0184 
0185         /* get the conversion qualifier */
0186         qualifier = -1;
0187         if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
0188             qualifier = *fmt;
0189             ++fmt;
0190         }
0191 
0192         /* default base */
0193         base = 10;
0194 
0195         switch (*fmt) {
0196         case 'c':
0197             if (!(flags & LEFT))
0198                 while (--field_width > 0)
0199                     *str++ = ' ';
0200             *str++ = (unsigned char)va_arg(args, int);
0201             while (--field_width > 0)
0202                 *str++ = ' ';
0203             continue;
0204 
0205         case 's':
0206             s = va_arg(args, char *);
0207             len = strnlen(s, precision);
0208 
0209             if (!(flags & LEFT))
0210                 while (len < field_width--)
0211                     *str++ = ' ';
0212             for (i = 0; i < len; ++i)
0213                 *str++ = *s++;
0214             while (len < field_width--)
0215                 *str++ = ' ';
0216             continue;
0217 
0218         case 'p':
0219             if (field_width == -1) {
0220                 field_width = 2 * sizeof(void *);
0221                 flags |= ZEROPAD;
0222             }
0223             str = number(str,
0224                      (unsigned long)va_arg(args, void *), 16,
0225                      field_width, precision, flags);
0226             continue;
0227 
0228         case 'n':
0229             if (qualifier == 'l') {
0230                 long *ip = va_arg(args, long *);
0231                 *ip = (str - buf);
0232             } else {
0233                 int *ip = va_arg(args, int *);
0234                 *ip = (str - buf);
0235             }
0236             continue;
0237 
0238         case '%':
0239             *str++ = '%';
0240             continue;
0241 
0242             /* integer number formats - set up the flags and "break" */
0243         case 'o':
0244             base = 8;
0245             break;
0246 
0247         case 'x':
0248             flags |= SMALL;
0249         case 'X':
0250             base = 16;
0251             break;
0252 
0253         case 'd':
0254         case 'i':
0255             flags |= SIGN;
0256         case 'u':
0257             break;
0258 
0259         default:
0260             *str++ = '%';
0261             if (*fmt)
0262                 *str++ = *fmt;
0263             else
0264                 --fmt;
0265             continue;
0266         }
0267         if (qualifier == 'l')
0268             num = va_arg(args, unsigned long);
0269         else if (qualifier == 'h') {
0270             num = (unsigned short)va_arg(args, int);
0271             if (flags & SIGN)
0272                 num = (short)num;
0273         } else if (flags & SIGN)
0274             num = va_arg(args, int);
0275         else
0276             num = va_arg(args, unsigned int);
0277         str = number(str, num, base, field_width, precision, flags);
0278     }
0279     *str = '\0';
0280     return str - buf;
0281 }
0282 
0283 int sprintf(char *buf, const char *fmt, ...)
0284 {
0285     va_list args;
0286     int i;
0287 
0288     va_start(args, fmt);
0289     i = vsprintf(buf, fmt, args);
0290     va_end(args);
0291     return i;
0292 }
0293 
0294 int printf(const char *fmt, ...)
0295 {
0296     char printf_buf[1024];
0297     va_list args;
0298     int printed;
0299 
0300     va_start(args, fmt);
0301     printed = vsprintf(printf_buf, fmt, args);
0302     va_end(args);
0303 
0304     puts(printf_buf);
0305 
0306     return printed;
0307 }