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