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