fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

vsnprintf.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: vsnprintf.c 7903 2010-11-28 21:06:39Z matt $"
00003  *
00004  * snprintf() and vsnprintf() functions for the Fast Light Tool Kit (FLTK).
00005  *
00006  * Copyright 1998-2010 by Bill Spitzak and others.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Library General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Library General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Library General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021  * USA.
00022  *
00023  * Please report all bugs and problems on the following page:
00024  *
00025  *     http://www.fltk.org/str.php
00026  */
00027 
00028 #include <stdio.h>
00029 #include "flstring.h"
00030 
00031 #ifdef HAVE_SYS_STDTYPES_H
00032 #  include <sys/stdtypes.h>
00033 #endif /* HAVE_SYS_STDTYPES_H */
00034 
00035 #ifdef __cplusplus
00036 extern "C" {
00037 #endif
00038 
00039 int fl_vsnprintf(char* buffer, size_t bufsize, const char* format, va_list ap) {
00040   char          *bufptr,                /* Pointer to position in buffer */
00041                 *bufend,                /* Pointer to end of buffer */
00042                 sign,                   /* Sign of format width */
00043                 size,                   /* Size character (h, l, L) */
00044                 type;                   /* Format type character */
00045   int           width,                  /* Width of field */
00046                 prec;                   /* Number of characters of precision */
00047   char          tformat[100],           /* Temporary format string for sprintf() */
00048                 *tptr,                  /* Pointer into temporary format */
00049                 temp[1024];             /* Buffer for formatted numbers */
00050   char          *s;                     /* Pointer to string */
00051   int           slen;                   /* Length of string */
00052   int           bytes;                  /* Total number of bytes needed */
00053 
00054 
00055  /*
00056   * Loop through the format string, formatting as needed...
00057   */
00058 
00059   bufptr = buffer;
00060   bufend = buffer + bufsize - 1;
00061   bytes  = 0;
00062 
00063   while (*format) {
00064     if (*format == '%') {
00065       tptr = tformat;
00066       *tptr++ = *format++;
00067 
00068       if (*format == '%') {
00069         if (bufptr && bufptr < bufend) *bufptr++ = *format;
00070         bytes ++;
00071         format ++;
00072         continue;
00073       } else if (strchr(" -+#\'", *format)) {
00074         *tptr++ = *format;
00075         sign = *format++;
00076       } else sign = 0;
00077 
00078       if (*format == '*') {
00079         /* Get width from argument... */
00080         format ++;
00081         width = va_arg(ap, int);
00082         snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
00083         tptr += strlen(tptr);
00084       } else {
00085         width = 0;
00086         while (isdigit(*format & 255)) {
00087           if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
00088           width = width * 10 + *format++ - '0';
00089         }
00090       }
00091 
00092       if (*format == '.') {
00093         if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
00094         format ++;
00095 
00096         if (*format == '*') {
00097           /* Get precision from argument... */
00098           format ++;
00099           prec = va_arg(ap, int);
00100           snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
00101           tptr += strlen(tptr);
00102         } else {
00103           prec = 0;
00104           while (isdigit(*format & 255)) {
00105             if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
00106             prec = prec * 10 + *format++ - '0';
00107           }
00108         }
00109       } else prec = -1;
00110 
00111       size = '\0';
00112 
00113       if (*format == 'l' && format[1] == 'l') {
00114         size = 'L';
00115         if (tptr < (tformat + sizeof(tformat) - 2)) {
00116           *tptr++ = 'l';
00117           *tptr++ = 'l';
00118         }
00119         format += 2;
00120       } else if (*format == 'h' || *format == 'l' || *format == 'L') {
00121         if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
00122         size = *format++;
00123       }
00124 
00125       if (!*format) break;
00126 
00127       if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format;
00128       type  = *format++;
00129       *tptr = '\0';
00130 
00131       switch (type) {
00132         case 'E' : /* Floating point formats */
00133         case 'G' :
00134         case 'e' :
00135         case 'f' :
00136         case 'g' :
00137           if ((width + 2) > sizeof(temp)) break;
00138 
00139           sprintf(temp, tformat, va_arg(ap, double));
00140 
00141           bytes += strlen(temp);
00142 
00143           if (bufptr) {
00144             if ((bufptr + strlen(temp)) > bufend) {
00145               strncpy(bufptr, temp, (size_t)(bufend - bufptr));
00146               bufptr = bufend;
00147             } else {
00148               strcpy(bufptr, temp);
00149               bufptr += strlen(temp);
00150             }
00151           }
00152           break;
00153 
00154         case 'B' : /* Integer formats */
00155         case 'X' :
00156         case 'b' :
00157         case 'd' :
00158         case 'i' :
00159         case 'o' :
00160         case 'u' :
00161         case 'x' :
00162           if ((width + 2) > sizeof(temp)) break;
00163 
00164 #ifdef HAVE_LONG_LONG
00165           if (size == 'L')
00166             sprintf(temp, tformat, va_arg(ap, long long));
00167           else
00168 #endif /* HAVE_LONG_LONG */
00169           if (size == 'l')
00170             sprintf(temp, tformat, va_arg(ap, long));
00171           else
00172             sprintf(temp, tformat, va_arg(ap, int));
00173 
00174           bytes += strlen(temp);
00175 
00176           if (bufptr) {
00177             if ((bufptr + strlen(temp)) > bufend) {
00178               strncpy(bufptr, temp, (size_t)(bufend - bufptr));
00179               bufptr = bufend;
00180             } else {
00181               strcpy(bufptr, temp);
00182               bufptr += strlen(temp);
00183             }
00184           }
00185           break;
00186             
00187         case 'p' : /* Pointer value */
00188           if ((width + 2) > sizeof(temp)) break;
00189 
00190           sprintf(temp, tformat, va_arg(ap, void *));
00191 
00192           bytes += strlen(temp);
00193 
00194           if (bufptr) {
00195             if ((bufptr + strlen(temp)) > bufend) {
00196               strncpy(bufptr, temp, (size_t)(bufend - bufptr));
00197               bufptr = bufend;
00198             } else {
00199               strcpy(bufptr, temp);
00200               bufptr += strlen(temp);
00201             }
00202           }
00203           break;
00204 
00205         case 'c' : /* Character or character array */
00206           bytes += width;
00207 
00208           if (bufptr) {
00209             if (width <= 1) *bufptr++ = va_arg(ap, int);
00210             else {
00211               if ((bufptr + width) > bufend) width = bufend - bufptr;
00212 
00213               memcpy(bufptr, va_arg(ap, char *), (size_t)width);
00214               bufptr += width;
00215             }
00216           }
00217           break;
00218 
00219         case 's' : /* String */
00220           if ((s = va_arg(ap, char *)) == NULL) s = "(null)";
00221 
00222           slen = strlen(s);
00223           if (slen > width && prec != width) width = slen;
00224 
00225           bytes += width;
00226 
00227           if (bufptr) {
00228             if ((bufptr + width) > bufend) width = bufend - bufptr;
00229 
00230             if (slen > width) slen = width;
00231 
00232             if (sign == '-') {
00233               strncpy(bufptr, s, (size_t)slen);
00234               memset(bufptr + slen, ' ', (size_t)(width - slen));
00235             } else {
00236               memset(bufptr, ' ', (size_t)(width - slen));
00237               strncpy(bufptr + width - slen, s, (size_t)slen);
00238             }
00239 
00240             bufptr += width;
00241           }
00242           break;
00243 
00244         case 'n' : /* Output number of chars so far */
00245           *(va_arg(ap, int *)) = bytes;
00246           break;
00247       }
00248     } else {
00249       bytes ++;
00250 
00251       if (bufptr && bufptr < bufend) *bufptr++ = *format;
00252       format ++;
00253     }
00254   }
00255 
00256  /*
00257   * Nul-terminate the string and return the number of characters needed.
00258   */
00259 
00260   if (bufptr) *bufptr = '\0';
00261 
00262   return (bytes);
00263 }
00264 
00265 int fl_snprintf(char* str, size_t size, const char* fmt, ...) {
00266   int ret;
00267   va_list ap;
00268   va_start(ap, fmt);
00269   ret = vsnprintf(str, size, fmt, ap);
00270   va_end(ap);
00271   return ret;
00272 }
00273 
00274 #ifdef __cplusplus
00275 }
00276 #endif
00277 
00278 /*
00279  * End of "$Id: vsnprintf.c 7903 2010-11-28 21:06:39Z matt $".
00280  */
00281