Merge branch 'master' of ssh://git.samba.org/data/git/samba into selftest
[kai/samba.git] / source4 / lib / json / printbuf.c
1 /*
2  * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $
3  *
4  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
5  * Michael Clark <michael@metaparadigm.com>
6  *
7  * This library is free software; you can redistribute it and/or modify
8  * it under the terms of the MIT license. See COPYING for details.
9  *
10  */
11
12 #include "config.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #if HAVE_STDARG_H
19 # include <stdarg.h>
20 #else /* !HAVE_STDARG_H */
21 # error Not enough var arg support!
22 #endif /* HAVE_STDARG_H */
23
24 #include "bits.h"
25 #include "debug.h"
26 #include "printbuf.h"
27
28 struct printbuf* printbuf_new()
29 {
30   struct printbuf *p;
31
32   if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL;
33   p->size = 32;
34   p->bpos = 0;
35   if(!(p->buf = malloc(p->size))) {
36     free(p);
37     return NULL;
38   }
39   return p;
40 }
41
42
43 int printbuf_memappend(struct printbuf *p, char *buf, int size)
44 {
45   char *t;
46   if(p->size - p->bpos <= size) {
47     int new_size = max(p->size * 2, p->bpos + size + 8);
48 #ifdef PRINTBUF_DEBUG
49     mc_debug("printbuf_memappend: realloc "
50              "bpos=%d wrsize=%d old_size=%d new_size=%d\n",
51              p->bpos, size, p->size, new_size);
52 #endif /* PRINTBUF_DEBUG */
53     if(!(t = realloc(p->buf, new_size))) return -1;
54     p->size = new_size;
55     p->buf = t;
56   }
57   memcpy(p->buf + p->bpos, buf, size);
58   p->bpos += size;
59   p->buf[p->bpos]= '\0';
60   return size;
61 }
62
63 #if !HAVE_VSNPRINTF && defined(WIN32)
64 # define vsnprintf _vsnprintf
65 #elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */
66 # error Need vsnprintf!
67 #endif /* !HAVE_VSNPRINTF && defined(WIN32) */
68
69 #if !HAVE_VASPRINTF
70 /* CAW: compliant version of vasprintf */
71 static int vasprintf(char **buf, const char *fmt, va_list ap)
72 {
73 #ifndef WIN32
74         static char _T_emptybuffer = '\0';
75 #endif /* !defined(WIN32) */
76         int chars;
77         char *b;
78
79         if(!buf) { return -1; }
80
81 #ifdef WIN32
82         chars = _vscprintf(fmt, ap)+1;
83 #else /* !defined(WIN32) */
84         /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite
85            our buffer like on some 64bit sun systems.... but hey, its time to move on */
86         chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1;
87         if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */
88 #endif /* defined(WIN32) */
89
90         b = (char*)malloc(sizeof(char)*chars);
91         if(!b) { return -1; }
92
93         if((chars = vsprintf(b, fmt, ap)) < 0)
94         {
95                 free(b);
96         } else {
97                 *buf = b;
98         }
99
100         return chars;
101 }
102 #endif /* !HAVE_VASPRINTF */
103
104 int sprintbuf(struct printbuf *p, const char *msg, ...)
105 {
106   va_list ap;
107   char *t;
108   int size;
109   char buf[128];
110
111   /* user stack buffer first */
112   va_start(ap, msg);
113   size = vsnprintf(buf, 128, msg, ap);
114   va_end(ap);
115   /* if string is greater than stack buffer, then use dynamic string
116      with vasprintf.  Note: some implementation of vsnprintf return -1
117      if output is truncated whereas some return the number of bytes that
118      would have been writen - this code handles both cases. */
119   if(size == -1 || size > 127) {
120     int ret;
121     va_start(ap, msg);
122     if((size = vasprintf(&t, msg, ap)) == -1) return -1;
123     va_end(ap);
124     ret = printbuf_memappend(p, t, size);
125     free(t);
126     return ret;
127   } else {
128     return printbuf_memappend(p, buf, size);
129   }
130 }
131
132 void printbuf_reset(struct printbuf *p)
133 {
134   p->buf[0] = '\0';
135   p->bpos = 0;
136 }
137
138 void printbuf_free(struct printbuf *p)
139 {
140   if(p) {
141     free(p->buf);
142     free(p);
143   }
144 }