/src/gstreamer/subprojects/gstreamer/gst/printf/vasnprintf.c
Line | Count | Source |
1 | | /* vsprintf with automatic memory allocation. |
2 | | Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc. |
3 | | |
4 | | This program is free software; you can redistribute it and/or modify it |
5 | | under the terms of the GNU Library General Public License as published |
6 | | by the Free Software Foundation; either version 2, or (at your option) |
7 | | any later version. |
8 | | |
9 | | This program is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | | Library General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU Library General Public |
15 | | License along with this program; if not, write to the Free Software |
16 | | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
17 | | USA. */ |
18 | | |
19 | | #ifndef _WIN32 |
20 | | /* Tell glibc's <stdio.h> to provide a prototype for snprintf(). |
21 | | This must come before <config.h> because <config.h> may include |
22 | | <features.h>, and once <features.h> has been included, it's too late. */ |
23 | | #ifndef _GNU_SOURCE |
24 | | # define _GNU_SOURCE 1 |
25 | | #endif |
26 | | #endif |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | # include <config.h> |
30 | | #endif |
31 | | |
32 | | #include "gst-printf.h" |
33 | | |
34 | | /* Specification. */ |
35 | | #include "vasnprintf.h" |
36 | | |
37 | | #include <stdio.h> /* snprintf(), sprintf() */ |
38 | | #include <stdlib.h> /* abort(), malloc(), realloc(), free() */ |
39 | | #include <string.h> /* memcpy(), strlen() */ |
40 | | #include <errno.h> /* errno */ |
41 | | #include <limits.h> /* CHAR_BIT */ |
42 | | #include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */ |
43 | | #include "printf-parse.h" |
44 | | #include "printf-extension.h" |
45 | | |
46 | | #ifdef HAVE_WCHAR_T |
47 | | # ifdef HAVE_WCSLEN |
48 | | # define local_wcslen wcslen |
49 | | # else |
50 | | /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid |
51 | | a dependency towards this library, here is a local substitute. |
52 | | Define this substitute only once, even if this file is included |
53 | | twice in the same compilation unit. */ |
54 | | # ifndef local_wcslen_defined |
55 | | # define local_wcslen_defined 1 |
56 | | static size_t |
57 | | local_wcslen (const wchar_t *s) |
58 | | { |
59 | | const wchar_t *ptr; |
60 | | |
61 | | for (ptr = s; *ptr != (wchar_t) 0; ptr++); |
62 | | return ptr - s; |
63 | | } |
64 | | # endif |
65 | | # endif |
66 | | #endif |
67 | | |
68 | | /* For those losing systems which don't have 'alloca' we have to add |
69 | | some additional code emulating it. */ |
70 | | #if defined (alloca) || defined (GLIB_HAVE_ALLOCA_H) |
71 | | # define freea(p) /* nothing */ |
72 | | #else |
73 | | # define alloca(n) malloc (n) |
74 | | # define freea(p) free (p) |
75 | | #endif |
76 | | |
77 | | #ifndef HAVE_LONG_LONG_FORMAT |
78 | | static inline int |
79 | | print_long_long (char *buf, |
80 | | int len, |
81 | | int width, |
82 | | int precision, |
83 | | unsigned long flags, char conversion, unsigned long long number) |
84 | 0 | { |
85 | 0 | int negative = FALSE; |
86 | 0 | char buffer[128]; |
87 | 0 | char *bufferend; |
88 | 0 | char *pointer; |
89 | 0 | int base; |
90 | 0 | static const char *upper = "0123456789ABCDEFX"; |
91 | 0 | static const char *lower = "0123456789abcdefx"; |
92 | 0 | const char *digits; |
93 | 0 | int i; |
94 | 0 | char *p; |
95 | 0 | int count; |
96 | |
|
97 | 0 | #define EMIT(c) \ |
98 | 0 | if (p - buf == len - 1) \ |
99 | 0 | { \ |
100 | 0 | *p++ = '\0'; \ |
101 | 0 | return len; \ |
102 | 0 | } \ |
103 | 0 | else \ |
104 | 0 | *p++ = c; |
105 | |
|
106 | 0 | p = buf; |
107 | |
|
108 | 0 | switch (conversion) { |
109 | 0 | case 'o': |
110 | 0 | base = 8; |
111 | 0 | digits = lower; |
112 | 0 | negative = FALSE; |
113 | 0 | break; |
114 | 0 | case 'x': |
115 | 0 | base = 16; |
116 | 0 | digits = lower; |
117 | 0 | negative = FALSE; |
118 | 0 | break; |
119 | 0 | case 'X': |
120 | 0 | base = 16; |
121 | 0 | digits = upper; |
122 | 0 | negative = FALSE; |
123 | 0 | break; |
124 | 0 | case 'u': |
125 | 0 | base = 10; |
126 | 0 | digits = lower; |
127 | 0 | negative = FALSE; |
128 | 0 | break; |
129 | 0 | default: |
130 | 0 | base = 10; |
131 | 0 | digits = lower; |
132 | 0 | negative = (long long) number < 0; |
133 | 0 | if (negative) |
134 | 0 | number = -((long long) number); |
135 | 0 | break; |
136 | 0 | } |
137 | | |
138 | | /* Build number */ |
139 | 0 | pointer = bufferend = &buffer[sizeof (buffer) - 1]; |
140 | 0 | *pointer-- = '\0'; |
141 | 0 | for (i = 1; i < (int) sizeof (buffer); i++) { |
142 | 0 | *pointer-- = digits[number % base]; |
143 | 0 | number /= base; |
144 | 0 | if (number == 0) |
145 | 0 | break; |
146 | 0 | } |
147 | | |
148 | | /* Adjust width */ |
149 | 0 | width -= (bufferend - pointer) - 1; |
150 | | |
151 | | /* Adjust precision */ |
152 | 0 | if (precision != -1) { |
153 | 0 | precision -= (bufferend - pointer) - 1; |
154 | 0 | if (precision < 0) |
155 | 0 | precision = 0; |
156 | 0 | flags |= FLAG_ZERO; |
157 | 0 | } |
158 | | |
159 | | /* Adjust width further */ |
160 | 0 | if (negative || (flags & FLAG_SHOWSIGN) || (flags & FLAG_SPACE)) |
161 | 0 | width--; |
162 | 0 | if (flags & FLAG_ALT) { |
163 | 0 | switch (base) { |
164 | 0 | case 16: |
165 | 0 | width -= 2; |
166 | 0 | break; |
167 | 0 | case 8: |
168 | 0 | width--; |
169 | 0 | break; |
170 | 0 | default: |
171 | 0 | break; |
172 | 0 | } |
173 | 0 | } |
174 | | |
175 | | /* Output prefixes spaces if needed */ |
176 | 0 | if (!((flags & FLAG_LEFT) || ((flags & FLAG_ZERO) && (precision == -1)))) { |
177 | 0 | count = (precision == -1) ? 0 : precision; |
178 | 0 | while (width-- > count) |
179 | 0 | *p++ = ' '; |
180 | 0 | } |
181 | | |
182 | | /* width has been adjusted for signs and alternatives */ |
183 | 0 | if (negative) { |
184 | 0 | EMIT ('-'); |
185 | 0 | } else if (flags & FLAG_SHOWSIGN) { |
186 | 0 | EMIT ('+'); |
187 | 0 | } else if (flags & FLAG_SPACE) { |
188 | 0 | EMIT (' '); |
189 | 0 | } |
190 | | |
191 | 0 | if (flags & FLAG_ALT) { |
192 | 0 | switch (base) { |
193 | 0 | case 8: |
194 | 0 | EMIT ('0'); |
195 | 0 | break; |
196 | 0 | case 16: |
197 | 0 | EMIT ('0'); |
198 | 0 | EMIT (digits[16]); |
199 | 0 | break; |
200 | 0 | default: |
201 | 0 | break; |
202 | 0 | } /* switch base */ |
203 | 0 | } |
204 | | |
205 | | /* Output prefixed zero padding if needed */ |
206 | 0 | if (flags & FLAG_ZERO) { |
207 | 0 | if (precision == -1) |
208 | 0 | precision = width; |
209 | 0 | while (precision-- > 0) { |
210 | 0 | EMIT ('0'); |
211 | 0 | width--; |
212 | 0 | } |
213 | 0 | } |
214 | | |
215 | | /* Output the number itself */ |
216 | 0 | while (*(++pointer)) { |
217 | 0 | EMIT (*pointer); |
218 | 0 | } |
219 | | |
220 | | /* Output trailing spaces if needed */ |
221 | 0 | if (flags & FLAG_LEFT) { |
222 | 0 | while (width-- > 0) |
223 | 0 | EMIT (' '); |
224 | 0 | } |
225 | | |
226 | 0 | EMIT ('\0'); |
227 | |
|
228 | 0 | return p - buf - 1; |
229 | 0 | } |
230 | | #endif |
231 | | |
232 | | static void |
233 | | printf_postprocess_args (char_directives * directives, arguments * arguments) |
234 | 67.4k | { |
235 | 67.4k | int i; |
236 | | |
237 | 92.2k | for (i = 0; i < directives->count; ++i) { |
238 | 24.7k | char_directive *dp; |
239 | 24.7k | argument *a; |
240 | | |
241 | 24.7k | dp = &directives->dir[i]; |
242 | | |
243 | | /* %% has no arguments, for example */ |
244 | 24.7k | if (dp->arg_index < 0) |
245 | 0 | continue; |
246 | | |
247 | 24.7k | a = &arguments->arg[dp->arg_index]; |
248 | | |
249 | 24.7k | if (a->type == TYPE_POINTER_EXT) { |
250 | 1.16k | char fmt[4]; |
251 | | |
252 | 1.16k | fmt[0] = 'p'; |
253 | 1.16k | fmt[1] = POINTER_EXT_SIGNIFIER_CHAR; |
254 | 1.16k | fmt[2] = dp->ptr_ext_char; |
255 | 1.16k | fmt[3] = '\0'; |
256 | | |
257 | 1.16k | a->ext_string = |
258 | 1.16k | __gst_printf_pointer_extension_serialize (fmt, a->a.a_pointer); |
259 | 1.16k | } |
260 | 24.7k | } |
261 | 67.4k | } |
262 | | |
263 | | static gboolean |
264 | | gather_logging_arguments (const char *format, char_directives * d, |
265 | | arguments * a, va_list args) |
266 | 67.4k | { |
267 | 67.4k | if (printf_parse (format, d, a) < 0) { |
268 | 0 | errno = EINVAL; |
269 | 0 | return FALSE; |
270 | 0 | } |
271 | | |
272 | 67.4k | #define LOCAL_CLEANUP() \ |
273 | 67.4k | if (d->dir != d->direct_alloc_dir) \ |
274 | 0 | free (d->dir); \ |
275 | 0 | while (a->count--) { \ |
276 | 0 | if (a->arg[a->count].ext_string) \ |
277 | 0 | free (a->arg[a->count].ext_string); \ |
278 | 0 | } \ |
279 | 0 | if (a->arg != a->direct_alloc_arg) { \ |
280 | 0 | free (a->arg); \ |
281 | 0 | } |
282 | | |
283 | 67.4k | if (printf_fetchargs (args, a) < 0) { |
284 | 0 | LOCAL_CLEANUP (); |
285 | 0 | errno = EINVAL; |
286 | 0 | return FALSE; |
287 | 0 | } |
288 | | |
289 | | /* collect TYPE_POINTER_EXT argument strings */ |
290 | 67.4k | printf_postprocess_args (d, a); |
291 | | |
292 | 67.4k | return TRUE; |
293 | 67.4k | } |
294 | | |
295 | | char * |
296 | | vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args) |
297 | 67.4k | { |
298 | 67.4k | char_directives d; |
299 | 67.4k | arguments a; |
300 | | |
301 | 67.4k | if (!gather_logging_arguments (format, &d, &a, args)) { |
302 | 0 | return NULL; |
303 | 0 | } |
304 | | |
305 | 67.4k | #define CLEANUP() \ |
306 | 67.4k | if (d.dir != d.direct_alloc_dir) \ |
307 | 67.4k | free (d.dir); \ |
308 | 92.2k | while (a.count--) { \ |
309 | 24.7k | if (a.arg[a.count].ext_string) \ |
310 | 24.7k | free (a.arg[a.count].ext_string); \ |
311 | 24.7k | } \ |
312 | 67.4k | if (a.arg != a.direct_alloc_arg) { \ |
313 | 0 | free (a.arg); \ |
314 | 0 | } |
315 | | |
316 | 67.4k | { |
317 | 67.4k | char *buf = |
318 | 67.4k | (char *) alloca (7 + d.max_width_length + d.max_precision_length + 6); |
319 | 67.4k | const char *cp; |
320 | 67.4k | unsigned int i; |
321 | 67.4k | char_directive *dp; |
322 | | /* Output string accumulator. */ |
323 | 67.4k | char *result; |
324 | 67.4k | size_t allocated; |
325 | 67.4k | size_t length; |
326 | | |
327 | 67.4k | if (resultbuf != NULL) { |
328 | 6.63k | result = resultbuf; |
329 | 6.63k | allocated = *lengthp; |
330 | 60.8k | } else { |
331 | 60.8k | result = NULL; |
332 | 60.8k | allocated = 0; |
333 | 60.8k | } |
334 | 67.4k | length = 0; |
335 | | /* Invariants: |
336 | | result is either == resultbuf or == NULL or malloc-allocated. |
337 | | If length > 0, then result != NULL. */ |
338 | | |
339 | 67.4k | #define ENSURE_ALLOCATION(needed) \ |
340 | 176k | if ((needed) > allocated) \ |
341 | 176k | { \ |
342 | 64.3k | char *memory; \ |
343 | 64.3k | \ |
344 | 64.3k | allocated = (allocated > 0 ? 2 * allocated : 320); \ |
345 | 64.3k | if ((needed) > allocated) \ |
346 | 64.3k | allocated = (needed); \ |
347 | 64.3k | if (result == resultbuf || result == NULL) \ |
348 | 64.3k | memory = (char *) malloc (allocated); \ |
349 | 64.3k | else \ |
350 | 64.3k | memory = (char *) realloc (result, allocated); \ |
351 | 64.3k | \ |
352 | 64.3k | if (memory == NULL) \ |
353 | 64.3k | { \ |
354 | 0 | if (!(result == resultbuf || result == NULL)) \ |
355 | 0 | free (result); \ |
356 | 0 | freea (buf); \ |
357 | 0 | CLEANUP (); \ |
358 | 0 | errno = ENOMEM; \ |
359 | 0 | return NULL; \ |
360 | 0 | } \ |
361 | 64.3k | if (result == resultbuf && length > 0) \ |
362 | 64.3k | memcpy (memory, result, length); \ |
363 | 64.3k | result = memory; \ |
364 | 64.3k | } |
365 | | |
366 | 92.2k | for (cp = format, i = 0, dp = &d.dir[0];; cp = dp->dir_end, i++, dp++) { |
367 | 92.2k | if (cp != dp->dir_start) { |
368 | 80.7k | size_t n = dp->dir_start - cp; |
369 | | |
370 | 80.7k | ENSURE_ALLOCATION (length + n); |
371 | 80.7k | memcpy (result + length, cp, n); |
372 | 80.7k | length += n; |
373 | 80.7k | } |
374 | 92.2k | if (i == d.count) |
375 | 67.4k | break; |
376 | | |
377 | | /* Execute a single directive. */ |
378 | 24.7k | if (dp->conversion == '%') { |
379 | 0 | if (!(dp->arg_index < 0)) |
380 | 0 | abort (); |
381 | 0 | ENSURE_ALLOCATION (length + 1); |
382 | 0 | result[length] = '%'; |
383 | 0 | length += 1; |
384 | 24.7k | } else { |
385 | 24.7k | if (!(dp->arg_index >= 0)) |
386 | 0 | abort (); |
387 | | |
388 | 24.7k | if (dp->conversion == 'n') { |
389 | 0 | switch (a.arg[dp->arg_index].type) { |
390 | 0 | case TYPE_COUNT_SCHAR_POINTER: |
391 | 0 | *a.arg[dp->arg_index].a.a_count_schar_pointer = length; |
392 | 0 | break; |
393 | 0 | case TYPE_COUNT_SHORT_POINTER: |
394 | 0 | *a.arg[dp->arg_index].a.a_count_short_pointer = length; |
395 | 0 | break; |
396 | 0 | case TYPE_COUNT_INT_POINTER: |
397 | 0 | *a.arg[dp->arg_index].a.a_count_int_pointer = length; |
398 | 0 | break; |
399 | 0 | case TYPE_COUNT_LONGINT_POINTER: |
400 | 0 | *a.arg[dp->arg_index].a.a_count_longint_pointer = length; |
401 | 0 | break; |
402 | 0 | #ifdef HAVE_LONG_LONG |
403 | 0 | case TYPE_COUNT_LONGLONGINT_POINTER: |
404 | 0 | *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; |
405 | 0 | break; |
406 | 0 | #endif |
407 | 0 | default: |
408 | 0 | abort (); |
409 | 0 | } |
410 | 24.7k | } else { |
411 | 24.7k | arg_type type = a.arg[dp->arg_index].type; |
412 | 24.7k | char *p; |
413 | 24.7k | unsigned int prefix_count; |
414 | 24.7k | int prefixes[2]; |
415 | | #ifndef HAVE_SNPRINTF |
416 | | unsigned int tmp_length; |
417 | | char tmpbuf[700]; |
418 | | char *tmp; |
419 | | |
420 | | /* Allocate a temporary buffer of sufficient size for calling |
421 | | sprintf. */ |
422 | | { |
423 | | unsigned int width; |
424 | | unsigned int precision; |
425 | | |
426 | | width = 0; |
427 | | if (dp->width_start != dp->width_end) { |
428 | | if (dp->width_arg_index >= 0) { |
429 | | int arg; |
430 | | |
431 | | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) |
432 | | abort (); |
433 | | arg = a.arg[dp->width_arg_index].a.a_int; |
434 | | width = (arg < 0 ? -arg : arg); |
435 | | } else { |
436 | | const char *digitp = dp->width_start; |
437 | | |
438 | | do |
439 | | width = width * 10 + (*digitp++ - '0'); |
440 | | while (digitp != dp->width_end); |
441 | | } |
442 | | } |
443 | | |
444 | | precision = 6; |
445 | | if (dp->precision_start != dp->precision_end) { |
446 | | if (dp->precision_arg_index >= 0) { |
447 | | int arg; |
448 | | |
449 | | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) |
450 | | abort (); |
451 | | arg = a.arg[dp->precision_arg_index].a.a_int; |
452 | | precision = (arg < 0 ? 0 : arg); |
453 | | } else { |
454 | | const char *digitp = dp->precision_start + 1; |
455 | | |
456 | | precision = 0; |
457 | | while (digitp != dp->precision_end) |
458 | | precision = precision * 10 + (*digitp++ - '0'); |
459 | | } |
460 | | } |
461 | | |
462 | | switch (dp->conversion) { |
463 | | case 'd': |
464 | | case 'i': |
465 | | case 'u': |
466 | | # ifdef HAVE_LONG_LONG |
467 | | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) |
468 | | tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.30103 /* binary -> decimal */ |
469 | | * 2 /* estimate for FLAG_GROUP */ |
470 | | ) |
471 | | + 1 /* turn floor into ceil */ |
472 | | + 1; /* account for leading sign */ |
473 | | else |
474 | | # endif |
475 | | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) |
476 | | tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.30103 /* binary -> decimal */ |
477 | | * 2 /* estimate for FLAG_GROUP */ |
478 | | ) |
479 | | + 1 /* turn floor into ceil */ |
480 | | + 1; /* account for leading sign */ |
481 | | else |
482 | | tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.30103 /* binary -> decimal */ |
483 | | * 2 /* estimate for FLAG_GROUP */ |
484 | | ) |
485 | | + 1 /* turn floor into ceil */ |
486 | | + 1; /* account for leading sign */ |
487 | | break; |
488 | | |
489 | | case 'o': |
490 | | # ifdef HAVE_LONG_LONG |
491 | | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) |
492 | | tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.333334 /* binary -> octal */ |
493 | | ) |
494 | | + 1 /* turn floor into ceil */ |
495 | | + 1; /* account for leading sign */ |
496 | | else |
497 | | # endif |
498 | | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) |
499 | | tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.333334 /* binary -> octal */ |
500 | | ) |
501 | | + 1 /* turn floor into ceil */ |
502 | | + 1; /* account for leading sign */ |
503 | | else |
504 | | tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.333334 /* binary -> octal */ |
505 | | ) |
506 | | + 1 /* turn floor into ceil */ |
507 | | + 1; /* account for leading sign */ |
508 | | break; |
509 | | |
510 | | case 'x': |
511 | | case 'X': |
512 | | # ifdef HAVE_LONG_LONG |
513 | | if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) |
514 | | tmp_length = (unsigned int) (sizeof (unsigned long long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ |
515 | | ) |
516 | | + 1 /* turn floor into ceil */ |
517 | | + 2; /* account for leading sign or alternate form */ |
518 | | else |
519 | | # endif |
520 | | # ifdef HAVE_INT64_AND_I64 |
521 | | if (type == TYPE_INT64 || type == TYPE_UINT64) |
522 | | tmp_length = (unsigned int) (sizeof (unsigned __int64) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ |
523 | | ) |
524 | | + 1 /* turn floor into ceil */ |
525 | | + 2; /* account for leading sign or alternate form */ |
526 | | else |
527 | | # endif |
528 | | if (type == TYPE_LONGINT || type == TYPE_ULONGINT) |
529 | | tmp_length = (unsigned int) (sizeof (unsigned long) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ |
530 | | ) |
531 | | + 1 /* turn floor into ceil */ |
532 | | + 2; /* account for leading sign or alternate form */ |
533 | | else |
534 | | tmp_length = (unsigned int) (sizeof (unsigned int) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ |
535 | | ) |
536 | | + 1 /* turn floor into ceil */ |
537 | | + 2; /* account for leading sign or alternate form */ |
538 | | break; |
539 | | |
540 | | case 'f': |
541 | | case 'F': |
542 | | # ifdef HAVE_LONG_DOUBLE |
543 | | if (type == TYPE_LONGDOUBLE) |
544 | | tmp_length = (unsigned int) (LDBL_MAX_EXP * 0.30103 /* binary -> decimal */ |
545 | | * 2 /* estimate for FLAG_GROUP */ |
546 | | ) |
547 | | + 1 /* turn floor into ceil */ |
548 | | + precision + 10; /* sign, decimal point etc. */ |
549 | | else |
550 | | # endif |
551 | | tmp_length = (unsigned int) (DBL_MAX_EXP * 0.30103 /* binary -> decimal */ |
552 | | * 2 /* estimate for FLAG_GROUP */ |
553 | | ) |
554 | | + 1 /* turn floor into ceil */ |
555 | | + precision + 10; /* sign, decimal point etc. */ |
556 | | break; |
557 | | |
558 | | case 'e': |
559 | | case 'E': |
560 | | case 'g': |
561 | | case 'G': |
562 | | case 'a': |
563 | | case 'A': |
564 | | tmp_length = precision + 12; /* sign, decimal point, exponent etc. */ |
565 | | break; |
566 | | |
567 | | case 'c': |
568 | | # ifdef HAVE_WINT_T |
569 | | if (type == TYPE_WIDE_CHAR) |
570 | | tmp_length = MB_CUR_MAX; |
571 | | else |
572 | | # endif |
573 | | tmp_length = 1; |
574 | | break; |
575 | | |
576 | | case 's': |
577 | | # ifdef HAVE_WCHAR_T |
578 | | if (type == TYPE_WIDE_STRING) |
579 | | tmp_length = (a.arg[dp->arg_index].a.a_wide_string == NULL ? 6 /* wcslen(L"(null)") */ |
580 | | : local_wcslen (a.arg[dp->arg_index].a.a_wide_string)) |
581 | | * MB_CUR_MAX; |
582 | | else |
583 | | # endif |
584 | | tmp_length = a.arg[dp->arg_index].a.a_string == NULL ? 6 /* strlen("(null)") */ |
585 | | : strlen (a.arg[dp->arg_index].a.a_string); |
586 | | break; |
587 | | |
588 | | case 'p': |
589 | | tmp_length = (unsigned int) (sizeof (void *) * CHAR_BIT * 0.25 /* binary -> hexadecimal */ |
590 | | ) |
591 | | + 1 /* turn floor into ceil */ |
592 | | + 2; /* account for leading 0x */ |
593 | | |
594 | | /* make sure we always have enough space for a plain %p, so + */ |
595 | | if (dp->flags & FLAG_PTR_EXT && a.arg[dp->arg_index].ext_string) |
596 | | tmp_length += strlen (a.arg[dp->arg_index].ext_string); |
597 | | break; |
598 | | |
599 | | default: |
600 | | abort (); |
601 | | } |
602 | | |
603 | | if (tmp_length < width) |
604 | | tmp_length = width; |
605 | | |
606 | | tmp_length++; /* account for trailing NUL */ |
607 | | } |
608 | | |
609 | | if (tmp_length <= sizeof (tmpbuf)) |
610 | | tmp = tmpbuf; |
611 | | else { |
612 | | tmp = (char *) malloc (tmp_length); |
613 | | if (tmp == NULL) { |
614 | | /* Out of memory. */ |
615 | | if (!(result == resultbuf || result == NULL)) |
616 | | free (result); |
617 | | freea (buf); |
618 | | CLEANUP (); |
619 | | errno = ENOMEM; |
620 | | return NULL; |
621 | | } |
622 | | } |
623 | | #endif |
624 | | |
625 | | /* Construct the format string for calling snprintf or |
626 | | sprintf. */ |
627 | 24.7k | p = buf; |
628 | 24.7k | *p++ = '%'; |
629 | 24.7k | if (dp->flags & FLAG_GROUP) |
630 | 0 | *p++ = '\''; |
631 | 24.7k | if (dp->flags & FLAG_LEFT) |
632 | 0 | *p++ = '-'; |
633 | 24.7k | if (dp->flags & FLAG_SHOWSIGN) |
634 | 0 | *p++ = '+'; |
635 | 24.7k | if (dp->flags & FLAG_SPACE) |
636 | 0 | *p++ = ' '; |
637 | 24.7k | if (dp->flags & FLAG_ALT) |
638 | 0 | *p++ = '#'; |
639 | 24.7k | if (dp->flags & FLAG_ZERO) |
640 | 2.17k | *p++ = '0'; |
641 | 24.7k | if (dp->width_start != dp->width_end) { |
642 | 2.17k | size_t n = dp->width_end - dp->width_start; |
643 | 2.17k | memcpy (p, dp->width_start, n); |
644 | 2.17k | p += n; |
645 | 2.17k | } |
646 | 24.7k | if (dp->precision_start != dp->precision_end) { |
647 | 0 | size_t n = dp->precision_end - dp->precision_start; |
648 | 0 | memcpy (p, dp->precision_start, n); |
649 | 0 | p += n; |
650 | 0 | } |
651 | | |
652 | 24.7k | switch (type) { |
653 | | #ifdef HAVE_INT64_AND_I64 |
654 | | case TYPE_INT64: |
655 | | case TYPE_UINT64: |
656 | | *p++ = 'I'; |
657 | | *p++ = '6'; |
658 | | *p++ = '4'; |
659 | | break; |
660 | | #endif |
661 | 0 | #ifdef HAVE_LONG_LONG |
662 | 0 | case TYPE_LONGLONGINT: |
663 | 0 | case TYPE_ULONGLONGINT: |
664 | | #ifdef HAVE_INT64_AND_I64 /* The system (sn)printf uses %I64. Also assume |
665 | | * that long long == __int64. |
666 | | */ |
667 | | *p++ = 'I'; |
668 | | *p++ = '6'; |
669 | | *p++ = '4'; |
670 | | break; |
671 | | #else |
672 | 0 | *p++ = 'l'; |
673 | 0 | G_GNUC_FALLTHROUGH; |
674 | 0 | #endif |
675 | 0 | #endif |
676 | 792 | case TYPE_LONGINT: |
677 | 1.06k | case TYPE_ULONGINT: |
678 | | #ifdef HAVE_WINT_T |
679 | | case TYPE_WIDE_CHAR: |
680 | | #endif |
681 | | #ifdef HAVE_WCHAR_T |
682 | | case TYPE_WIDE_STRING: |
683 | | #endif |
684 | 1.06k | *p++ = 'l'; |
685 | 1.06k | break; |
686 | | #ifdef HAVE_LONG_DOUBLE |
687 | | case TYPE_LONGDOUBLE: |
688 | | *p++ = 'L'; |
689 | | break; |
690 | | #endif |
691 | 23.7k | default: |
692 | 23.7k | break; |
693 | 24.7k | } |
694 | 24.7k | *p = dp->conversion; |
695 | 24.7k | p[1] = '\0'; |
696 | | |
697 | | /* Construct the arguments for calling snprintf or sprintf. */ |
698 | 24.7k | prefix_count = 0; |
699 | 24.7k | if (dp->width_arg_index >= 0) { |
700 | 0 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) |
701 | 0 | abort (); |
702 | 0 | prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; |
703 | 0 | } |
704 | 24.7k | if (dp->precision_arg_index >= 0) { |
705 | 0 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) |
706 | 0 | abort (); |
707 | 0 | prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; |
708 | 0 | } |
709 | 24.7k | #ifdef HAVE_SNPRINTF |
710 | | /* Prepare checking whether snprintf returns the count |
711 | | via %n. */ |
712 | 24.7k | ENSURE_ALLOCATION (length + 1); |
713 | 24.7k | result[length] = '\0'; |
714 | 24.7k | #endif |
715 | | |
716 | 28.2k | for (;;) { |
717 | 28.2k | size_t maxlen; |
718 | 28.2k | int count; |
719 | 28.2k | #ifdef HAVE_SNPRINTF |
720 | 28.2k | int retcount; |
721 | 28.2k | #endif |
722 | | |
723 | 28.2k | maxlen = allocated - length; |
724 | 28.2k | count = -1; |
725 | | |
726 | 28.2k | #ifdef HAVE_SNPRINTF |
727 | 28.2k | retcount = 0; |
728 | | |
729 | 28.2k | #define SNPRINTF_BUF(arg) \ |
730 | 28.2k | switch (prefix_count) \ |
731 | 28.2k | { \ |
732 | 28.2k | case 0: \ |
733 | 28.2k | retcount = snprintf (result + length, maxlen, buf, \ |
734 | 28.2k | arg, &count); \ |
735 | 28.2k | break; \ |
736 | 0 | case 1: \ |
737 | 0 | retcount = snprintf (result + length, maxlen, buf, \ |
738 | 0 | prefixes[0], arg, &count); \ |
739 | 0 | break; \ |
740 | 0 | case 2: \ |
741 | 0 | retcount = snprintf (result + length, maxlen, buf, \ |
742 | 0 | prefixes[0], prefixes[1], arg, \ |
743 | 0 | &count); \ |
744 | 0 | break; \ |
745 | 0 | default: \ |
746 | 0 | abort (); \ |
747 | 28.2k | } |
748 | | #else |
749 | | #define SNPRINTF_BUF(arg) \ |
750 | | switch (prefix_count) \ |
751 | | { \ |
752 | | case 0: \ |
753 | | count = sprintf (tmp, buf, arg); \ |
754 | | break; \ |
755 | | case 1: \ |
756 | | count = sprintf (tmp, buf, prefixes[0], arg); \ |
757 | | break; \ |
758 | | case 2: \ |
759 | | count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ |
760 | | arg); \ |
761 | | break; \ |
762 | | default: \ |
763 | | abort (); \ |
764 | | } |
765 | | #endif |
766 | | |
767 | 28.2k | switch (type) { |
768 | 0 | case TYPE_SCHAR: |
769 | 0 | { |
770 | 0 | int arg = a.arg[dp->arg_index].a.a_schar; |
771 | 0 | SNPRINTF_BUF (arg); |
772 | 0 | } |
773 | 0 | break; |
774 | 0 | case TYPE_UCHAR: |
775 | 0 | { |
776 | 0 | unsigned int arg = a.arg[dp->arg_index].a.a_uchar; |
777 | 0 | SNPRINTF_BUF (arg); |
778 | 0 | } |
779 | 0 | break; |
780 | 0 | case TYPE_SHORT: |
781 | 0 | { |
782 | 0 | int arg = a.arg[dp->arg_index].a.a_short; |
783 | 0 | SNPRINTF_BUF (arg); |
784 | 0 | } |
785 | 0 | break; |
786 | 0 | case TYPE_USHORT: |
787 | 0 | { |
788 | 0 | unsigned int arg = a.arg[dp->arg_index].a.a_ushort; |
789 | 0 | SNPRINTF_BUF (arg); |
790 | 0 | } |
791 | 0 | break; |
792 | 2.14k | case TYPE_INT: |
793 | 2.14k | { |
794 | 2.14k | int arg = a.arg[dp->arg_index].a.a_int; |
795 | 2.14k | SNPRINTF_BUF (arg); |
796 | 2.14k | } |
797 | 0 | break; |
798 | 5.18k | case TYPE_UINT: |
799 | 5.18k | { |
800 | 5.18k | unsigned int arg = a.arg[dp->arg_index].a.a_uint; |
801 | 5.18k | SNPRINTF_BUF (arg); |
802 | 5.18k | } |
803 | 0 | break; |
804 | 792 | case TYPE_LONGINT: |
805 | 792 | { |
806 | 792 | long int arg = a.arg[dp->arg_index].a.a_longint; |
807 | 792 | SNPRINTF_BUF (arg); |
808 | 792 | } |
809 | 0 | break; |
810 | 270 | case TYPE_ULONGINT: |
811 | 270 | { |
812 | 270 | unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; |
813 | 270 | SNPRINTF_BUF (arg); |
814 | 270 | } |
815 | 0 | break; |
816 | | #ifdef HAVE_INT64_AND_I64 |
817 | | case TYPE_INT64: |
818 | | { |
819 | | __int64 arg = a.arg[dp->arg_index].a.a_int64; |
820 | | SNPRINTF_BUF (arg); |
821 | | } |
822 | | break; |
823 | | case TYPE_UINT64: |
824 | | { |
825 | | unsigned __int64 arg = a.arg[dp->arg_index].a.a_uint64; |
826 | | SNPRINTF_BUF (arg); |
827 | | } |
828 | | break; |
829 | | #endif |
830 | 0 | #ifdef HAVE_LONG_LONG |
831 | 0 | #ifndef HAVE_LONG_LONG_FORMAT |
832 | 0 | case TYPE_LONGLONGINT: |
833 | 0 | case TYPE_ULONGLONGINT: |
834 | 0 | { |
835 | 0 | unsigned long long int arg = |
836 | 0 | a.arg[dp->arg_index].a.a_ulonglongint; |
837 | 0 | int width; |
838 | 0 | int precision; |
839 | |
|
840 | 0 | width = 0; |
841 | 0 | if (dp->width_start != dp->width_end) { |
842 | 0 | if (dp->width_arg_index >= 0) { |
843 | 0 | int arg; |
844 | |
|
845 | 0 | if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) |
846 | 0 | abort (); |
847 | 0 | arg = a.arg[dp->width_arg_index].a.a_int; |
848 | 0 | width = (arg < 0 ? -arg : arg); |
849 | 0 | } else { |
850 | 0 | const char *digitp = dp->width_start; |
851 | |
|
852 | 0 | do |
853 | 0 | width = width * 10 + (*digitp++ - '0'); |
854 | 0 | while (digitp != dp->width_end); |
855 | 0 | } |
856 | 0 | } |
857 | | |
858 | 0 | precision = -1; |
859 | 0 | if (dp->precision_start != dp->precision_end) { |
860 | 0 | if (dp->precision_arg_index >= 0) { |
861 | 0 | int arg; |
862 | |
|
863 | 0 | if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) |
864 | 0 | abort (); |
865 | 0 | arg = a.arg[dp->precision_arg_index].a.a_int; |
866 | 0 | precision = (arg < 0 ? 0 : arg); |
867 | 0 | } else { |
868 | 0 | const char *digitp = dp->precision_start + 1; |
869 | |
|
870 | 0 | precision = 0; |
871 | 0 | do |
872 | 0 | precision = precision * 10 + (*digitp++ - '0'); |
873 | 0 | while (digitp != dp->precision_end); |
874 | 0 | } |
875 | 0 | } |
876 | 0 | #ifdef HAVE_SNPRINTF |
877 | 0 | count = print_long_long (result + length, maxlen, |
878 | 0 | width, precision, dp->flags, dp->conversion, arg); |
879 | | #else |
880 | | count = print_long_long (tmp, tmp_length, |
881 | | width, precision, dp->flags, dp->conversion, arg); |
882 | | #endif |
883 | 0 | } |
884 | 0 | break; |
885 | | #else |
886 | | case TYPE_LONGLONGINT: |
887 | | { |
888 | | long long int arg = a.arg[dp->arg_index].a.a_longlongint; |
889 | | SNPRINTF_BUF (arg); |
890 | | } |
891 | | break; |
892 | | case TYPE_ULONGLONGINT: |
893 | | { |
894 | | unsigned long long int arg = |
895 | | a.arg[dp->arg_index].a.a_ulonglongint; |
896 | | SNPRINTF_BUF (arg); |
897 | | } |
898 | | break; |
899 | | #endif |
900 | 0 | #endif |
901 | 0 | case TYPE_DOUBLE: |
902 | 0 | { |
903 | 0 | double arg = a.arg[dp->arg_index].a.a_double; |
904 | 0 | SNPRINTF_BUF (arg); |
905 | 0 | } |
906 | 0 | break; |
907 | | #ifdef HAVE_LONG_DOUBLE |
908 | | case TYPE_LONGDOUBLE: |
909 | | { |
910 | | long double arg = a.arg[dp->arg_index].a.a_longdouble; |
911 | | SNPRINTF_BUF (arg); |
912 | | } |
913 | | break; |
914 | | #endif |
915 | 240 | case TYPE_CHAR: |
916 | 240 | { |
917 | 240 | int arg = a.arg[dp->arg_index].a.a_char; |
918 | 240 | SNPRINTF_BUF (arg); |
919 | 240 | } |
920 | 0 | break; |
921 | | #ifdef HAVE_WINT_T |
922 | | case TYPE_WIDE_CHAR: |
923 | | { |
924 | | wint_t arg = a.arg[dp->arg_index].a.a_wide_char; |
925 | | SNPRINTF_BUF (arg); |
926 | | } |
927 | | break; |
928 | | #endif |
929 | 17.9k | case TYPE_STRING: |
930 | 17.9k | { |
931 | 17.9k | const char *arg = a.arg[dp->arg_index].a.a_string == NULL |
932 | 17.9k | ? "(null)" : a.arg[dp->arg_index].a.a_string; |
933 | 17.9k | SNPRINTF_BUF (arg); |
934 | 17.9k | } |
935 | 0 | break; |
936 | | #ifdef HAVE_WCHAR_T |
937 | | case TYPE_WIDE_STRING: |
938 | | { |
939 | | const wchar_t *arg = |
940 | | a.arg[dp->arg_index].a.a_wide_string == |
941 | | NULL ? L"(null)" : a.arg[dp->arg_index].a.a_wide_string; |
942 | | SNPRINTF_BUF (arg); |
943 | | } |
944 | | break; |
945 | | #endif |
946 | 0 | case TYPE_POINTER: |
947 | 0 | { |
948 | 0 | void *arg = a.arg[dp->arg_index].a.a_pointer; |
949 | 0 | SNPRINTF_BUF (arg); |
950 | 0 | } |
951 | 0 | break; |
952 | 1.63k | case TYPE_POINTER_EXT: |
953 | 1.63k | { |
954 | 1.63k | void *arg = a.arg[dp->arg_index].a.a_pointer; |
955 | | |
956 | 1.63k | if (a.arg[dp->arg_index].ext_string != NULL) { |
957 | 1.63k | arg = a.arg[dp->arg_index].ext_string; |
958 | 1.63k | *p = 's'; |
959 | 1.63k | } |
960 | | |
961 | 1.63k | SNPRINTF_BUF (arg); |
962 | 1.63k | } |
963 | 0 | break; |
964 | 0 | default: |
965 | 0 | abort (); |
966 | 28.2k | } |
967 | | |
968 | 28.2k | #ifdef HAVE_SNPRINTF |
969 | | /* Portability: Not all implementations of snprintf() |
970 | | are ISO C 99 compliant. Determine the number of |
971 | | bytes that snprintf() has produced or would have |
972 | | produced. */ |
973 | 28.2k | if (count >= 0) { |
974 | | /* Verify that snprintf() has NUL-terminated its |
975 | | result. */ |
976 | 0 | if (count < maxlen && result[length + count] != '\0') |
977 | 0 | abort (); |
978 | | /* Portability hack. */ |
979 | 0 | if (retcount > count) |
980 | 0 | count = retcount; |
981 | 28.2k | } else { |
982 | | /* snprintf() doesn't understand the '%n' |
983 | | directive. */ |
984 | 28.2k | if (p[1] != '\0') { |
985 | | /* Don't use the '%n' directive; instead, look |
986 | | at the snprintf() return value. */ |
987 | 0 | p[1] = '\0'; |
988 | 0 | continue; |
989 | 0 | } |
990 | 28.2k | count = retcount; |
991 | 28.2k | } |
992 | 28.2k | #endif |
993 | | |
994 | | /* Attempt to handle failure. */ |
995 | 28.2k | if (count < 0) { |
996 | 0 | if (!(result == resultbuf || result == NULL)) |
997 | 0 | free (result); |
998 | 0 | freea (buf); |
999 | | #ifndef HAVE_SNPRINTF |
1000 | | if (tmp != tmpbuf) |
1001 | | free (tmp); |
1002 | | #endif |
1003 | 0 | CLEANUP (); |
1004 | 0 | errno = EINVAL; |
1005 | 0 | return NULL; |
1006 | 0 | } |
1007 | | #ifndef HAVE_SNPRINTF |
1008 | | if (count >= tmp_length) |
1009 | | /* tmp_length was incorrectly calculated - fix the |
1010 | | code above! */ |
1011 | | abort (); |
1012 | | #endif |
1013 | | |
1014 | | /* Make room for the result. */ |
1015 | 28.2k | if (count >= maxlen) { |
1016 | | /* Need at least count bytes. But allocate |
1017 | | proportionally, to avoid looping eternally if |
1018 | | snprintf() reports a too small count. */ |
1019 | 3.45k | size_t n = length + count; |
1020 | | |
1021 | 3.45k | if (n < 2 * allocated) |
1022 | 2.71k | n = 2 * allocated; |
1023 | | |
1024 | 3.45k | ENSURE_ALLOCATION (n); |
1025 | 3.45k | #ifdef HAVE_SNPRINTF |
1026 | 3.45k | continue; |
1027 | 3.45k | #endif |
1028 | 3.45k | } |
1029 | 24.7k | #ifdef HAVE_SNPRINTF |
1030 | | /* The snprintf() result did fit. */ |
1031 | | #else |
1032 | | /* Append the sprintf() result. */ |
1033 | | memcpy (result + length, tmp, count); |
1034 | | if (tmp != tmpbuf) |
1035 | | free (tmp); |
1036 | | #endif |
1037 | | |
1038 | 24.7k | length += count; |
1039 | 24.7k | break; |
1040 | 28.2k | } |
1041 | 24.7k | } |
1042 | 24.7k | } |
1043 | 24.7k | } |
1044 | | |
1045 | | /* Add the final NUL. */ |
1046 | 67.4k | ENSURE_ALLOCATION (length + 1); |
1047 | 67.4k | result[length] = '\0'; |
1048 | | |
1049 | 67.4k | freea (buf); |
1050 | 67.4k | CLEANUP (); |
1051 | 67.4k | *lengthp = length; |
1052 | 67.4k | return result; |
1053 | 67.4k | } |
1054 | 67.4k | } |