X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/b57f37fb6a4d30ac9aaba3bbca06f5a3307c804a..36fb4e9a7743326d1a2ca7601bc9bf1c5b9a0bcb:/libratbox/src/snprintf.c diff --git a/libratbox/src/snprintf.c b/libratbox/src/snprintf.c index 0c116ab..593fe81 100644 --- a/libratbox/src/snprintf.c +++ b/libratbox/src/snprintf.c @@ -4,7 +4,7 @@ * The original headers are below.. * Note that this implementation does not process floating point numbers so * you will likely need to fall back to using sprintf yourself to do those... - * $Id: snprintf.c 25038 2008-01-23 16:03:08Z androsyn $ + * $Id: snprintf.c 26092 2008-09-19 15:13:52Z androsyn $ */ /* @@ -27,12 +27,13 @@ #include #include -static int skip_atoi(const char **s) +static int +skip_atoi(const char **s) { - int i=0; + int i = 0; - while (isdigit(**s)) - i = i*10 + *((*s)++) - '0'; + while(isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; return i; } @@ -46,50 +47,56 @@ static int skip_atoi(const char **s) /* Formats correctly any integer in [0,99999]. * Outputs from one to five digits depending on input. * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ -static char* put_dec_trunc(char *buf, unsigned q) +static char * +put_dec_trunc(char *buf, unsigned q) { unsigned d3, d2, d1, d0; - d1 = (q>>4) & 0xf; - d2 = (q>>8) & 0xf; - d3 = (q>>12); + d1 = (q >> 4) & 0xf; + d2 = (q >> 8) & 0xf; + d3 = (q >> 12); - d0 = 6*(d3 + d2 + d1) + (q & 0xf); + d0 = 6 * (d3 + d2 + d1) + (q & 0xf); q = (d0 * 0xcd) >> 11; - d0 = d0 - 10*q; - *buf++ = d0 + '0'; /* least significant digit */ - d1 = q + 9*d3 + 5*d2 + d1; - if (d1 != 0) { + d0 = d0 - 10 * q; + *buf++ = d0 + '0'; /* least significant digit */ + d1 = q + 9 * d3 + 5 * d2 + d1; + if(d1 != 0) + { q = (d1 * 0xcd) >> 11; - d1 = d1 - 10*q; - *buf++ = d1 + '0'; /* next digit */ + d1 = d1 - 10 * q; + *buf++ = d1 + '0'; /* next digit */ - d2 = q + 2*d2; - if ((d2 != 0) || (d3 != 0)) { + d2 = q + 2 * d2; + if((d2 != 0) || (d3 != 0)) + { q = (d2 * 0xd) >> 7; - d2 = d2 - 10*q; - *buf++ = d2 + '0'; /* next digit */ + d2 = d2 - 10 * q; + *buf++ = d2 + '0'; /* next digit */ - d3 = q + 4*d3; - if (d3 != 0) { + d3 = q + 4 * d3; + if(d3 != 0) + { q = (d3 * 0xcd) >> 11; - d3 = d3 - 10*q; - *buf++ = d3 + '0'; /* next digit */ - if (q != 0) - *buf++ = q + '0'; /* most sign. digit */ + d3 = d3 - 10 * q; + *buf++ = d3 + '0'; /* next digit */ + if(q != 0) + *buf++ = q + '0'; /* most sign. digit */ } } } return buf; } + /* Same with if's removed. Always emits five digits */ -static char* put_dec_full(char *buf, unsigned q) +static char * +put_dec_full(char *buf, unsigned q) { /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ /* but anyway, gcc produces better code with full-sized ints */ unsigned d3, d2, d1, d0; - d1 = (q>>4) & 0xf; - d2 = (q>>8) & 0xf; - d3 = (q>>12); + d1 = (q >> 4) & 0xf; + d2 = (q >> 8) & 0xf; + d3 = (q >> 12); /* Possible ways to approx. divide by 10 */ /* gcc -O2 replaces multiply with shifts and adds */ @@ -99,34 +106,36 @@ static char* put_dec_full(char *buf, unsigned q) // (x * 0x1a) >> 8: 11010 - same // (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) - d0 = 6*(d3 + d2 + d1) + (q & 0xf); + d0 = 6 * (d3 + d2 + d1) + (q & 0xf); q = (d0 * 0xcd) >> 11; - d0 = d0 - 10*q; + d0 = d0 - 10 * q; *buf++ = d0 + '0'; - d1 = q + 9*d3 + 5*d2 + d1; - q = (d1 * 0xcd) >> 11; - d1 = d1 - 10*q; - *buf++ = d1 + '0'; - - d2 = q + 2*d2; - q = (d2 * 0xd) >> 7; - d2 = d2 - 10*q; - *buf++ = d2 + '0'; - - d3 = q + 4*d3; - q = (d3 * 0xcd) >> 11; /* - shorter code */ - /* q = (d3 * 0x67) >> 10; - would also work */ - d3 = d3 - 10*q; - *buf++ = d3 + '0'; - *buf++ = q + '0'; + d1 = q + 9 * d3 + 5 * d2 + d1; + q = (d1 * 0xcd) >> 11; + d1 = d1 - 10 * q; + *buf++ = d1 + '0'; + + d2 = q + 2 * d2; + q = (d2 * 0xd) >> 7; + d2 = d2 - 10 * q; + *buf++ = d2 + '0'; + + d3 = q + 4 * d3; + q = (d3 * 0xcd) >> 11; /* - shorter code */ + /* q = (d3 * 0x67) >> 10; - would also work */ + d3 = d3 - 10 * q; + *buf++ = d3 + '0'; + *buf++ = q + '0'; return buf; } -static char* put_dec(char *buf, unsigned long long int num) +static char * +put_dec(char *buf, unsigned long long int num) { - while (1) { + while(1) + { unsigned rem; - if (num < 100000) + if(num < 100000) return put_dec_trunc(buf, num); rem = num % 100000; num = num / 100000; @@ -142,115 +151,140 @@ static char* put_dec(char *buf, unsigned long long int num) #define SPECIAL 32 /* 0x */ #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ -static char *number(char *buf, char *end, unsigned long long int num, int base, int size, int precision, int type) +static char * +number(char *buf, char *end, unsigned long long int num, int base, int size, int precision, + int type) { - char sign,tmp[66]; + char sign, tmp[66]; const char *digits; /* we are called with base 8, 10 or 16, only, thus don't need "g..." */ - static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */ - static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ + static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */ + static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ int need_pfx = ((type & SPECIAL) && base != 10); int i; digits = (type & LARGE) ? large_digits : small_digits; - if (type & LEFT) + if(type & LEFT) type &= ~ZEROPAD; - if (base < 2 || base > 36) + if(base < 2 || base > 36) return NULL; sign = 0; - if (type & SIGN) { - if ((signed long long int) num < 0) { + if(type & SIGN) + { + if((signed long long int)num < 0) + { sign = '-'; - num = - (signed long long int) num; + num = -(signed long long int)num; size--; - } else if (type & PLUS) { + } + else if(type & PLUS) + { sign = '+'; size--; - } else if (type & SPACE) { + } + else if(type & SPACE) + { sign = ' '; size--; } } - if (need_pfx) { + if(need_pfx) + { size--; - if (base == 16) + if(base == 16) size--; } /* generate full string in tmp[], in reverse order */ i = 0; - if (num == 0) + if(num == 0) tmp[i++] = '0'; /* Generic code, for any base: - else do { - tmp[i++] = digits[do_div(num,base)]; - } while (num != 0); - */ - else if (base != 10) { /* 8 or 16 */ + else do { + tmp[i++] = digits[do_div(num,base)]; + } while (num != 0); + */ + else if(base != 10) + { /* 8 or 16 */ int mask = base - 1; int shift = 3; - if (base == 16) shift = 4; - do { + if(base == 16) + shift = 4; + do + { tmp[i++] = digits[((unsigned char)num) & mask]; num >>= shift; - } while (num); - } else { /* base 10 */ + } + while(num); + } + else + { /* base 10 */ i = put_dec(tmp, num) - tmp; } /* printing 100 using %2d gives "100", not "00" */ - if (i > precision) + if(i > precision) precision = i; /* leading space padding */ size -= precision; - if (!(type & (ZEROPAD+LEFT))) { - while(--size >= 0) { - if (buf < end) + if(!(type & (ZEROPAD + LEFT))) + { + while(--size >= 0) + { + if(buf < end) *buf = ' '; ++buf; } } /* sign */ - if (sign) { - if (buf < end) + if(sign) + { + if(buf < end) *buf = sign; ++buf; } /* "0x" / "0" prefix */ - if (need_pfx) { - if (buf < end) + if(need_pfx) + { + if(buf < end) *buf = '0'; ++buf; - if (base == 16) { - if (buf < end) - *buf = digits[16]; /* for arbitrary base: digits[33]; */ + if(base == 16) + { + if(buf < end) + *buf = digits[16]; /* for arbitrary base: digits[33]; */ ++buf; } } /* zero or space padding */ - if (!(type & LEFT)) { + if(!(type & LEFT)) + { char c = (type & ZEROPAD) ? '0' : ' '; - while (--size >= 0) { - if (buf < end) + while(--size >= 0) + { + if(buf < end) *buf = c; ++buf; } } /* hmm even more zero padding? */ - while (i <= --precision) { - if (buf < end) + while(i <= --precision) + { + if(buf < end) *buf = '0'; ++buf; } /* actual digits of result */ - while (--i >= 0) { - if (buf < end) + while(--i >= 0) + { + if(buf < end) *buf = tmp[i]; ++buf; } /* trailing space padding */ - while (--size >= 0) { - if (buf < end) + while(--size >= 0) + { + if(buf < end) *buf = ' '; ++buf; } @@ -275,7 +309,8 @@ static char *number(char *buf, char *end, unsigned long long int num, int base, * Call this function if you are already dealing with a va_list. * You probably want snprintf() instead. */ -int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) +int +rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { int len; unsigned long long int num; @@ -289,13 +324,14 @@ int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) int precision; /* min. # of digits for integers; max number of chars for from string */ int qualifier; /* 'h', 'l', or 'L' for integer fields */ - /* 'z' support added 23/7/1999 S.H. */ - /* 'z' changed to 'Z' --davidm 1/25/99 */ - /* 't' added for ptrdiff_t */ + /* 'z' support added 23/7/1999 S.H. */ + /* 'z' changed to 'Z' --davidm 1/25/99 */ + /* 't' added for ptrdiff_t */ /* Reject out-of-range values early. Large positive sizes are used for unknown buffer sizes. */ - if (unlikely((int) size < 0)) { + if(rb_unlikely((int)size < 0)) + { return 0; } @@ -303,14 +339,17 @@ int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) end = buf + size; /* Make sure end is always >= buf */ - if (end < buf) { + if(end < buf) + { end = ((void *)-1); size = end - buf; } - for (; *fmt ; ++fmt) { - if (*fmt != '%') { - if (str < end) + for(; *fmt; ++fmt) + { + if(*fmt != '%') + { + if(str < end) *str = *fmt; ++str; continue; @@ -318,25 +357,38 @@ int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) /* process flags */ flags = 0; - repeat: - ++fmt; /* this also skips first '%' */ - switch (*fmt) { - case '-': flags |= LEFT; goto repeat; - case '+': flags |= PLUS; goto repeat; - case ' ': flags |= SPACE; goto repeat; - case '#': flags |= SPECIAL; goto repeat; - case '0': flags |= ZEROPAD; goto repeat; - } + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } /* get field width */ field_width = -1; - if (isdigit(*fmt)) + if(isdigit(*fmt)) field_width = skip_atoi(&fmt); - else if (*fmt == '*') { + else if(*fmt == '*') + { ++fmt; /* it's the next argument */ field_width = va_arg(args, int); - if (field_width < 0) { + if(field_width < 0) + { field_width = -field_width; flags |= LEFT; } @@ -344,26 +396,30 @@ int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) /* get the precision */ precision = -1; - if (*fmt == '.') { - ++fmt; - if (isdigit(*fmt)) + if(*fmt == '.') + { + ++fmt; + if(isdigit(*fmt)) precision = skip_atoi(&fmt); - else if (*fmt == '*') { + else if(*fmt == '*') + { ++fmt; /* it's the next argument */ precision = va_arg(args, int); } - if (precision < 0) + if(precision < 0) precision = 0; } /* get the conversion qualifier */ qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || - *fmt =='Z' || *fmt == 'z' || *fmt == 't') { + if(*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt == 'Z' || *fmt == 'z' || *fmt == 't') + { qualifier = *fmt; ++fmt; - if (qualifier == 'l' && *fmt == 'l') { + if(qualifier == 'l' && *fmt == 'l') + { qualifier = 'L'; ++fmt; } @@ -372,144 +428,172 @@ int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) /* default base */ base = 10; - switch (*fmt) { - case 'c': - if (!(flags & LEFT)) { - while (--field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - } - c = (unsigned char) va_arg(args, int); - if (str < end) - *str = c; - ++str; - while (--field_width > 0) { - if (str < end) + switch (*fmt) + { + case 'c': + if(!(flags & LEFT)) + { + while(--field_width > 0) + { + if(str < end) *str = ' '; ++str; } - continue; + } + c = (unsigned char)va_arg(args, int); + if(str < end) + *str = c; + ++str; + while(--field_width > 0) + { + if(str < end) + *str = ' '; + ++str; + } + continue; - case 's': - s = va_arg(args, char *); - if (s == NULL) { - abort(); /* prefer blowing up vs corrupt data */ - } - len = rb_strnlen(s, precision); - - if (!(flags & LEFT)) { - while (len < field_width--) { - if (str < end) - *str = ' '; - ++str; - } - } - for (i = 0; i < len; ++i) { - if (str < end) - *str = *s; - ++str; ++s; - } - while (len < field_width--) { - if (str < end) + case 's': + s = va_arg(args, char *); + if(s == NULL) + { + abort(); /* prefer blowing up vs corrupt data */ + } + len = rb_strnlen(s, precision); + + if(!(flags & LEFT)) + { + while(len < field_width--) + { + if(str < end) *str = ' '; ++str; } - continue; + } + for(i = 0; i < len; ++i) + { + if(str < end) + *str = *s; + ++str; + ++s; + } + while(len < field_width--) + { + if(str < end) + *str = ' '; + ++str; + } + continue; - case 'p': - if (field_width == -1) { - field_width = 2*sizeof(void *); - flags |= ZEROPAD; - } - str = number(str, end, - (unsigned long) va_arg(args, void *), - 16, field_width, precision, flags); - continue; - - - case 'n': - /* FIXME: - * What does C99 say about the overflow case here? */ - if (qualifier == 'l') { - long * ip = va_arg(args, long *); - *ip = (str - buf); - } else if (qualifier == 'Z' || qualifier == 'z') { - size_t * ip = va_arg(args, size_t *); - *ip = (str - buf); - } else { - int * ip = va_arg(args, int *); - *ip = (str - buf); - } - continue; + case 'p': + if(field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, end, + (unsigned long)va_arg(args, void *), + 16, field_width, precision, flags); + continue; - case '%': - if (str < end) - *str = '%'; - ++str; - continue; - - /* integer number formats - set up the flags and "break" */ - case 'o': - base = 8; - break; - - case 'X': - flags |= LARGE; - case 'x': - base = 16; - break; - - case 'd': - case 'i': - flags |= SIGN; - case 'u': - break; - - default: - if (str < end) - *str = '%'; + + case 'n': + /* FIXME: + * What does C99 say about the overflow case here? */ + if(qualifier == 'l') + { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } + else if(qualifier == 'Z' || qualifier == 'z') + { + size_t *ip = va_arg(args, size_t *); + *ip = (str - buf); + } + else + { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + if(str < end) + *str = '%'; + ++str; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + if(str < end) + *str = '%'; + ++str; + if(*fmt) + { + if(str < end) + *str = *fmt; ++str; - if (*fmt) { - if (str < end) - *str = *fmt; - ++str; - } else { - --fmt; - } - continue; + } + else + { + --fmt; + } + continue; } - if (qualifier == 'L') + if(qualifier == 'L') num = va_arg(args, long long int); - else if (qualifier == 'l') { + else if(qualifier == 'l') + { num = va_arg(args, unsigned long); - if (flags & SIGN) - num = (signed long) num; - } else if (qualifier == 'Z' || qualifier == 'z') { + if(flags & SIGN) + num = (signed long)num; + } + else if(qualifier == 'Z' || qualifier == 'z') + { num = va_arg(args, size_t); - } else if (qualifier == 't') { + } + else if(qualifier == 't') + { num = va_arg(args, ptrdiff_t); - } else if (qualifier == 'h') { - num = (unsigned short) va_arg(args, int); - if (flags & SIGN) - num = (signed short) num; - } else { + } + else if(qualifier == 'h') + { + num = (unsigned short)va_arg(args, int); + if(flags & SIGN) + num = (signed short)num; + } + else + { num = va_arg(args, unsigned int); - if (flags & SIGN) - num = (signed int) num; + if(flags & SIGN) + num = (signed int)num; } - str = number(str, end, num, base, - field_width, precision, flags); + str = number(str, end, num, base, field_width, precision, flags); } - if (size > 0) { - if (str < end) + if(size > 0) + { + if(str < end) *str = '\0'; else end[-1] = '\0'; } /* the trailing null byte doesn't count towards the total */ - return str-buf; + return str - buf; } /** @@ -524,13 +608,14 @@ int rb_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) * as per ISO C99. If the return is greater than or equal to * @size, the resulting string is truncated. */ -int rb_snprintf(char * buf, size_t size, const char *fmt, ...) +int +rb_snprintf(char *buf, size_t size, const char *fmt, ...) { va_list args; int i; va_start(args, fmt); - i=rb_vsnprintf(buf,size,fmt,args); + i = rb_vsnprintf(buf, size, fmt, args); va_end(args); return i; } @@ -548,7 +633,8 @@ int rb_snprintf(char * buf, size_t size, const char *fmt, ...) * Call this function if you are already dealing with a va_list. * You probably want sprintf() instead. */ -int rb_vsprintf(char *buf, const char *fmt, va_list args) +int +rb_vsprintf(char *buf, const char *fmt, va_list args) { return rb_vsnprintf(buf, INT_MAX, fmt, args); } @@ -563,13 +649,14 @@ int rb_vsprintf(char *buf, const char *fmt, va_list args) * into @buf. Use snprintf() or scnprintf() in order to avoid * buffer overflows. */ -int rb_sprintf(char * buf, const char *fmt, ...) +int +rb_sprintf(char *buf, const char *fmt, ...) { va_list args; int i; va_start(args, fmt); - i=rb_vsnprintf(buf, INT_MAX, fmt, args); + i = rb_vsnprintf(buf, INT_MAX, fmt, args); va_end(args); return i; } @@ -578,12 +665,12 @@ int rb_sprintf(char * buf, const char *fmt, ...) * rb_vsprintf_append() * appends sprintf formatted string to the end of the buffer */ - + int rb_vsprintf_append(char *str, const char *format, va_list ap) { - size_t x = strlen(str); - return(rb_vsprintf(str+x, format, ap) + x); + size_t x = strlen(str); + return (rb_vsprintf(str + x, format, ap) + x); } /* @@ -593,12 +680,12 @@ rb_vsprintf_append(char *str, const char *format, va_list ap) int rb_sprintf_append(char *str, const char *format, ...) { - int x; - va_list ap; - va_start(ap, format); - x = rb_vsprintf_append(str, format, ap); - va_end(ap); - return(x); + int x; + va_list ap; + va_start(ap, format); + x = rb_vsprintf_append(str, format, ap); + va_end(ap); + return (x); } /* @@ -610,8 +697,17 @@ rb_sprintf_append(char *str, const char *format, ...) int rb_vsnprintf_append(char *str, size_t len, const char *format, va_list ap) { - size_t x = strlen(str); - return(rb_vsnprintf(str+x, len - x, format, ap) + x); + size_t x; + if(len == 0) + return 0; + x = strlen(str); + + if(len < x) + { + str[len - 1] = '\0'; + return len - 1; + } + return (rb_vsnprintf(str + x, len - x, format, ap) + x); } /* @@ -623,11 +719,10 @@ rb_vsnprintf_append(char *str, size_t len, const char *format, va_list ap) int rb_snprintf_append(char *str, size_t len, const char *format, ...) { - int x; - va_list ap; - va_start(ap, format); - x = rb_vsnprintf_append(str, len, format, ap); - va_end(ap); - return(x); + int x; + va_list ap; + va_start(ap, format); + x = rb_vsnprintf_append(str, len, format, ap); + va_end(ap); + return (x); } -