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