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