Home | History | Annotate | Download | only in cups
      1 /*
      2  * snprintf functions for CUPS.
      3  *
      4  * Copyright 2007-2013 by Apple Inc.
      5  * Copyright 1997-2007 by Easy Software Products.
      6  *
      7  * These coded instructions, statements, and computer programs are the
      8  * property of Apple Inc. and are protected by Federal copyright
      9  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
     10  * which should have been included with this file.  If this file is
     11  * missing or damaged, see the license at "http://www.cups.org/".
     12  *
     13  * This file is subject to the Apple OS-Developed Software exception.
     14  */
     15 
     16 /*
     17  * Include necessary headers...
     18  */
     19 
     20 #include "string-private.h"
     21 
     22 
     23 #ifndef HAVE_VSNPRINTF
     24 /*
     25  * '_cups_vsnprintf()' - Format a string into a fixed size buffer.
     26  */
     27 
     28 int					/* O - Number of bytes formatted */
     29 _cups_vsnprintf(char       *buffer,	/* O - Output buffer */
     30                 size_t     bufsize,	/* O - Size of output buffer */
     31 	        const char *format,	/* I - printf-style format string */
     32 	        va_list    ap)		/* I - Pointer to additional arguments */
     33 {
     34   char		*bufptr,		/* Pointer to position in buffer */
     35 		*bufend,		/* Pointer to end of buffer */
     36 		sign,			/* Sign of format width */
     37 		size,			/* Size character (h, l, L) */
     38 		type;			/* Format type character */
     39   int		width,			/* Width of field */
     40 		prec;			/* Number of characters of precision */
     41   char		tformat[100],		/* Temporary format string for sprintf() */
     42 		*tptr,			/* Pointer into temporary format */
     43 		temp[1024];		/* Buffer for formatted numbers */
     44   size_t	templen;		/* Length of "temp" */
     45   char		*s;			/* Pointer to string */
     46   int		slen;			/* Length of string */
     47   int		bytes;			/* Total number of bytes needed */
     48 
     49 
     50  /*
     51   * Loop through the format string, formatting as needed...
     52   */
     53 
     54   bufptr = buffer;
     55   bufend = buffer + bufsize - 1;
     56   bytes  = 0;
     57 
     58   while (*format)
     59   {
     60     if (*format == '%')
     61     {
     62       tptr = tformat;
     63       *tptr++ = *format++;
     64 
     65       if (*format == '%')
     66       {
     67         if (bufptr && bufptr < bufend) *bufptr++ = *format;
     68         bytes ++;
     69         format ++;
     70 	continue;
     71       }
     72       else if (strchr(" -+#\'", *format))
     73       {
     74         *tptr++ = *format;
     75         sign = *format++;
     76       }
     77       else
     78         sign = 0;
     79 
     80       if (*format == '*')
     81       {
     82        /*
     83         * Get width from argument...
     84 	*/
     85 
     86 	format ++;
     87 	width = va_arg(ap, int);
     88 
     89 	snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
     90 	tptr += strlen(tptr);
     91       }
     92       else
     93       {
     94 	width = 0;
     95 
     96 	while (isdigit(*format & 255))
     97 	{
     98 	  if (tptr < (tformat + sizeof(tformat) - 1))
     99 	    *tptr++ = *format;
    100 
    101 	  width = width * 10 + *format++ - '0';
    102 	}
    103       }
    104 
    105       if (*format == '.')
    106       {
    107 	if (tptr < (tformat + sizeof(tformat) - 1))
    108 	  *tptr++ = *format;
    109 
    110         format ++;
    111 
    112         if (*format == '*')
    113 	{
    114          /*
    115 	  * Get precision from argument...
    116 	  */
    117 
    118 	  format ++;
    119 	  prec = va_arg(ap, int);
    120 
    121 	  snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
    122 	  tptr += strlen(tptr);
    123 	}
    124 	else
    125 	{
    126 	  prec = 0;
    127 
    128 	  while (isdigit(*format & 255))
    129 	  {
    130 	    if (tptr < (tformat + sizeof(tformat) - 1))
    131 	      *tptr++ = *format;
    132 
    133 	    prec = prec * 10 + *format++ - '0';
    134 	  }
    135 	}
    136       }
    137       else
    138         prec = -1;
    139 
    140       if (*format == 'l' && format[1] == 'l')
    141       {
    142         size = 'L';
    143 
    144 	if (tptr < (tformat + sizeof(tformat) - 2))
    145 	{
    146 	  *tptr++ = 'l';
    147 	  *tptr++ = 'l';
    148 	}
    149 
    150 	format += 2;
    151       }
    152       else if (*format == 'h' || *format == 'l' || *format == 'L')
    153       {
    154 	if (tptr < (tformat + sizeof(tformat) - 1))
    155 	  *tptr++ = *format;
    156 
    157         size = *format++;
    158       }
    159 
    160       if (!*format)
    161         break;
    162 
    163       if (tptr < (tformat + sizeof(tformat) - 1))
    164         *tptr++ = *format;
    165 
    166       type  = *format++;
    167       *tptr = '\0';
    168 
    169       switch (type)
    170       {
    171 	case 'E' : /* Floating point formats */
    172 	case 'G' :
    173 	case 'e' :
    174 	case 'f' :
    175 	case 'g' :
    176 	    if ((width + 2) > sizeof(temp))
    177 	      break;
    178 
    179 	    sprintf(temp, tformat, va_arg(ap, double));
    180 	    templen = strlen(temp):
    181 
    182             bytes += (int)templen;
    183 
    184             if (bufptr)
    185 	    {
    186 	      if ((bufptr + templen) > bufend)
    187 	      {
    188 		strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
    189 		bufptr = bufend;
    190 	      }
    191 	      else
    192 	      {
    193 		memcpy(bufptr, temp, templen + 1);
    194 		bufptr += templen;
    195 	      }
    196 	    }
    197 	    break;
    198 
    199         case 'B' : /* Integer formats */
    200 	case 'X' :
    201 	case 'b' :
    202         case 'd' :
    203 	case 'i' :
    204 	case 'o' :
    205 	case 'u' :
    206 	case 'x' :
    207 	    if ((width + 2) > sizeof(temp))
    208 	      break;
    209 
    210 	    sprintf(temp, tformat, va_arg(ap, int));
    211 	    templen = strlen(temp):
    212 
    213             bytes += (int)templen;
    214 
    215 	    if (bufptr)
    216 	    {
    217 	      if ((bufptr + templen) > bufend)
    218 	      {
    219 		strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
    220 		bufptr = bufend;
    221 	      }
    222 	      else
    223 	      {
    224 		memcpy(bufptr, temp, templen + 1);
    225 		bufptr += templen;
    226 	      }
    227 	    }
    228 	    break;
    229 
    230 	case 'p' : /* Pointer value */
    231 	    if ((width + 2) > sizeof(temp))
    232 	      break;
    233 
    234 	    sprintf(temp, tformat, va_arg(ap, void *));
    235 	    templen = strlen(temp):
    236 
    237             bytes += (int)templen;
    238 
    239 	    if (bufptr)
    240 	    {
    241 	      if ((bufptr + templen) > bufend)
    242 	      {
    243 		strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
    244 		bufptr = bufend;
    245 	      }
    246 	      else
    247 	      {
    248 		memcpy(bufptr, temp, templen + 1);
    249 		bufptr += templen;
    250 	      }
    251 	    }
    252 	    break;
    253 
    254         case 'c' : /* Character or character array */
    255 	    bytes += width;
    256 
    257 	    if (bufptr)
    258 	    {
    259 	      if (width <= 1)
    260 	        *bufptr++ = va_arg(ap, int);
    261 	      else
    262 	      {
    263 		if ((bufptr + width) > bufend)
    264 		  width = (int)(bufend - bufptr);
    265 
    266 		memcpy(bufptr, va_arg(ap, char *), (size_t)width);
    267 		bufptr += width;
    268 	      }
    269 	    }
    270 	    break;
    271 
    272 	case 's' : /* String */
    273 	    if ((s = va_arg(ap, char *)) == NULL)
    274 	      s = "(null)";
    275 
    276 	    slen = (int)strlen(s);
    277 	    if (slen > width && prec != width)
    278 	      width = slen;
    279 
    280             bytes += width;
    281 
    282 	    if (bufptr)
    283 	    {
    284 	      if ((bufptr + width) > bufend)
    285 	        width = (int)(bufend - bufptr);
    286 
    287               if (slen > width)
    288 	        slen = width;
    289 
    290 	      if (sign == '-')
    291 	      {
    292 		memcpy(bufptr, s, (size_t)slen);
    293 		memset(bufptr + slen, ' ', (size_t)(width - slen));
    294 	      }
    295 	      else
    296 	      {
    297 		memset(bufptr, ' ', (size_t)(width - slen));
    298 		memcpy(bufptr + width - slen, s, (size_t)slen);
    299 	      }
    300 
    301 	      bufptr += width;
    302 	    }
    303 	    break;
    304 
    305 	case 'n' : /* Output number of chars so far */
    306 	    *(va_arg(ap, int *)) = bytes;
    307 	    break;
    308       }
    309     }
    310     else
    311     {
    312       bytes ++;
    313 
    314       if (bufptr && bufptr < bufend)
    315         *bufptr++ = *format;
    316 
    317       format ++;
    318     }
    319   }
    320 
    321  /*
    322   * Nul-terminate the string and return the number of characters needed.
    323   */
    324 
    325   *bufptr = '\0';
    326 
    327   return (bytes);
    328 }
    329 #endif /* !HAVE_VSNPRINT */
    330 
    331 
    332 #ifndef HAVE_SNPRINTF
    333 /*
    334  * '_cups_snprintf()' - Format a string into a fixed size buffer.
    335  */
    336 
    337 int					/* O - Number of bytes formatted */
    338 _cups_snprintf(char       *buffer,	/* O - Output buffer */
    339                size_t     bufsize,	/* O - Size of output buffer */
    340                const char *format,	/* I - printf-style format string */
    341 	       ...)			/* I - Additional arguments as needed */
    342 {
    343   int		bytes;			/* Number of bytes formatted */
    344   va_list 	ap;			/* Pointer to additional arguments */
    345 
    346 
    347   va_start(ap, format);
    348   bytes = vsnprintf(buffer, bufsize, format, ap);
    349   va_end(ap);
    350 
    351   return (bytes);
    352 }
    353 #endif /* !HAVE_SNPRINTF */
    354