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