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