1/*
2 * "$Id: snprintf.c 11093 2013-07-03 20:48:42Z msweet $"
3 *
4 *   snprintf functions for CUPS.
5 *
6 *   Copyright 2007-2013 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
35int					/* 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  size_t	templen;		/* Length of "temp" */
52  char		*s;			/* Pointer to string */
53  int		slen;			/* Length of string */
54  int		bytes;			/* Total number of bytes needed */
55
56
57 /*
58  * Loop through the format string, formatting as needed...
59  */
60
61  bufptr = buffer;
62  bufend = buffer + bufsize - 1;
63  bytes  = 0;
64
65  while (*format)
66  {
67    if (*format == '%')
68    {
69      tptr = tformat;
70      *tptr++ = *format++;
71
72      if (*format == '%')
73      {
74        if (bufptr && bufptr < bufend) *bufptr++ = *format;
75        bytes ++;
76        format ++;
77	continue;
78      }
79      else if (strchr(" -+#\'", *format))
80      {
81        *tptr++ = *format;
82        sign = *format++;
83      }
84      else
85        sign = 0;
86
87      if (*format == '*')
88      {
89       /*
90        * Get width from argument...
91	*/
92
93	format ++;
94	width = va_arg(ap, int);
95
96	snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
97	tptr += strlen(tptr);
98      }
99      else
100      {
101	width = 0;
102
103	while (isdigit(*format & 255))
104	{
105	  if (tptr < (tformat + sizeof(tformat) - 1))
106	    *tptr++ = *format;
107
108	  width = width * 10 + *format++ - '0';
109	}
110      }
111
112      if (*format == '.')
113      {
114	if (tptr < (tformat + sizeof(tformat) - 1))
115	  *tptr++ = *format;
116
117        format ++;
118
119        if (*format == '*')
120	{
121         /*
122	  * Get precision from argument...
123	  */
124
125	  format ++;
126	  prec = va_arg(ap, int);
127
128	  snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
129	  tptr += strlen(tptr);
130	}
131	else
132	{
133	  prec = 0;
134
135	  while (isdigit(*format & 255))
136	  {
137	    if (tptr < (tformat + sizeof(tformat) - 1))
138	      *tptr++ = *format;
139
140	    prec = prec * 10 + *format++ - '0';
141	  }
142	}
143      }
144      else
145        prec = -1;
146
147      if (*format == 'l' && format[1] == 'l')
148      {
149        size = 'L';
150
151	if (tptr < (tformat + sizeof(tformat) - 2))
152	{
153	  *tptr++ = 'l';
154	  *tptr++ = 'l';
155	}
156
157	format += 2;
158      }
159      else if (*format == 'h' || *format == 'l' || *format == 'L')
160      {
161	if (tptr < (tformat + sizeof(tformat) - 1))
162	  *tptr++ = *format;
163
164        size = *format++;
165      }
166
167      if (!*format)
168        break;
169
170      if (tptr < (tformat + sizeof(tformat) - 1))
171        *tptr++ = *format;
172
173      type  = *format++;
174      *tptr = '\0';
175
176      switch (type)
177      {
178	case 'E' : /* Floating point formats */
179	case 'G' :
180	case 'e' :
181	case 'f' :
182	case 'g' :
183	    if ((width + 2) > sizeof(temp))
184	      break;
185
186	    sprintf(temp, tformat, va_arg(ap, double));
187	    templen = strlen(temp):
188
189            bytes += (int)templen;
190
191            if (bufptr)
192	    {
193	      if ((bufptr + templen) > bufend)
194	      {
195		strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
196		bufptr = bufend;
197	      }
198	      else
199	      {
200		memcpy(bufptr, temp, templen + 1);
201		bufptr += templen;
202	      }
203	    }
204	    break;
205
206        case 'B' : /* Integer formats */
207	case 'X' :
208	case 'b' :
209        case 'd' :
210	case 'i' :
211	case 'o' :
212	case 'u' :
213	case 'x' :
214	    if ((width + 2) > sizeof(temp))
215	      break;
216
217	    sprintf(temp, tformat, va_arg(ap, int));
218	    templen = strlen(temp):
219
220            bytes += (int)templen;
221
222	    if (bufptr)
223	    {
224	      if ((bufptr + templen) > bufend)
225	      {
226		strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
227		bufptr = bufend;
228	      }
229	      else
230	      {
231		memcpy(bufptr, temp, templen + 1);
232		bufptr += templen;
233	      }
234	    }
235	    break;
236
237	case 'p' : /* Pointer value */
238	    if ((width + 2) > sizeof(temp))
239	      break;
240
241	    sprintf(temp, tformat, va_arg(ap, void *));
242	    templen = strlen(temp):
243
244            bytes += (int)templen;
245
246	    if (bufptr)
247	    {
248	      if ((bufptr + templen) > bufend)
249	      {
250		strlcpy(bufptr, temp, (size_t)(bufend - bufptr));
251		bufptr = bufend;
252	      }
253	      else
254	      {
255		memcpy(bufptr, temp, templen + 1);
256		bufptr += templen;
257	      }
258	    }
259	    break;
260
261        case 'c' : /* Character or character array */
262	    bytes += width;
263
264	    if (bufptr)
265	    {
266	      if (width <= 1)
267	        *bufptr++ = va_arg(ap, int);
268	      else
269	      {
270		if ((bufptr + width) > bufend)
271		  width = (int)(bufend - bufptr);
272
273		memcpy(bufptr, va_arg(ap, char *), (size_t)width);
274		bufptr += width;
275	      }
276	    }
277	    break;
278
279	case 's' : /* String */
280	    if ((s = va_arg(ap, char *)) == NULL)
281	      s = "(null)";
282
283	    slen = (int)strlen(s);
284	    if (slen > width && prec != width)
285	      width = slen;
286
287            bytes += width;
288
289	    if (bufptr)
290	    {
291	      if ((bufptr + width) > bufend)
292	        width = (int)(bufend - bufptr);
293
294              if (slen > width)
295	        slen = width;
296
297	      if (sign == '-')
298	      {
299		memcpy(bufptr, s, (size_t)slen);
300		memset(bufptr + slen, ' ', (size_t)(width - slen));
301	      }
302	      else
303	      {
304		memset(bufptr, ' ', (size_t)(width - slen));
305		memcpy(bufptr + width - slen, s, (size_t)slen);
306	      }
307
308	      bufptr += width;
309	    }
310	    break;
311
312	case 'n' : /* Output number of chars so far */
313	    *(va_arg(ap, int *)) = bytes;
314	    break;
315      }
316    }
317    else
318    {
319      bytes ++;
320
321      if (bufptr && bufptr < bufend)
322        *bufptr++ = *format;
323
324      format ++;
325    }
326  }
327
328 /*
329  * Nul-terminate the string and return the number of characters needed.
330  */
331
332  *bufptr = '\0';
333
334  return (bytes);
335}
336#endif /* !HAVE_VSNPRINT */
337
338
339#ifndef HAVE_SNPRINTF
340/*
341 * '_cups_snprintf()' - Format a string into a fixed size buffer.
342 */
343
344int					/* O - Number of bytes formatted */
345_cups_snprintf(char       *buffer,	/* O - Output buffer */
346               size_t     bufsize,	/* O - Size of output buffer */
347               const char *format,	/* I - printf-style format string */
348	       ...)			/* I - Additional arguments as needed */
349{
350  int		bytes;			/* Number of bytes formatted */
351  va_list 	ap;			/* Pointer to additional arguments */
352
353
354  va_start(ap, format);
355  bytes = vsnprintf(buffer, bufsize, format, ap);
356  va_end(ap);
357
358  return (bytes);
359}
360#endif /* !HAVE_SNPRINTF */
361
362
363/*
364 * End of "$Id: snprintf.c 11093 2013-07-03 20:48:42Z msweet $".
365 */
366
367