From 558958ad23a305d43a52589ca651a18dcc09aa0b Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Sun, 10 Apr 2005 22:14:08 +0000 Subject: [PATCH] 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 --- CHANGES | 2 + src/flstring.c | 6 +- src/flstring.h | 8 +- src/vsnprintf.c | 287 ++++++++++++++++++++++++++++++++++-------------- 4 files changed, 215 insertions(+), 88 deletions(-) diff --git a/CHANGES b/CHANGES index e75e68131..db73b102b 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,8 @@ CHANGES IN FLTK 1.1.7 - Documentation fixes (STR #648, STR #692, STR #730, STR #744, STR #745) + - The FLTK string functions are now compiled in on all + systems (STR #774) - Fixed symbol demo label bug (STR #777) - Fixed position of menu titles (STR #795) - Added missing Fl_Window::copy_label() method. 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,76 +34,219 @@ 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; + + /* + * Nul-terminate the string and return the number of characters needed. + */ + + if (bufptr) *bufptr = '\0'; + + return (bytes); } -#endif - -#if !HAVE_SNPRINTF - int fl_snprintf(char* str, size_t size, const char* fmt, ...) { int ret; va_list ap; @@ -127,8 +256,6 @@ int fl_snprintf(char* str, size_t size, const char* fmt, ...) { return ret; } -#endif - #ifdef __cplusplus } #endif