linux/arch/powerpc/boot/stdio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) Paul Mackerras 1997.
   4 */
   5#include <stdarg.h>
   6#include <stddef.h>
   7#include "string.h"
   8#include "stdio.h"
   9#include "ops.h"
  10
  11size_t strnlen(const char * s, size_t count)
  12{
  13        const char *sc;
  14
  15        for (sc = s; count-- && *sc != '\0'; ++sc)
  16                /* nothing */;
  17        return sc - s;
  18}
  19
  20char *strrchr(const char *s, int c)
  21{
  22        const char *last = NULL;
  23        do {
  24                if (*s == (char)c)
  25                        last = s;
  26        } while (*s++);
  27        return (char *)last;
  28}
  29
  30#ifdef __powerpc64__
  31
  32# define do_div(n, base) ({                                             \
  33        unsigned int __base = (base);                                   \
  34        unsigned int __rem;                                             \
  35        __rem = ((unsigned long long)(n)) % __base;                     \
  36        (n) = ((unsigned long long)(n)) / __base;                       \
  37        __rem;                                                          \
  38})
  39
  40#else
  41
  42extern unsigned int __div64_32(unsigned long long *dividend,
  43                               unsigned int divisor);
  44
  45/* The unnecessary pointer compare is there
  46 * to check for type safety (n must be 64bit)
  47 */
  48# define do_div(n,base) ({                                              \
  49        unsigned int __base = (base);                                   \
  50        unsigned int __rem;                                             \
  51        (void)(((typeof((n)) *)0) == ((unsigned long long *)0));        \
  52        if (((n) >> 32) == 0) {                                         \
  53                __rem = (unsigned int)(n) % __base;                     \
  54                (n) = (unsigned int)(n) / __base;                       \
  55        } else                                                          \
  56                __rem = __div64_32(&(n), __base);                       \
  57        __rem;                                                          \
  58 })
  59
  60#endif /* __powerpc64__ */
  61
  62static int skip_atoi(const char **s)
  63{
  64        int i, c;
  65
  66        for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
  67                i = i*10 + c - '0';
  68        return i;
  69}
  70
  71#define ZEROPAD 1               /* pad with zero */
  72#define SIGN    2               /* unsigned/signed long */
  73#define PLUS    4               /* show plus */
  74#define SPACE   8               /* space if plus */
  75#define LEFT    16              /* left justified */
  76#define SPECIAL 32              /* 0x */
  77#define LARGE   64              /* use 'ABCDEF' instead of 'abcdef' */
  78
  79static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
  80{
  81        char c,sign,tmp[66];
  82        const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
  83        int i;
  84
  85        if (type & LARGE)
  86                digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  87        if (type & LEFT)
  88                type &= ~ZEROPAD;
  89        if (base < 2 || base > 36)
  90                return 0;
  91        c = (type & ZEROPAD) ? '0' : ' ';
  92        sign = 0;
  93        if (type & SIGN) {
  94                if ((signed long long)num < 0) {
  95                        sign = '-';
  96                        num = - (signed long long)num;
  97                        size--;
  98                } else if (type & PLUS) {
  99                        sign = '+';
 100                        size--;
 101                } else if (type & SPACE) {
 102                        sign = ' ';
 103                        size--;
 104                }
 105        }
 106        if (type & SPECIAL) {
 107                if (base == 16)
 108                        size -= 2;
 109                else if (base == 8)
 110                        size--;
 111        }
 112        i = 0;
 113        if (num == 0)
 114                tmp[i++]='0';
 115        else while (num != 0) {
 116                tmp[i++] = digits[do_div(num, base)];
 117        }
 118        if (i > precision)
 119                precision = i;
 120        size -= precision;
 121        if (!(type&(ZEROPAD+LEFT)))
 122                while(size-->0)
 123                        *str++ = ' ';
 124        if (sign)
 125                *str++ = sign;
 126        if (type & SPECIAL) {
 127                if (base==8)
 128                        *str++ = '0';
 129                else if (base==16) {
 130                        *str++ = '0';
 131                        *str++ = digits[33];
 132                }
 133        }
 134        if (!(type & LEFT))
 135                while (size-- > 0)
 136                        *str++ = c;
 137        while (i < precision--)
 138                *str++ = '0';
 139        while (i-- > 0)
 140                *str++ = tmp[i];
 141        while (size-- > 0)
 142                *str++ = ' ';
 143        return str;
 144}
 145
 146int vsprintf(char *buf, const char *fmt, va_list args)
 147{
 148        int len;
 149        unsigned long long num;
 150        int i, base;
 151        char * str;
 152        const char *s;
 153
 154        int flags;              /* flags to number() */
 155
 156        int field_width;        /* width of output field */
 157        int precision;          /* min. # of digits for integers; max
 158                                   number of chars for from string */
 159        int qualifier;          /* 'h', 'l', or 'L' for integer fields */
 160                                /* 'z' support added 23/7/1999 S.H.    */
 161                                /* 'z' changed to 'Z' --davidm 1/25/99 */
 162
 163        
 164        for (str=buf ; *fmt ; ++fmt) {
 165                if (*fmt != '%') {
 166                        *str++ = *fmt;
 167                        continue;
 168                }
 169                        
 170                /* process flags */
 171                flags = 0;
 172                repeat:
 173                        ++fmt;          /* this also skips first '%' */
 174                        switch (*fmt) {
 175                                case '-': flags |= LEFT; goto repeat;
 176                                case '+': flags |= PLUS; goto repeat;
 177                                case ' ': flags |= SPACE; goto repeat;
 178                                case '#': flags |= SPECIAL; goto repeat;
 179                                case '0': flags |= ZEROPAD; goto repeat;
 180                                }
 181                
 182                /* get field width */
 183                field_width = -1;
 184                if ('0' <= *fmt && *fmt <= '9')
 185                        field_width = skip_atoi(&fmt);
 186                else if (*fmt == '*') {
 187                        ++fmt;
 188                        /* it's the next argument */
 189                        field_width = va_arg(args, int);
 190                        if (field_width < 0) {
 191                                field_width = -field_width;
 192                                flags |= LEFT;
 193                        }
 194                }
 195
 196                /* get the precision */
 197                precision = -1;
 198                if (*fmt == '.') {
 199                        ++fmt;  
 200                        if ('0' <= *fmt && *fmt <= '9')
 201                                precision = skip_atoi(&fmt);
 202                        else if (*fmt == '*') {
 203                                ++fmt;
 204                                /* it's the next argument */
 205                                precision = va_arg(args, int);
 206                        }
 207                        if (precision < 0)
 208                                precision = 0;
 209                }
 210
 211                /* get the conversion qualifier */
 212                qualifier = -1;
 213                if (*fmt == 'l' && *(fmt + 1) == 'l') {
 214                        qualifier = 'q';
 215                        fmt += 2;
 216                } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
 217                        || *fmt == 'Z') {
 218                        qualifier = *fmt;
 219                        ++fmt;
 220                }
 221
 222                /* default base */
 223                base = 10;
 224
 225                switch (*fmt) {
 226                case 'c':
 227                        if (!(flags & LEFT))
 228                                while (--field_width > 0)
 229                                        *str++ = ' ';
 230                        *str++ = (unsigned char) va_arg(args, int);
 231                        while (--field_width > 0)
 232                                *str++ = ' ';
 233                        continue;
 234
 235                case 's':
 236                        s = va_arg(args, char *);
 237                        if (!s)
 238                                s = "<NULL>";
 239
 240                        len = strnlen(s, precision);
 241
 242                        if (!(flags & LEFT))
 243                                while (len < field_width--)
 244                                        *str++ = ' ';
 245                        for (i = 0; i < len; ++i)
 246                                *str++ = *s++;
 247                        while (len < field_width--)
 248                                *str++ = ' ';
 249                        continue;
 250
 251                case 'p':
 252                        if (field_width == -1) {
 253                                field_width = 2*sizeof(void *);
 254                                flags |= ZEROPAD;
 255                        }
 256                        str = number(str,
 257                                (unsigned long) va_arg(args, void *), 16,
 258                                field_width, precision, flags);
 259                        continue;
 260
 261
 262                case 'n':
 263                        if (qualifier == 'l') {
 264                                long * ip = va_arg(args, long *);
 265                                *ip = (str - buf);
 266                        } else if (qualifier == 'Z') {
 267                                size_t * ip = va_arg(args, size_t *);
 268                                *ip = (str - buf);
 269                        } else {
 270                                int * ip = va_arg(args, int *);
 271                                *ip = (str - buf);
 272                        }
 273                        continue;
 274
 275                case '%':
 276                        *str++ = '%';
 277                        continue;
 278
 279                /* integer number formats - set up the flags and "break" */
 280                case 'o':
 281                        base = 8;
 282                        break;
 283
 284                case 'X':
 285                        flags |= LARGE;
 286                case 'x':
 287                        base = 16;
 288                        break;
 289
 290                case 'd':
 291                case 'i':
 292                        flags |= SIGN;
 293                case 'u':
 294                        break;
 295
 296                default:
 297                        *str++ = '%';
 298                        if (*fmt)
 299                                *str++ = *fmt;
 300                        else
 301                                --fmt;
 302                        continue;
 303                }
 304                if (qualifier == 'l') {
 305                        num = va_arg(args, unsigned long);
 306                        if (flags & SIGN)
 307                                num = (signed long) num;
 308                } else if (qualifier == 'q') {
 309                        num = va_arg(args, unsigned long long);
 310                        if (flags & SIGN)
 311                                num = (signed long long) num;
 312                } else if (qualifier == 'Z') {
 313                        num = va_arg(args, size_t);
 314                } else if (qualifier == 'h') {
 315                        num = (unsigned short) va_arg(args, int);
 316                        if (flags & SIGN)
 317                                num = (signed short) num;
 318                } else {
 319                        num = va_arg(args, unsigned int);
 320                        if (flags & SIGN)
 321                                num = (signed int) num;
 322                }
 323                str = number(str, num, base, field_width, precision, flags);
 324        }
 325        *str = '\0';
 326        return str-buf;
 327}
 328
 329int sprintf(char * buf, const char *fmt, ...)
 330{
 331        va_list args;
 332        int i;
 333
 334        va_start(args, fmt);
 335        i=vsprintf(buf,fmt,args);
 336        va_end(args);
 337        return i;
 338}
 339
 340static char sprint_buf[1024];
 341
 342int
 343printf(const char *fmt, ...)
 344{
 345        va_list args;
 346        int n;
 347
 348        va_start(args, fmt);
 349        n = vsprintf(sprint_buf, fmt, args);
 350        va_end(args);
 351        if (console_ops.write)
 352                console_ops.write(sprint_buf, n);
 353        return n;
 354}
 355