linux/arch/x86/boot/printf.c
<<
>>
Prefs
   1/* -*- linux-c -*- ------------------------------------------------------- *
   2 *
   3 *   Copyright (C) 1991, 1992 Linus Torvalds
   4 *   Copyright 2007 rPath, Inc. - All Rights Reserved
   5 *
   6 *   This file is part of the Linux kernel, and is made available under
   7 *   the terms of the GNU General Public License version 2.
   8 *
   9 * ----------------------------------------------------------------------- */
  10
  11/*
  12 * arch/i386/boot/printf.c
  13 *
  14 * Oh, it's a waste of space, but oh-so-yummy for debugging.  This
  15 * version of printf() does not include 64-bit support.  "Live with
  16 * it."
  17 *
  18 */
  19
  20#include "boot.h"
  21
  22static int skip_atoi(const char **s)
  23{
  24        int i = 0;
  25
  26        while (isdigit(**s))
  27                i = i * 10 + *((*s)++) - '0';
  28        return i;
  29}
  30
  31#define ZEROPAD 1               /* pad with zero */
  32#define SIGN    2               /* unsigned/signed long */
  33#define PLUS    4               /* show plus */
  34#define SPACE   8               /* space if plus */
  35#define LEFT    16              /* left justified */
  36#define SMALL   32              /* Must be 32 == 0x20 */
  37#define SPECIAL 64              /* 0x */
  38
  39#define do_div(n,base) ({ \
  40int __res; \
  41__res = ((unsigned long) n) % (unsigned) base; \
  42n = ((unsigned long) n) / (unsigned) base; \
  43__res; })
  44
  45static char *number(char *str, long num, int base, int size, int precision,
  46                    int type)
  47{
  48        /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
  49        static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
  50
  51        char tmp[66];
  52        char c, sign, locase;
  53        int i;
  54
  55        /* locase = 0 or 0x20. ORing digits or letters with 'locase'
  56         * produces same digits or (maybe lowercased) letters */
  57        locase = (type & SMALL);
  58        if (type & LEFT)
  59                type &= ~ZEROPAD;
  60        if (base < 2 || base > 36)
  61                return 0;
  62        c = (type & ZEROPAD) ? '0' : ' ';
  63        sign = 0;
  64        if (type & SIGN) {
  65                if (num < 0) {
  66                        sign = '-';
  67                        num = -num;
  68                        size--;
  69                } else if (type & PLUS) {
  70                        sign = '+';
  71                        size--;
  72                } else if (type & SPACE) {
  73                        sign = ' ';
  74                        size--;
  75                }
  76        }
  77        if (type & SPECIAL) {
  78                if (base == 16)
  79                        size -= 2;
  80                else if (base == 8)
  81                        size--;
  82        }
  83        i = 0;
  84        if (num == 0)
  85                tmp[i++] = '0';
  86        else
  87                while (num != 0)
  88                        tmp[i++] = (digits[do_div(num, base)] | locase);
  89        if (i > precision)
  90                precision = i;
  91        size -= precision;
  92        if (!(type & (ZEROPAD + LEFT)))
  93                while (size-- > 0)
  94                        *str++ = ' ';
  95        if (sign)
  96                *str++ = sign;
  97        if (type & SPECIAL) {
  98                if (base == 8)
  99                        *str++ = '0';
 100                else if (base == 16) {
 101                        *str++ = '0';
 102                        *str++ = ('X' | locase);
 103                }
 104        }
 105        if (!(type & LEFT))
 106                while (size-- > 0)
 107                        *str++ = c;
 108        while (i < precision--)
 109                *str++ = '0';
 110        while (i-- > 0)
 111                *str++ = tmp[i];
 112        while (size-- > 0)
 113                *str++ = ' ';
 114        return str;
 115}
 116
 117int vsprintf(char *buf, const char *fmt, va_list args)
 118{
 119        int len;
 120        unsigned long num;
 121        int i, base;
 122        char *str;
 123        const char *s;
 124
 125        int flags;              /* flags to number() */
 126
 127        int field_width;        /* width of output field */
 128        int precision;          /* min. # of digits for integers; max
 129                                   number of chars for from string */
 130        int qualifier;          /* 'h', 'l', or 'L' for integer fields */
 131
 132        for (str = buf; *fmt; ++fmt) {
 133                if (*fmt != '%') {
 134                        *str++ = *fmt;
 135                        continue;
 136                }
 137
 138                /* process flags */
 139                flags = 0;
 140              repeat:
 141                ++fmt;          /* this also skips first '%' */
 142                switch (*fmt) {
 143                case '-':
 144                        flags |= LEFT;
 145                        goto repeat;
 146                case '+':
 147                        flags |= PLUS;
 148                        goto repeat;
 149                case ' ':
 150                        flags |= SPACE;
 151                        goto repeat;
 152                case '#':
 153                        flags |= SPECIAL;
 154                        goto repeat;
 155                case '0':
 156                        flags |= ZEROPAD;
 157                        goto repeat;
 158                }
 159
 160                /* get field width */
 161                field_width = -1;
 162                if (isdigit(*fmt))
 163                        field_width = skip_atoi(&fmt);
 164                else if (*fmt == '*') {
 165                        ++fmt;
 166                        /* it's the next argument */
 167                        field_width = va_arg(args, int);
 168                        if (field_width < 0) {
 169                                field_width = -field_width;
 170                                flags |= LEFT;
 171                        }
 172                }
 173
 174                /* get the precision */
 175                precision = -1;
 176                if (*fmt == '.') {
 177                        ++fmt;
 178                        if (isdigit(*fmt))
 179                                precision = skip_atoi(&fmt);
 180                        else if (*fmt == '*') {
 181                                ++fmt;
 182                                /* it's the next argument */
 183                                precision = va_arg(args, int);
 184                        }
 185                        if (precision < 0)
 186                                precision = 0;
 187                }
 188
 189                /* get the conversion qualifier */
 190                qualifier = -1;
 191                if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
 192                        qualifier = *fmt;
 193                        ++fmt;
 194                }
 195
 196                /* default base */
 197                base = 10;
 198
 199                switch (*fmt) {
 200                case 'c':
 201                        if (!(flags & LEFT))
 202                                while (--field_width > 0)
 203                                        *str++ = ' ';
 204                        *str++ = (unsigned char)va_arg(args, int);
 205                        while (--field_width > 0)
 206                                *str++ = ' ';
 207                        continue;
 208
 209                case 's':
 210                        s = va_arg(args, char *);
 211                        len = strnlen(s, precision);
 212
 213                        if (!(flags & LEFT))
 214                                while (len < field_width--)
 215                                        *str++ = ' ';
 216                        for (i = 0; i < len; ++i)
 217                                *str++ = *s++;
 218                        while (len < field_width--)
 219                                *str++ = ' ';
 220                        continue;
 221
 222                case 'p':
 223                        if (field_width == -1) {
 224                                field_width = 2 * sizeof(void *);
 225                                flags |= ZEROPAD;
 226                        }
 227                        str = number(str,
 228                                     (unsigned long)va_arg(args, void *), 16,
 229                                     field_width, precision, flags);
 230                        continue;
 231
 232                case 'n':
 233                        if (qualifier == 'l') {
 234                                long *ip = va_arg(args, long *);
 235                                *ip = (str - buf);
 236                        } else {
 237                                int *ip = va_arg(args, int *);
 238                                *ip = (str - buf);
 239                        }
 240                        continue;
 241
 242                case '%':
 243                        *str++ = '%';
 244                        continue;
 245
 246                        /* integer number formats - set up the flags and "break" */
 247                case 'o':
 248                        base = 8;
 249                        break;
 250
 251                case 'x':
 252                        flags |= SMALL;
 253                case 'X':
 254                        base = 16;
 255                        break;
 256
 257                case 'd':
 258                case 'i':
 259                        flags |= SIGN;
 260                case 'u':
 261                        break;
 262
 263                default:
 264                        *str++ = '%';
 265                        if (*fmt)
 266                                *str++ = *fmt;
 267                        else
 268                                --fmt;
 269                        continue;
 270                }
 271                if (qualifier == 'l')
 272                        num = va_arg(args, unsigned long);
 273                else if (qualifier == 'h') {
 274                        num = (unsigned short)va_arg(args, int);
 275                        if (flags & SIGN)
 276                                num = (short)num;
 277                } else if (flags & SIGN)
 278                        num = va_arg(args, int);
 279                else
 280                        num = va_arg(args, unsigned int);
 281                str = number(str, num, base, field_width, precision, flags);
 282        }
 283        *str = '\0';
 284        return str - buf;
 285}
 286
 287int sprintf(char *buf, const char *fmt, ...)
 288{
 289        va_list args;
 290        int i;
 291
 292        va_start(args, fmt);
 293        i = vsprintf(buf, fmt, args);
 294        va_end(args);
 295        return i;
 296}
 297
 298int printf(const char *fmt, ...)
 299{
 300        char printf_buf[1024];
 301        va_list args;
 302        int printed;
 303
 304        va_start(args, fmt);
 305        printed = vsprintf(printf_buf, fmt, args);
 306        va_end(args);
 307
 308        puts(printf_buf);
 309
 310        return printed;
 311}
 312
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.