|
|
1.1 ! root 1: /* ! 2: * linux/kernel/vsprintf.c ! 3: * ! 4: * Copyright (C) 1991, 1992 Linus Torvalds ! 5: */ ! 6: ! 7: /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ ! 8: /* ! 9: * Wirzenius wrote this portably, Torvalds fucked it up :-) ! 10: */ ! 11: ! 12: #include <stdarg.h> ! 13: #include <linux/types.h> ! 14: #include <linux/string.h> ! 15: #include <linux/kernel.h> ! 16: ! 17: static inline ! 18: isxdigit(c) ! 19: char c; ! 20: { ! 21: return ((c >= '0' && c <= '9') ! 22: || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ! 23: } ! 24: ! 25: static inline ! 26: islower(c) ! 27: char c; ! 28: { ! 29: return (c >= 'a' && c <= 'z'); ! 30: } ! 31: ! 32: static inline ! 33: toupper(c) ! 34: char c; ! 35: { ! 36: return (islower(c) ? c - 'a' + 'A' : c); ! 37: } ! 38: ! 39: static inline ! 40: isdigit(c) ! 41: char c; ! 42: { ! 43: return (c >= '0' && c <= '9'); ! 44: } ! 45: ! 46: unsigned long ! 47: simple_strtoul(const char *cp,char **endp,unsigned int base) ! 48: { ! 49: unsigned long result = 0,value; ! 50: ! 51: if (!base) { ! 52: base = 10; ! 53: if (*cp == '0') { ! 54: base = 8; ! 55: cp++; ! 56: if ((*cp == 'x') && isxdigit(cp[1])) { ! 57: cp++; ! 58: base = 16; ! 59: } ! 60: } ! 61: } ! 62: while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) ! 63: ? toupper(*cp) : *cp)-'A'+10) < base) { ! 64: result = result*base + value; ! 65: cp++; ! 66: } ! 67: if (endp) ! 68: *endp = (char *)cp; ! 69: return result; ! 70: } ! 71: ! 72: /* we use this so that we can do without the ctype library */ ! 73: #define is_digit(c) ((c) >= '0' && (c) <= '9') ! 74: ! 75: static int ! 76: skip_atoi(const char **s) ! 77: { ! 78: int i=0; ! 79: ! 80: while (is_digit(**s)) ! 81: i = i*10 + *((*s)++) - '0'; ! 82: return i; ! 83: } ! 84: ! 85: #define ZEROPAD 1 /* pad with zero */ ! 86: #define SIGN 2 /* unsigned/signed long */ ! 87: #define PLUS 4 /* show plus */ ! 88: #define SPACE 8 /* space if plus */ ! 89: #define LEFT 16 /* left justified */ ! 90: #define SPECIAL 32 /* 0x */ ! 91: #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ ! 92: ! 93: #define do_div(n,base) ({ \ ! 94: int __res; \ ! 95: __res = ((unsigned long) n) % (unsigned) base; \ ! 96: n = ((unsigned long) n) / (unsigned) base; \ ! 97: __res; }) ! 98: ! 99: static char * ! 100: number(char * str, long num, int base, int size, int precision, int type) ! 101: { ! 102: char c,sign,tmp[36]; ! 103: const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; ! 104: int i; ! 105: ! 106: if (type & LARGE) ! 107: digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; ! 108: if (type & LEFT) ! 109: type &= ~ZEROPAD; ! 110: if (base < 2 || base > 36) ! 111: return 0; ! 112: c = (type & ZEROPAD) ? '0' : ' '; ! 113: sign = 0; ! 114: if (type & SIGN) { ! 115: if (num < 0) { ! 116: sign = '-'; ! 117: num = -num; ! 118: size--; ! 119: } else if (type & PLUS) { ! 120: sign = '+'; ! 121: size--; ! 122: } else if (type & SPACE) { ! 123: sign = ' '; ! 124: size--; ! 125: } ! 126: } ! 127: if (type & SPECIAL) { ! 128: if (base == 16) ! 129: size -= 2; ! 130: else if (base == 8) ! 131: size--; ! 132: } ! 133: i = 0; ! 134: if (num == 0) ! 135: tmp[i++]='0'; ! 136: else while (num != 0) ! 137: tmp[i++] = digits[do_div(num,base)]; ! 138: if (i > precision) ! 139: precision = i; ! 140: size -= precision; ! 141: if (!(type&(ZEROPAD+LEFT))) ! 142: while(size-->0) ! 143: *str++ = ' '; ! 144: if (sign) ! 145: *str++ = sign; ! 146: if (type & SPECIAL) ! 147: if (base==8) ! 148: *str++ = '0'; ! 149: else if (base==16) { ! 150: *str++ = '0'; ! 151: *str++ = digits[33]; ! 152: } ! 153: if (!(type & LEFT)) ! 154: while (size-- > 0) ! 155: *str++ = c; ! 156: while (i < precision--) ! 157: *str++ = '0'; ! 158: while (i-- > 0) ! 159: *str++ = tmp[i]; ! 160: while (size-- > 0) ! 161: *str++ = ' '; ! 162: return str; ! 163: } ! 164: ! 165: int ! 166: linux_vsprintf(char *buf, const char *fmt, va_list args) ! 167: { ! 168: int len; ! 169: unsigned long num; ! 170: int i, base; ! 171: char * str; ! 172: char *s; ! 173: ! 174: int flags; /* flags to number() */ ! 175: ! 176: int field_width; /* width of output field */ ! 177: int precision; /* min. # of digits for integers; max ! 178: number of chars for from string */ ! 179: int qualifier; /* 'h', 'l', or 'L' for integer fields */ ! 180: ! 181: for (str=buf ; *fmt ; ++fmt) { ! 182: if (*fmt != '%') { ! 183: *str++ = *fmt; ! 184: continue; ! 185: } ! 186: ! 187: /* process flags */ ! 188: flags = 0; ! 189: repeat: ! 190: ++fmt; /* this also skips first '%' */ ! 191: switch (*fmt) { ! 192: case '-': flags |= LEFT; goto repeat; ! 193: case '+': flags |= PLUS; goto repeat; ! 194: case ' ': flags |= SPACE; goto repeat; ! 195: case '#': flags |= SPECIAL; goto repeat; ! 196: case '0': flags |= ZEROPAD; goto repeat; ! 197: } ! 198: ! 199: /* get field width */ ! 200: field_width = -1; ! 201: if (is_digit(*fmt)) ! 202: field_width = skip_atoi(&fmt); ! 203: else if (*fmt == '*') { ! 204: ++fmt; ! 205: /* it's the next argument */ ! 206: field_width = va_arg(args, int); ! 207: if (field_width < 0) { ! 208: field_width = -field_width; ! 209: flags |= LEFT; ! 210: } ! 211: } ! 212: ! 213: /* get the precision */ ! 214: precision = -1; ! 215: if (*fmt == '.') { ! 216: ++fmt; ! 217: if (is_digit(*fmt)) ! 218: precision = skip_atoi(&fmt); ! 219: else if (*fmt == '*') { ! 220: ++fmt; ! 221: /* it's the next argument */ ! 222: precision = va_arg(args, int); ! 223: } ! 224: if (precision < 0) ! 225: precision = 0; ! 226: } ! 227: ! 228: /* get the conversion qualifier */ ! 229: qualifier = -1; ! 230: if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { ! 231: qualifier = *fmt; ! 232: ++fmt; ! 233: } ! 234: ! 235: /* default base */ ! 236: base = 10; ! 237: ! 238: switch (*fmt) { ! 239: case 'c': ! 240: if (!(flags & LEFT)) ! 241: while (--field_width > 0) ! 242: *str++ = ' '; ! 243: *str++ = (unsigned char) va_arg(args, int); ! 244: while (--field_width > 0) ! 245: *str++ = ' '; ! 246: continue; ! 247: ! 248: case 's': ! 249: s = va_arg(args, char *); ! 250: if (!s) ! 251: s = "<NULL>"; ! 252: len = strlen(s); ! 253: if (precision < 0) ! 254: precision = len; ! 255: else if (len > precision) ! 256: len = precision; ! 257: ! 258: if (!(flags & LEFT)) ! 259: while (len < field_width--) ! 260: *str++ = ' '; ! 261: for (i = 0; i < len; ++i) ! 262: *str++ = *s++; ! 263: while (len < field_width--) ! 264: *str++ = ' '; ! 265: continue; ! 266: ! 267: case 'p': ! 268: if (field_width == -1) { ! 269: field_width = 2*sizeof(void *); ! 270: flags |= ZEROPAD; ! 271: } ! 272: str = number(str, ! 273: (unsigned long) va_arg(args, void *), 16, ! 274: field_width, precision, flags); ! 275: continue; ! 276: ! 277: ! 278: case 'n': ! 279: if (qualifier == 'l') { ! 280: long * ip = va_arg(args, long *); ! 281: *ip = (str - buf); ! 282: } else { ! 283: int * ip = va_arg(args, int *); ! 284: *ip = (str - buf); ! 285: } ! 286: continue; ! 287: ! 288: /* integer number formats - set up the flags and "break" */ ! 289: case 'o': ! 290: base = 8; ! 291: break; ! 292: ! 293: case 'X': ! 294: flags |= LARGE; ! 295: case 'x': ! 296: base = 16; ! 297: break; ! 298: ! 299: case 'd': ! 300: case 'i': ! 301: flags |= SIGN; ! 302: case 'u': ! 303: break; ! 304: ! 305: default: ! 306: if (*fmt != '%') ! 307: *str++ = '%'; ! 308: if (*fmt) ! 309: *str++ = *fmt; ! 310: else ! 311: --fmt; ! 312: continue; ! 313: } ! 314: if (qualifier == 'l') ! 315: num = va_arg(args, unsigned long); ! 316: else if (qualifier == 'h') ! 317: if (flags & SIGN) ! 318: num = va_arg(args, short); ! 319: else ! 320: num = va_arg(args, unsigned short); ! 321: else if (flags & SIGN) ! 322: num = va_arg(args, int); ! 323: else ! 324: num = va_arg(args, unsigned int); ! 325: str = number(str, num, base, field_width, precision, flags); ! 326: } ! 327: *str = '\0'; ! 328: return str-buf; ! 329: } ! 330: ! 331: int ! 332: linux_sprintf(char * buf, const char *fmt, ...) ! 333: { ! 334: va_list args; ! 335: int i; ! 336: ! 337: va_start(args, fmt); ! 338: i = linux_vsprintf(buf, fmt, args); ! 339: va_end(args); ! 340: return i; ! 341: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.