implement obstack_vprintf
[libfirm] / ir / obstack / obstack_printf.c
1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <assert.h>
5 #include "obstack.h"
6
7 #ifdef _WIN32
8 #define vsnprintf _vsnprintf
9 #endif
10
11 int obstack_vprintf(struct obstack *obst, const char *fmt, va_list ap)
12 {
13         char    buf[128];
14         char   *buffer = buf;
15         size_t  size   = sizeof(buf);
16         int     len;
17
18         for (;;) {
19                 len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
20
21                 /* snprintf should return -1 only in the error case, but older glibcs
22                  * and probably other systems are buggy in this respect and return -1 if
23                  * the buffer was too small. We only abort for LARGE unrealistic buffer
24                  * sizes here */
25                 if (len < 0) {
26                         if (buffer != buf)
27                                 free(buffer);
28                         if (size > 65536)
29                                 return -1;
30                         size *= 2;
31                 } else if ((size_t)len >= size) {
32                         /* If we come here more than once, vsnprintf() returned garbage */
33                         assert(buffer == buf);
34                         size = (size_t)len + 1;
35                 } else {
36                         break;
37                 }
38                 buffer = malloc(size);
39         }
40
41         obstack_grow(obst, buffer, len);
42         if (buffer != buf)
43                 free(buffer);
44
45         return len;
46 }
47
48 int obstack_printf(struct obstack *obst, const char *fmt, ...)
49 {
50         va_list ap;
51         int     res;
52
53         va_start(ap, fmt);
54         res = obstack_vprintf(obst, fmt, ap);
55         va_end(ap);
56
57         return res;
58 }