Back to index

tetex-bin  3.0
safe_sprintf.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2001,2003 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Thomas E. Dickey <dickey@clark.net> 1997                        *
00031  ****************************************************************************/
00032 
00033 #include <curses.priv.h>
00034 #include <ctype.h>
00035 
00036 MODULE_ID("$Id: safe_sprintf.c,v 1.18 2003/08/09 21:52:04 tom Exp $")
00037 
00038 #if USE_SAFE_SPRINTF
00039 
00040 typedef enum {
00041     Flags, Width, Prec, Type, Format
00042 } PRINTF;
00043 
00044 #define VA_INTGR(type) ival = va_arg(ap, type)
00045 #define VA_FLOAT(type) fval = va_arg(ap, type)
00046 #define VA_POINT(type) pval = (void *)va_arg(ap, type)
00047 
00048 /*
00049  * Scan a variable-argument list for printf to determine the number of
00050  * characters that would be emitted.
00051  */
00052 static int
00053 _nc_printf_length(const char *fmt, va_list ap)
00054 {
00055     size_t length = BUFSIZ;
00056     char *buffer;
00057     char *format;
00058     int len = 0;
00059     size_t fmt_len;
00060     char fmt_arg[BUFSIZ];
00061 
00062     if (fmt == 0 || *fmt == '\0')
00063        return 0;
00064     fmt_len = strlen(fmt) + 1;
00065     if ((format = typeMalloc(char, fmt_len)) == 0)
00066          return -1;
00067     if ((buffer = typeMalloc(char, length)) == 0) {
00068        free(format);
00069        return -1;
00070     }
00071 
00072     while (*fmt != '\0') {
00073        if (*fmt == '%') {
00074            static char dummy[] = "";
00075            PRINTF state = Flags;
00076            char *pval = dummy;     /* avoid const-cast */
00077            double fval = 0.0;
00078            int done = FALSE;
00079            int ival = 0;
00080            int prec = -1;
00081            int type = 0;
00082            int used = 0;
00083            int width = -1;
00084            size_t f = 0;
00085 
00086            format[f++] = *fmt;
00087            while (*++fmt != '\0' && len >= 0 && !done) {
00088               format[f++] = *fmt;
00089 
00090               if (isdigit(UChar(*fmt))) {
00091                   int num = *fmt - '0';
00092                   if (state == Flags && num != 0)
00093                      state = Width;
00094                   if (state == Width) {
00095                      if (width < 0)
00096                          width = 0;
00097                      width = (width * 10) + num;
00098                   } else if (state == Prec) {
00099                      if (prec < 0)
00100                          prec = 0;
00101                      prec = (prec * 10) + num;
00102                   }
00103               } else if (*fmt == '*') {
00104                   VA_INTGR(int);
00105                   if (state == Flags)
00106                      state = Width;
00107                   if (state == Width) {
00108                      width = ival;
00109                   } else if (state == Prec) {
00110                      prec = ival;
00111                   }
00112                   sprintf(fmt_arg, "%d", ival);
00113                   fmt_len += strlen(fmt_arg);
00114                   if ((format = realloc(format, fmt_len)) == 0) {
00115                      return -1;
00116                   }
00117                   strcpy(&format[--f], fmt_arg);
00118                   f = strlen(format);
00119               } else if (isalpha(UChar(*fmt))) {
00120                   done = TRUE;
00121                   switch (*fmt) {
00122                   case 'Z': /* FALLTHRU */
00123                   case 'h': /* FALLTHRU */
00124                   case 'l': /* FALLTHRU */
00125                      done = FALSE;
00126                      type = *fmt;
00127                      break;
00128                   case 'i': /* FALLTHRU */
00129                   case 'd': /* FALLTHRU */
00130                   case 'u': /* FALLTHRU */
00131                   case 'x': /* FALLTHRU */
00132                   case 'X': /* FALLTHRU */
00133                      if (type == 'l')
00134                          VA_INTGR(long);
00135                      else if (type == 'Z')
00136                          VA_INTGR(size_t);
00137                      else
00138                          VA_INTGR(int);
00139                      used = 'i';
00140                      break;
00141                   case 'f': /* FALLTHRU */
00142                   case 'e': /* FALLTHRU */
00143                   case 'E': /* FALLTHRU */
00144                   case 'g': /* FALLTHRU */
00145                   case 'G': /* FALLTHRU */
00146                      VA_FLOAT(double);
00147                      used = 'f';
00148                      break;
00149                   case 'c':
00150                      VA_INTGR(int);
00151                      used = 'i';
00152                      break;
00153                   case 's':
00154                      VA_POINT(char *);
00155                      if (prec < 0)
00156                          prec = strlen(pval);
00157                      if (prec > (int) length) {
00158                          length = length + prec;
00159                          buffer = typeRealloc(char, length, buffer);
00160                          if (buffer == 0) {
00161                             free(format);
00162                             return -1;
00163                          }
00164                      }
00165                      used = 'p';
00166                      break;
00167                   case 'p':
00168                      VA_POINT(void *);
00169                      used = 'p';
00170                      break;
00171                   case 'n':
00172                      VA_POINT(int *);
00173                      used = 0;
00174                      break;
00175                   default:
00176                      break;
00177                   }
00178               } else if (*fmt == '.') {
00179                   state = Prec;
00180               } else if (*fmt == '%') {
00181                   done = TRUE;
00182                   used = 'p';
00183               }
00184            }
00185            format[f] = '\0';
00186            switch (used) {
00187            case 'i':
00188               sprintf(buffer, format, ival);
00189               break;
00190            case 'f':
00191               sprintf(buffer, format, fval);
00192               break;
00193            default:
00194               sprintf(buffer, format, pval);
00195               break;
00196            }
00197            len += (int) strlen(buffer);
00198        } else {
00199            fmt++;
00200            len++;
00201        }
00202     }
00203 
00204     free(buffer);
00205     free(format);
00206     return len;
00207 }
00208 #endif
00209 
00210 /*
00211  * Wrapper for vsprintf that allocates a buffer big enough to hold the result.
00212  */
00213 NCURSES_EXPORT(char *)
00214 _nc_printf_string(const char *fmt, va_list ap)
00215 {
00216     static char *buf;
00217     static size_t used;
00218     char *result = 0;
00219 
00220     if (fmt != 0) {
00221 #if USE_SAFE_SPRINTF
00222        int len = _nc_printf_length(fmt, ap);
00223 
00224        if ((int) used < len + 1) {
00225            used = 2 * (len + 1);
00226            buf = typeRealloc(char, used, buf);
00227        }
00228        if (buf != 0) {
00229            *buf = '\0';
00230            if (len >= 0) {
00231               vsprintf(buf, fmt, ap);
00232            }
00233            result = buf;
00234        }
00235 #else
00236        static int rows, cols;
00237 
00238        if (screen_lines > rows || screen_columns > cols) {
00239            if (screen_lines > rows)
00240               rows = screen_lines;
00241            if (screen_columns > cols)
00242               cols = screen_columns;
00243            used = (rows * (cols + 1)) + 1;
00244            buf = typeRealloc(char, used, buf);
00245        }
00246 
00247        if (buf != 0) {
00248 # if HAVE_VSNPRINTF
00249            vsnprintf(buf, used, fmt, ap); /* GNU extension */
00250 # else
00251            vsprintf(buf, fmt, ap); /* ANSI */
00252 # endif
00253            result = buf;
00254        }
00255 #endif
00256     } else if (buf != 0) {  /* see _nc_freeall() */
00257        free(buf);
00258        buf = 0;
00259        used = 0;
00260     }
00261     return result;
00262 }