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