summaryrefslogtreecommitdiff
path: root/vsnprintf.c
diff options
context:
space:
mode:
authorsvn 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
committersvn 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
commit55bf4dbcabf378e9472b7d31d6edf87f6ac853e9 (patch)
tree7a9454ea6b8750256e242cf6d5fba3ca7a4b5044 /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.c518
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;
+}
+
+/*************************************************************************/