|
|
1.1 ! root 1: /* ! 2: * String functions for logger. ! 3: */ ! 4: ! 5: /* ! 6: * linux/lib/vsprintf.c ! 7: * ! 8: * Copyright (C) 1991, 1992 Linus Torvalds ! 9: */ ! 10: ! 11: /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ ! 12: /* ! 13: * Wirzenius wrote this portably, Torvalds fucked it up :-) ! 14: */ ! 15: ! 16: /* ! 17: * Fri Jul 13 2001 Crutcher Dunnavant <[email protected]> ! 18: * - changed to provide snprintf and vsnprintf functions ! 19: */ ! 20: ! 21: #include "config.h" ! 22: #include "libc/string.h" ! 23: #include "libc/vsprintf.h" ! 24: ! 25: static int skip_atoi(const char **s) ! 26: { ! 27: int i=0; ! 28: ! 29: while (isdigit(**s)) ! 30: i = i*10 + *((*s)++) - '0'; ! 31: return i; ! 32: } ! 33: ! 34: #define ZEROPAD 1 /* pad with zero */ ! 35: #define SIGN 2 /* unsigned/signed long */ ! 36: #define PLUS 4 /* show plus */ ! 37: #define SPACE 8 /* space if plus */ ! 38: #define LEFT 16 /* left justified */ ! 39: #define SPECIAL 32 /* 0x */ ! 40: #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ ! 41: ! 42: #define do_div(n,base) ({ \ ! 43: int __res; \ ! 44: __res = ((unsigned long long) n) % (unsigned) base; \ ! 45: n = ((unsigned long long) n) / (unsigned) base; \ ! 46: __res; }) ! 47: ! 48: static int mstrlen( const char *str ); ! 49: ! 50: #ifndef PAGE_SIZE ! 51: #define PAGE_SIZE 4096 ! 52: #endif ! 53: ! 54: static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type) ! 55: { ! 56: char c,sign,tmp[66]; ! 57: const char *digits; ! 58: static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; ! 59: static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; ! 60: int i; ! 61: ! 62: digits = (type & LARGE) ? large_digits : small_digits; ! 63: if (type & LEFT) ! 64: type &= ~ZEROPAD; ! 65: if (base < 2 || base > 36) ! 66: return NULL; ! 67: c = (type & ZEROPAD) ? '0' : ' '; ! 68: sign = 0; ! 69: if (type & SIGN) { ! 70: if (num < 0) { ! 71: sign = '-'; ! 72: num = -num; ! 73: size--; ! 74: } else if (type & PLUS) { ! 75: sign = '+'; ! 76: size--; ! 77: } else if (type & SPACE) { ! 78: sign = ' '; ! 79: size--; ! 80: } ! 81: } ! 82: if (type & SPECIAL) { ! 83: if (base == 16) ! 84: size -= 2; ! 85: else if (base == 8) ! 86: size--; ! 87: } ! 88: i = 0; ! 89: if (num == 0) ! 90: tmp[i++]='0'; ! 91: else while (num != 0) ! 92: tmp[i++] = digits[do_div(num,base)]; ! 93: if (i > precision) ! 94: precision = i; ! 95: size -= precision; ! 96: if (!(type&(ZEROPAD+LEFT))) { ! 97: while(size-->0) { ! 98: if (buf <= end) ! 99: *buf = ' '; ! 100: ++buf; ! 101: } ! 102: } ! 103: if (sign) { ! 104: if (buf <= end) ! 105: *buf = sign; ! 106: ++buf; ! 107: } ! 108: if (type & SPECIAL) { ! 109: if (base==8) { ! 110: if (buf <= end) ! 111: *buf = '0'; ! 112: ++buf; ! 113: } else if (base==16) { ! 114: if (buf <= end) ! 115: *buf = '0'; ! 116: ++buf; ! 117: if (buf <= end) ! 118: *buf = digits[33]; ! 119: ++buf; ! 120: } ! 121: } ! 122: if (!(type & LEFT)) { ! 123: while (size-- > 0) { ! 124: if (buf <= end) ! 125: *buf = c; ! 126: ++buf; ! 127: } ! 128: } ! 129: while (i < precision--) { ! 130: if (buf <= end) ! 131: *buf = '0'; ! 132: ++buf; ! 133: } ! 134: while (i-- > 0) { ! 135: if (buf <= end) ! 136: *buf = tmp[i]; ! 137: ++buf; ! 138: } ! 139: while (size-- > 0) { ! 140: if (buf <= end) ! 141: *buf = ' '; ! 142: ++buf; ! 143: } ! 144: return buf; ! 145: } ! 146: ! 147: /** ! 148: * vsnprintf - Format a string and place it in a buffer ! 149: * @buf: The buffer to place the result into ! 150: * @size: The size of the buffer, including the trailing null space ! 151: * @fmt: The format string to use ! 152: * @args: Arguments for the format string ! 153: * ! 154: * Call this function if you are already dealing with a va_list. ! 155: * You probably want snprintf instead. ! 156: */ ! 157: int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) ! 158: { ! 159: int len; ! 160: unsigned long long num; ! 161: int i, base; ! 162: char *str, *end, c; ! 163: const char *s; ! 164: ! 165: int flags; /* flags to number() */ ! 166: ! 167: int field_width; /* width of output field */ ! 168: int precision; /* min. # of digits for integers; max ! 169: number of chars for from string */ ! 170: int qualifier; /* 'h', 'l', or 'L' for integer fields */ ! 171: /* 'z' support added 23/7/1999 S.H. */ ! 172: /* 'z' changed to 'Z' --davidm 1/25/99 */ ! 173: ! 174: str = buf; ! 175: end = buf + size - 1; ! 176: ! 177: if (end < buf - 1) { ! 178: end = ((void *) -1); ! 179: size = end - buf + 1; ! 180: } ! 181: ! 182: for (; *fmt ; ++fmt) { ! 183: if (*fmt != '%') { ! 184: if (str <= end) ! 185: *str = *fmt; ! 186: ++str; ! 187: continue; ! 188: } ! 189: ! 190: /* process flags */ ! 191: flags = 0; ! 192: repeat: ! 193: ++fmt; /* this also skips first '%' */ ! 194: switch (*fmt) { ! 195: case '-': flags |= LEFT; goto repeat; ! 196: case '+': flags |= PLUS; goto repeat; ! 197: case ' ': flags |= SPACE; goto repeat; ! 198: case '#': flags |= SPECIAL; goto repeat; ! 199: case '0': flags |= ZEROPAD; goto repeat; ! 200: } ! 201: ! 202: /* get field width */ ! 203: field_width = -1; ! 204: if (isdigit(*fmt)) ! 205: field_width = skip_atoi(&fmt); ! 206: else if (*fmt == '*') { ! 207: ++fmt; ! 208: /* it's the next argument */ ! 209: field_width = va_arg(args, int); ! 210: if (field_width < 0) { ! 211: field_width = -field_width; ! 212: flags |= LEFT; ! 213: } ! 214: } ! 215: ! 216: /* get the precision */ ! 217: precision = -1; ! 218: if (*fmt == '.') { ! 219: ++fmt; ! 220: if (isdigit(*fmt)) ! 221: precision = skip_atoi(&fmt); ! 222: else if (*fmt == '*') { ! 223: ++fmt; ! 224: /* it's the next argument */ ! 225: precision = va_arg(args, int); ! 226: } ! 227: if (precision < 0) ! 228: precision = 0; ! 229: } ! 230: ! 231: /* get the conversion qualifier */ ! 232: qualifier = -1; ! 233: if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || ! 234: *fmt =='Z' || *fmt == 'z') { ! 235: qualifier = *fmt; ! 236: ++fmt; ! 237: if (qualifier == 'l' && *fmt == 'l') { ! 238: qualifier = 'L'; ! 239: ++fmt; ! 240: } ! 241: } ! 242: ! 243: /* default base */ ! 244: base = 10; ! 245: ! 246: switch (*fmt) { ! 247: case 'c': ! 248: if (!(flags & LEFT)) { ! 249: while (--field_width > 0) { ! 250: if (str <= end) ! 251: *str = ' '; ! 252: ++str; ! 253: } ! 254: } ! 255: c = (unsigned char) va_arg(args, int); ! 256: if (str <= end) ! 257: *str = c; ! 258: ++str; ! 259: while (--field_width > 0) { ! 260: if (str <= end) ! 261: *str = ' '; ! 262: ++str; ! 263: } ! 264: continue; ! 265: ! 266: case 's': ! 267: s = va_arg(args, char *); ! 268: if ((unsigned long)s < PAGE_SIZE) ! 269: s = "<NULL>"; ! 270: ! 271: #if 0 ! 272: len = strnlen(s, precision); ! 273: #else ! 274: len = mstrlen(s); ! 275: if( precision > len ) ! 276: len = precision; ! 277: #endif ! 278: if (!(flags & LEFT)) { ! 279: while (len < field_width--) { ! 280: if (str <= end) ! 281: *str = ' '; ! 282: ++str; ! 283: } ! 284: } ! 285: for (i = 0; i < len; ++i) { ! 286: if (str <= end) ! 287: *str = *s; ! 288: ++str; ++s; ! 289: } ! 290: while (len < field_width--) { ! 291: if (str <= end) ! 292: *str = ' '; ! 293: ++str; ! 294: } ! 295: continue; ! 296: ! 297: case 'p': ! 298: if (field_width == -1) { ! 299: field_width = 2*sizeof(void *); ! 300: flags |= ZEROPAD; ! 301: } ! 302: str = number(str, end, ! 303: (unsigned long) va_arg(args, void *), ! 304: 16, field_width, precision, flags); ! 305: continue; ! 306: ! 307: ! 308: case 'n': ! 309: /* FIXME: ! 310: * What does C99 say about the overflow case here? */ ! 311: if (qualifier == 'l') { ! 312: long * ip = va_arg(args, long *); ! 313: *ip = (str - buf); ! 314: } else if (qualifier == 'Z' || qualifier == 'z') { ! 315: size_t * ip = va_arg(args, size_t *); ! 316: *ip = (str - buf); ! 317: } else { ! 318: int * ip = va_arg(args, int *); ! 319: *ip = (str - buf); ! 320: } ! 321: continue; ! 322: ! 323: case '%': ! 324: if (str <= end) ! 325: *str = '%'; ! 326: ++str; ! 327: continue; ! 328: ! 329: /* integer number formats - set up the flags and "break" */ ! 330: case 'o': ! 331: base = 8; ! 332: break; ! 333: ! 334: case 'X': ! 335: flags |= LARGE; ! 336: case 'x': ! 337: base = 16; ! 338: break; ! 339: ! 340: case 'd': ! 341: case 'i': ! 342: flags |= SIGN; ! 343: case 'u': ! 344: break; ! 345: ! 346: default: ! 347: if (str <= end) ! 348: *str = '%'; ! 349: ++str; ! 350: if (*fmt) { ! 351: if (str <= end) ! 352: *str = *fmt; ! 353: ++str; ! 354: } else { ! 355: --fmt; ! 356: } ! 357: continue; ! 358: } ! 359: if (qualifier == 'L') ! 360: num = va_arg(args, long long); ! 361: else if (qualifier == 'l') { ! 362: num = va_arg(args, unsigned long); ! 363: if (flags & SIGN) ! 364: num = (signed long) num; ! 365: } else if (qualifier == 'Z' || qualifier == 'z') { ! 366: num = va_arg(args, size_t); ! 367: } else if (qualifier == 'h') { ! 368: num = (unsigned short) va_arg(args, int); ! 369: if (flags & SIGN) ! 370: num = (signed short) num; ! 371: } else { ! 372: num = va_arg(args, unsigned int); ! 373: if (flags & SIGN) ! 374: num = (signed int) num; ! 375: } ! 376: str = number(str, end, num, base, ! 377: field_width, precision, flags); ! 378: } ! 379: if (str <= end) ! 380: *str = '\0'; ! 381: else if (size > 0) ! 382: /* don't write out a null byte if the buf size is zero */ ! 383: *end = '\0'; ! 384: /* the trailing null byte doesn't count towards the total ! 385: * ++str; ! 386: */ ! 387: return str-buf; ! 388: } ! 389: ! 390: /** ! 391: * snprintf - Format a string and place it in a buffer ! 392: * @buf: The buffer to place the result into ! 393: * @size: The size of the buffer, including the trailing null space ! 394: * @fmt: The format string to use ! 395: * @...: Arguments for the format string ! 396: */ ! 397: int snprintf(char * buf, size_t size, const char *fmt, ...) ! 398: { ! 399: va_list args; ! 400: int i; ! 401: ! 402: va_start(args, fmt); ! 403: i=vsnprintf(buf,size,fmt,args); ! 404: va_end(args); ! 405: return i; ! 406: } ! 407: ! 408: /** ! 409: * vsprintf - Format a string and place it in a buffer ! 410: * @buf: The buffer to place the result into ! 411: * @fmt: The format string to use ! 412: * @args: Arguments for the format string ! 413: * ! 414: * Call this function if you are already dealing with a va_list. ! 415: * You probably want sprintf instead. ! 416: */ ! 417: int vsprintf(char *buf, const char *fmt, va_list args) ! 418: { ! 419: return vsnprintf(buf, (~0U)>>1, fmt, args); ! 420: } ! 421: ! 422: ! 423: /** ! 424: * sprintf - Format a string and place it in a buffer ! 425: * @buf: The buffer to place the result into ! 426: * @fmt: The format string to use ! 427: * @...: Arguments for the format string ! 428: */ ! 429: int sprintf(char * buf, const char *fmt, ...) ! 430: { ! 431: va_list args; ! 432: int i; ! 433: ! 434: va_start(args, fmt); ! 435: i=vsprintf(buf,fmt,args); ! 436: va_end(args); ! 437: return i; ! 438: } ! 439: ! 440: static int mstrlen( const char *str ) ! 441: { ! 442: int i=0; ! 443: if( str == NULL ) ! 444: return 0; ! 445: while( *str++ ) ! 446: i++; ! 447: return i; ! 448: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.