summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>2005-04-10 22:14:08 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>2005-04-10 22:14:08 +0000
commit558958ad23a305d43a52589ca651a18dcc09aa0b (patch)
treea8a15ce13e7913cdb46fe4e621e288486227d292 /src
parent5b20fbdce435bf8a367c06400d0119810ad71d20 (diff)
The FLTK string functions are now compiled in on all systems (STR
#774) src/vsnprintf.c: - Replaced fl_vsnprintf() implementation with one that properly emulates the vsnprintf() function. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4262 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src')
-rw-r--r--src/flstring.c6
-rw-r--r--src/flstring.h8
-rw-r--r--src/vsnprintf.c285
3 files changed, 212 insertions, 87 deletions
diff --git a/src/flstring.c b/src/flstring.c
index ce6967d18..269dbdad7 100644
--- a/src/flstring.c
+++ b/src/flstring.c
@@ -25,7 +25,7 @@
#include "flstring.h"
-# if !HAVE_STRLCAT
+
/*
* 'fl_strlcat()' - Safely concatenate two strings.
*/
@@ -64,9 +64,8 @@ fl_strlcat(char *dst, /* O - Destination string */
return (dstlen + srclen);
}
-# endif /* !HAVE_STRLCAT */
-# if !HAVE_STRLCPY
+
/*
* 'fl_strlcpy()' - Safely copy two strings.
*/
@@ -97,7 +96,6 @@ fl_strlcpy(char *dst, /* O - Destination string */
return (srclen);
}
-# endif /* !HAVE_STRLCPY */
/*
diff --git a/src/flstring.h b/src/flstring.h
index 82f54850c..24fd69e06 100644
--- a/src/flstring.h
+++ b/src/flstring.h
@@ -69,13 +69,13 @@ int strncasecmp(const char*,const char*,int);
char *strdup(const char*);
# endif
-# if !HAVE_SNPRINTF
FL_EXPORT extern int fl_snprintf(char *, size_t, const char *, ...);
+# if !HAVE_SNPRINTF
# define snprintf fl_snprintf
# endif /* !HAVE_SNPRINTF */
-# if !HAVE_VSNPRINTF
FL_EXPORT extern int fl_vsnprintf(char *, size_t, const char *, va_list ap);
+# if !HAVE_VSNPRINTF
# define vsnprintf fl_vsnprintf
# endif /* !HAVE_VSNPRINTF */
@@ -84,13 +84,13 @@ FL_EXPORT extern int fl_vsnprintf(char *, size_t, const char *, va_list ap);
* that work the way strncpy() and strncat() *should* have worked.
*/
-# if !HAVE_STRLCAT
FL_EXPORT extern size_t fl_strlcat(char *, const char *, size_t);
+# if !HAVE_STRLCAT
# define strlcat fl_strlcat
# endif /* !HAVE_STRLCAT */
-# if !HAVE_STRLCPY
FL_EXPORT extern size_t fl_strlcpy(char *, const char *, size_t);
+# if !HAVE_STRLCPY
# define strlcpy fl_strlcpy
# endif /* !HAVE_STRLCPY */
diff --git a/src/vsnprintf.c b/src/vsnprintf.c
index 9038bbbca..96a8b85a6 100644
--- a/src/vsnprintf.c
+++ b/src/vsnprintf.c
@@ -1,21 +1,7 @@
/*
* "$Id$"
*
- * vsnprintf() function for the Fast Light Tool Kit (FLTK).
- *
- * Emulates this call on systems that lack it (pretty much everything
- * except glibc systems).
- *
- * KNOWN BUGS:
- *
- * Field width & Precision is ignored for %%, %c, and %s.
- *
- * A malicious user who manages to create a %-fmt string that prints
- * more than 99 characters can still overflow the temporary buffer.
- * For instance %110f will overflow.
- *
- * Only handles formats that are both documented in the glibc man page
- * for printf and also handled by your system's sprintf().
+ * snprintf() and vsnprintf() functions for the Fast Light Tool Kit (FLTK).
*
* Copyright 1998-2005 by Bill Spitzak and others.
*
@@ -48,75 +34,218 @@
extern "C" {
#endif
-#if !HAVE_VSNPRINTF
+int fl_vsnprintf(char* buffer, size_t bufsize, const char* format, va_list ap) {
+ char *bufptr, /* Pointer to position in buffer */
+ *bufend, /* Pointer to end of buffer */
+ sign, /* Sign of format width */
+ size, /* Size character (h, l, L) */
+ type; /* Format type character */
+ const char *bufformat; /* Start of format */
+ int width, /* Width of field */
+ prec; /* Number of characters of precision */
+ char tformat[100], /* Temporary format string for sprintf() */
+ temp[1024]; /* Buffer for formatted numbers */
+ char *s; /* Pointer to string */
+ int slen; /* Length of string */
+ int bytes; /* Total number of bytes needed */
-int fl_vsnprintf(char* str, size_t size, const char* fmt, va_list ap) {
- const char* e = str+size-1;
- char* p = str;
- char copy[20];
- char* copy_p;
- char sprintf_out[100];
- while (*fmt && p < e) {
- if (*fmt != '%') {
- *p++ = *fmt++;
- } else {
- fmt++;
- copy[0] = '%';
- for (copy_p = copy+1; copy_p < copy+19;) {
- switch ((*copy_p++ = *fmt++)) {
- case 0:
- fmt--; goto CONTINUE;
- case '%':
- *p++ = '%'; goto CONTINUE;
- case 'c':
- *p++ = va_arg(ap, int);
- goto CONTINUE;
- case 'd':
- case 'i':
- case 'o':
- case 'u':
- case 'x':
- case 'X':
- *copy_p = 0;
- sprintf(sprintf_out, copy, va_arg(ap, int));
- copy_p = sprintf_out;
- goto DUP;
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- *copy_p = 0;
- sprintf(sprintf_out, copy, va_arg(ap, double));
- copy_p = sprintf_out;
- goto DUP;
- case 'p':
- *copy_p = 0;
- sprintf(sprintf_out, copy, va_arg(ap, void*));
- copy_p = sprintf_out;
- goto DUP;
- case 'n':
- *(va_arg(ap, int*)) = p-str;
- goto CONTINUE;
- case 's':
- copy_p = va_arg(ap, char*);
- if (!copy_p) copy_p = "NULL";
- DUP:
- while (*copy_p && p < e) *p++ = *copy_p++;
- goto CONTINUE;
- }
+ /*
+ * Loop through the format string, formatting as needed...
+ */
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+ bytes = 0;
+
+ while (*format) {
+ if (*format == '%') {
+ bufformat = format;
+ format ++;
+
+ if (*format == '%') {
+ *bufptr++ = *format++;
+ continue;
+ } else if (strchr(" -+#\'", *format)) sign = *format++;
+ else sign = 0;
+
+ width = 0;
+ while (isdigit(*format)) width = width * 10 + *format++ - '0';
+
+ if (*format == '.') {
+ format ++;
+ prec = 0;
+
+ while (isdigit(*format)) prec = prec * 10 + *format++ - '0';
+ } else prec = -1;
+
+ if (*format == 'l' && format[1] == 'l') {
+ size = 'L';
+ format += 2;
+ } else if (*format == 'h' || *format == 'l' || *format == 'L') size = *format++;
+
+ if (!*format) break;
+
+ type = *format++;
+
+ switch (type) {
+ case 'E' : /* Floating point formats */
+ case 'G' :
+ case 'e' :
+ case 'f' :
+ case 'g' :
+ if ((format - bufformat + 1) > sizeof(tformat) ||
+ (width + 2) > sizeof(temp)) break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ sprintf(temp, tformat, va_arg(ap, double));
+
+ bytes += strlen(temp);
+
+ if (bufptr) {
+ if ((bufptr + strlen(temp)) > bufend) {
+ strncpy(bufptr, temp, bufend - bufptr);
+ bufptr = bufend;
+ break;
+ } else {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'B' : /* Integer formats */
+ case 'X' :
+ case 'b' :
+ case 'd' :
+ case 'i' :
+ case 'o' :
+ case 'u' :
+ case 'x' :
+ if ((format - bufformat + 1) > sizeof(tformat) ||
+ (width + 2) > sizeof(temp)) break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ bytes += strlen(temp);
+
+ if (bufptr) {
+ if ((bufptr + strlen(temp)) > bufend) {
+ strncpy(bufptr, temp, bufend - bufptr);
+ bufptr = bufend;
+ break;
+ } else {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'p' : /* Pointer value */
+ if ((format - bufformat + 1) > sizeof(tformat) ||
+ (width + 2) > sizeof(temp)) break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ sprintf(temp, tformat, va_arg(ap, void *));
+
+ bytes += strlen(temp);
+
+ if (bufptr) {
+ if ((bufptr + strlen(temp)) > bufend) {
+ strncpy(bufptr, temp, bufend - bufptr);
+ bufptr = bufend;
+ break;
+ } else {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
+
+ case 'c' : /* Character or character array */
+ bytes += width;
+
+ if (bufptr) {
+ if (width <= 1) *bufptr++ = va_arg(ap, int);
+ else {
+ if ((bufptr + width) > bufend) width = bufend - bufptr;
+
+ memcpy(bufptr, va_arg(ap, char *), width);
+ bufptr += width;
+ }
+ }
+ break;
+
+ case 's' : /* String */
+ if ((s = va_arg(ap, char *)) == NULL) s = "(null)";
+
+ slen = strlen(s);
+ if (slen > width && prec != width) width = slen;
+
+ bytes += width;
+
+ if (bufptr) {
+ if ((bufptr + width) > bufend) width = bufend - bufptr;
+
+ if (slen > width) slen = width;
+
+ if (sign == '-') {
+ strncpy(bufptr, s, slen);
+ memset(bufptr + slen, ' ', width - slen);
+ } else {
+ memset(bufptr, ' ', width - slen);
+ strncpy(bufptr + width - slen, s, slen);
+ }
+
+ bufptr += width;
+ }
+ break;
+
+ case 'n' : /* Output number of chars so far */
+ if ((format - bufformat + 1) > sizeof(tformat) ||
+ (width + 2) > sizeof(temp)) break;
+
+ strncpy(tformat, bufformat, format - bufformat);
+ tformat[format - bufformat] = '\0';
+
+ sprintf(temp, tformat, va_arg(ap, int));
+
+ bytes += strlen(temp);
+
+ if (bufptr) {
+ if ((bufptr + strlen(temp)) > bufend) {
+ strncpy(bufptr, temp, bufend - bufptr);
+ bufptr = bufend;
+ break;
+ } else {
+ strcpy(bufptr, temp);
+ bufptr += strlen(temp);
+ }
+ }
+ break;
}
+ } else {
+ bytes ++;
+
+ if (bufptr && bufptr < bufend) *bufptr++ = *format++;
}
- CONTINUE:;
}
- *p = 0;
- if (*fmt) return -1;
- return p-str;
-}
-#endif
+ /*
+ * Nul-terminate the string and return the number of characters needed.
+ */
+
+ if (bufptr) *bufptr = '\0';
-#if !HAVE_SNPRINTF
+ return (bytes);
+}
int fl_snprintf(char* str, size_t size, const char* fmt, ...) {
int ret;
@@ -127,8 +256,6 @@ int fl_snprintf(char* str, size_t size, const char* fmt, ...) {
return ret;
}
-#endif
-
#ifdef __cplusplus
}
#endif