Home | History | Annotate | Download | only in dos
      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 
     18 static 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) ({ \
     38 int __res; \
     39 __res = ((unsigned long) n) % (unsigned) base; \
     40 n = ((unsigned long) n) / (unsigned) base; \
     41 __res; })
     42 
     43 static 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... */
    112 int sprintf(char *buf, const char *fmt, ...);
    113 
    114 int 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;
    137 repeat:
    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 
    284 int 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 
    295 int 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