diff options
author | svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b <svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-03-28 21:59:56 +0000 |
---|---|---|
committer | svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b <svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-03-28 21:59:56 +0000 |
commit | 55bf4dbcabf378e9472b7d31d6edf87f6ac853e9 (patch) | |
tree | 7a9454ea6b8750256e242cf6d5fba3ca7a4b5044 /vsnprintf.c |
Initial Anope Import
git-svn-id: svn://svn.anope.org/anope/trunk@1 31f1291d-b8d6-0310-a050-a5561fc1590b
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'vsnprintf.c')
-rw-r--r-- | vsnprintf.c | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/vsnprintf.c b/vsnprintf.c new file mode 100644 index 000000000..77d8fd0ac --- /dev/null +++ b/vsnprintf.c @@ -0,0 +1,518 @@ +/* An implementation of vsnprintf() for systems that don't have it. + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * $Id: vsnprintf.c,v 1.5 2003/07/20 01:15:50 dane Exp $ + * + */ + +#include <stdarg.h> +#include <string.h> +#include <ctype.h> + +typedef int (*_pfmt_writefunc_t) + (const char *buf, size_t len, void *arg1, void *arg2); + +int my_vsnprintf(char *string, size_t size, const char *format, + va_list args); + +/*************************************************************************/ + +/* Basic format routine for *printf() interfaces. Takes a writing function + * and two (optional) parameters, one pointer and one integer, for that + * function which are passed on unmodified. The function should return the + * number of bytes written, and 0 (not -1!) on write failure. + */ + +static int _pfmt(const char *format, va_list args, + _pfmt_writefunc_t writefunc, void *arg1, void *arg2) +{ + int total = 0; /* Total bytes written */ + const char *startptr; /* Beginning of non-token text in format string. + * Used for writing in bulk instead of + * character-at-a-time. */ + int n; /* Bytes written in last writefunc() call */ + int valid; /* Was this a valid %-token? */ + int alt_form; /* "Alternate form"? (# flag) */ + int zero_pad; /* Zero-pad value? */ + int left_justify; /* Left-justify? (0 means right-justify) */ + int always_sign; /* Always add sign value? */ + int width; /* Field width */ + int precision; /* Precision */ + int argsize; /* Size of argument: 0=normal, 1=short, 2=long, + * 3=long long */ + int what; /* What are we working on? 0=flags, 1=width, + * 2=precision, 3=argsize, 4=argtype */ + long intval; /* Integer value */ + char *strval; /* String value */ + void *ptrval; /* Pointer value */ + char numbuf[64]; /* Temporary buffer for printing numbers */ + char *numptr; /* Pointer to start of printed number in numbuf */ + + + intval = 0; + strval = NULL; + ptrval = NULL; + + startptr = format; + while (*format) { + if (*format != '%') { + format++; + continue; + } + if (startptr != format) { + /* Write out accumulated text */ + n = writefunc(startptr, format - startptr, arg1, arg2); + total += n; + /* Abort on short write */ + if (n != format - startptr) + break; + /* Point to this token, in case it's a bad one */ + startptr = format; + } + + valid = 0; /* 1 if valid, -1 if known not valid (syntax error) */ + alt_form = 0; + left_justify = 0; + always_sign = 0; + zero_pad = 0; + width = -1; + precision = -1; + argsize = 0; + what = 0; + + while (!valid && *++format) { /* Broken out of by terminal chars */ + switch (*format) { + + /* Flags */ + case '#': + if (what != 0) { + valid = -1; + break; + } + alt_form = 1; + break; + case '-': + if (what != 0) { + valid = -1; + break; + } + left_justify = 1; + break; + case '+': + if (what != 0) { + valid = -1; + break; + } + always_sign = 1; + break; + case '0': + if (what == 0) { + zero_pad = 1; + break; + } + /* else fall through */ + + /* Field widths */ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (what == 0) + what = 1; + else if (what > 2) { + valid = -1; + break; + } + if (what == 1) { + if (width < 0) + width = 0; + width = width * 10 + (*format) - '0'; + } else { + if (precision < 0) + precision = 0; + precision = precision * 10 + (*format) - '0'; + } + break; + case '*': + if (what == 0) + what = 1; + else if (what >= 2) { + valid = -1; + break; + } + if (what == 1) { + width = va_arg(args, int); + if (width < 0) { + width = -width; + left_justify = 1; + } + } else { + precision = va_arg(args, int); + } + break; + case '.': + if (what >= 2) { + valid = -1; + break; + } + what = 2; + break; + + /* Argument sizes */ + case 'h': + if (what > 3) { + valid = -1; + break; + } + argsize = 1; + what = 4; + break; + case 'l': + if (what > 3) { + valid = -1; + break; + } + argsize = 2; + what = 4; + break; + case 'L': + if (what > 3) { + valid = -1; + break; + } + argsize = 3; + what = 4; + break; + + /* Argument types */ + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (argsize == 1) + intval = va_arg(args, short); + else if (argsize == 2) + intval = va_arg(args, long); + else if (argsize == 3) + /* XXX we don't handle long longs yet */ + intval = va_arg(args, long); + else + intval = va_arg(args, int); + valid = 1; + break; + case 'c': + intval = va_arg(args, unsigned char); + valid = 1; + break; + case 's': + strval = va_arg(args, char *); + valid = 1; + break; + case 'p': + ptrval = va_arg(args, void *); + valid = 1; + break; + case 'n': + *((int *) va_arg(args, int *)) = total; + valid = 1; + break; + + /* All other characters--this neatly catches "%%" too */ + default: + valid = -1; + break; + } /* switch (*format) */ + } + if (valid != 1) { + /* Not a valid %-token; start loop over (token will get printed + * out next time through). */ + continue; + } + + /* Don't zero-pad if a precision was given or left-justifying */ + if (precision != -1 || left_justify) + zero_pad = 0; + + /* For numbers, limit precision to the size of the print buffer */ + if ((*format == 'd' || *format == 'i' || *format == 'o' + || *format == 'u' || *format == 'x' || *format == 'X') + && precision > (signed) sizeof(numbuf)) { + precision = sizeof(numbuf); + } + + switch (*format++) { /* Do something with this token */ + case 'p': + /* Print the NULL value specially */ + if (ptrval == NULL) { + total += writefunc("(null)", 6, arg1, arg2); + break; + } + /* For all other values, pretend it's really %#.8x */ + alt_form = 1; + zero_pad = 0; + precision = 8; + intval = (long) ptrval; + /* Fall through */ + + case 'x': + case 'X':{ + static const char x_chars[] = "0123456789abcdef0x"; + static const char X_chars[] = "0123456789ABCDEF0X"; + const char *chars = + (format[-1] == 'X') ? X_chars : x_chars; + const char *padstr = zero_pad ? "0" : " "; + unsigned long uintval; + int len; + + uintval = (unsigned long) intval; + if (alt_form && uintval != 0) { + n = writefunc(chars + 16, 2, arg1, arg2); + total += n; + if (n != 2) + break; + width -= 2; + } + if (precision < 1) + precision = 1; + numptr = numbuf + sizeof(numbuf); + for (len = 0; len < precision || uintval != 0; len++) { + *--numptr = chars[uintval % 16]; + uintval /= 16; + } + if (left_justify) { + n = writefunc(numptr, len, arg1, arg2); + total += n; + if (n != len) + break; + } + while (len < width) { + if (1 != writefunc(padstr, 1, arg1, arg2)) + break; + total++; + width--; + } + if (!left_justify) + total += writefunc(numptr, len, arg1, arg2); + break; + } /* case 'x', 'X' */ + + case 'o':{ + const char *padstr = zero_pad ? "0" : " "; + unsigned long uintval; + int len; + + uintval = (unsigned long) intval; + if (precision < 1) + precision = 1; + numptr = numbuf + sizeof(numbuf); + for (len = 0; len < precision || uintval != 0; len++) { + *--numptr = '0' + uintval % 8; + uintval /= 8; + } + if (alt_form && *numptr != '0') { + *--numptr = '0'; + len++; + } + if (left_justify) { + n = writefunc(numptr, len, arg1, arg2); + total += n; + if (n != len) + break; + } + while (len < width) { + if (1 != writefunc(padstr, 1, arg1, arg2)) + break; + total++; + width--; + } + if (!left_justify) + total += writefunc(numptr, len, arg1, arg2); + break; + } /* case 'o' */ + + if (alt_form && *numptr != '0') + *--numptr = '0'; + case 'u':{ + const char *padstr = zero_pad ? "0" : " "; + unsigned long uintval; + int len; + + uintval = (unsigned long) intval; + if (precision < 1) + precision = 1; + numptr = numbuf + sizeof(numbuf); + for (len = 0; len < precision || uintval != 0; len++) { + *--numptr = '0' + uintval % 10; + uintval /= 10; + } + if (left_justify) { + n = writefunc(numptr, len, arg1, arg2); + total += n; + if (n != len) + break; + } + while (len < width) { + if (1 != writefunc(padstr, 1, arg1, arg2)) + break; + total++; + width--; + } + if (!left_justify) + total += writefunc(numptr, len, arg1, arg2); + break; + } /* case 'u' */ + + case 'd': + case 'i':{ + const char *padstr = zero_pad ? "0" : " "; + int len; + + numptr = numbuf + sizeof(numbuf); + len = 0; + if (intval < 0) { + if (1 != writefunc("-", 1, arg1, arg2)) + break; + total++; + width--; + intval = -intval; + if (intval < 0) { /* true for 0x800...0 */ + *numptr-- = '0' - intval % 10; + len++; + intval /= 10; + intval = -intval; + } + } else if (intval >= 0 && always_sign) { + if (1 != writefunc("+", 1, arg1, arg2)) + break; + total++; + width--; + } + if (precision < 1) + precision = 1; + for (; len < precision || intval != 0; len++) { + *--numptr = '0' + intval % 10; + intval /= 10; + } + if (left_justify) { + n = writefunc(numptr, len, arg1, arg2); + total += n; + if (n != len) + break; + } + while (len < width) { + if (1 != writefunc(padstr, 1, arg1, arg2)) + break; + total++; + width--; + } + if (!left_justify) + total += writefunc(numptr, len, arg1, arg2); + break; + } /* case 'd', 'i' */ + + case 'c':{ + const char *padstr = zero_pad ? "0" : " "; + unsigned char c = (unsigned char) intval; + + if (left_justify) { + if (1 != writefunc(&c, 1, arg1, arg2)) + break; + total++; + } + while (width > 1) { + if (1 != writefunc(padstr, 1, arg1, arg2)) + break; + total++; + width--; + } + if (!left_justify) + total += writefunc(&c, 1, arg1, arg2); + break; + } /* case 'c' */ + + case 's':{ + const char *padstr = zero_pad ? "0" : " "; + int len; + + /* Catch null strings */ + if (strval == NULL) { + total += writefunc("(null)", 6, arg1, arg2); + break; + } + len = strlen(strval); + if (precision < 0 || precision > len) + precision = len; + if (left_justify && len > 0) { + n = writefunc(strval, precision, arg1, arg2); + total += n; + if (n != precision) + break; + } + while (width > precision) { + if (1 != writefunc(padstr, 1, arg1, arg2)) + break; + total++; + width--; + } + if (!left_justify && len > 0) + total += writefunc(strval, precision, arg1, arg2); + break; + } /* case 's' */ + + } /* switch (*format++) */ + + startptr = format; /* Start again after this %-token */ + } /* while (*format) */ + + /* Write anything left over. */ + if (startptr != format) + total += writefunc(startptr, format - startptr, arg1, arg2); + + /* Return total bytes written. */ + return total; +} + +/*************************************************************************/ + +static int writefunc(const char *buf, size_t len, char **string, + size_t * size) +{ + if (*size <= 0) + return 0; + if (len > (*size) - 1) + len = (*size) - 1; + if (len == 0) + return 0; + memcpy(*string, buf, len); + (*string) += len; + (*string)[0] = 0; + return len; +} + +int my_vsnprintf(char *string, size_t size, const char *format, + va_list args) +{ + int ret; + + if (size <= 0) + return 0; + ret = + _pfmt(format, args, (_pfmt_writefunc_t) writefunc, &string, &size); + return ret; +} + +/*************************************************************************/ |