NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1common / asn1_buffer.c
1 #define _GNU_SOURCE
2 #include <sys/types.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <assert.h>
8 #include "config.h"
9
10 #include "asn1_buffer.h"
11
12 #if !defined(HAVE_DECL_VASPRINTF) || (HAVE_DECL_VASPRINTF == 0)
13 int vasprintf(char **ret, const char *fmt, va_list args);
14 #endif
15
16 /*
17  * Create and destroy the buffer.
18  */
19 abuf *
20 abuf_new() {
21     abuf *ab = calloc(1, sizeof(abuf));
22     assert(ab);
23     ab->length = 0;
24     ab->size = 32;
25     ab->buffer = calloc(1, ab->size);
26     assert(ab->buffer);
27     return ab;
28 }
29
30 void abuf_free(abuf *ab) {
31     if(ab) {
32         union {
33             const char *c_buf;
34             char *nc_buf;
35         } const_cast;
36         const_cast.c_buf = ab->buffer;
37         free(const_cast.nc_buf);
38         free(ab);
39     }
40 }
41
42 /*
43  * Erase contents of the buffer (without destroying it).
44  */
45 void
46 abuf_clear(abuf *ab) {
47     union {
48         const char *c_buf;
49         char *nc_buf;
50     } const_cast;
51     if(!ab->buffer) {
52         ab->size = 32;
53         ab->buffer = calloc(1, ab->size);
54         assert(ab->buffer);
55     }
56     const_cast.c_buf = ab->buffer;
57     ab->length = 0;
58     const_cast.nc_buf[0] = '\0';
59 }
60
61 static void
62 abuf_resize_by(abuf *ab, size_t size) {
63     union {
64         const char *c_buf;
65         char *nc_buf;
66     } const_cast;
67     const_cast.c_buf = ab->buffer;
68
69     assert(!ab->buffer || ab->buffer[ab->length] == '\0');
70
71     size_t new_size = ab->length + size;
72     char *p = realloc(const_cast.nc_buf, new_size);
73     assert(p);
74     if(!ab->buffer) {
75         assert(ab->length == 0);
76         *p = '\0';
77     }
78     ab->buffer = p;
79     assert(ab->buffer[ab->length] == '\0');
80     ab->size = new_size;
81 }
82
83 void abuf_add_bytes(abuf *ab, const char *str, size_t size) {
84     abuf_resize_by(ab, size + 1);
85     union {
86         const char *c_buf;
87         char *nc_buf;
88     } const_cast;
89     const_cast.c_buf = ab->buffer;
90     memcpy(&const_cast.nc_buf[ab->length], str, size);
91     ab->length += size;
92     const_cast.nc_buf[ab->length] = '\0';
93 }
94
95 void abuf_str(abuf *ab, const char *str) {
96     abuf_add_bytes(ab, str, strlen(str));
97 }
98
99 void abuf_buf(abuf *ab, const abuf *buf) {
100     abuf_add_bytes(ab, buf->buffer, buf->length);
101 }
102
103 int abuf_printf(abuf *ab, const char *fmt, ...) {
104     va_list ap;
105
106     for(;;) {
107         union {
108             const char *c_buf;
109             char *nc_buf;
110         } const_cast;
111         const_cast.c_buf = ab->buffer;
112         va_start(ap, fmt);
113         int ret = vsnprintf(&const_cast.nc_buf[ab->length],
114                             ab->size - ab->length, fmt, ap);
115         va_end(ap);
116         assert(ret >= 0);
117         if((size_t)ret < ab->size - ab->length) {
118             ab->length += ret;
119             assert(ab->buffer[ab->length] == '\0');
120             return ret;
121         }
122         const_cast.nc_buf[ab->length] = '\0'; /* Restore order */
123         abuf_resize_by(ab, ret + 1);
124     }
125 }
126
127 int abuf_vprintf(abuf *ab, const char *fmt, va_list ap) {
128     int ret;
129     char *str = 0;
130
131     ret = vasprintf(&str, fmt, ap);
132     assert(ret >= 0);
133     assert(str != NULL);
134
135     abuf_add_bytes(ab, str, ret);
136
137     free(str);
138
139     return ret;
140 }
141
142 #if !defined(HAVE_DECL_VASPRINTF) || (HAVE_DECL_VASPRINTF == 0)
143 /* Solaris doesn't have vasprintf(3). */
144 int
145 vasprintf(char **ret, const char *fmt, va_list args) {
146     int actual_length = -1;
147     va_list copy;
148     va_copy(copy, args);
149
150     int suggested = vsnprintf(NULL, 0, fmt, args);
151     if(suggested >= 0) {
152         *ret = malloc(suggested + 1);
153         if(*ret) {
154             int actual_length = vsnprintf(*ret, suggested + 1, fmt, copy);
155             if(actual_length >= 0) {
156                 assert(actual_length == suggested);
157                 assert((*ret)[actual_length] == '\0');
158             } else {
159                 free(*ret);
160                 *ret = 0;
161             }
162         }
163     } else {
164         *ret = NULL;
165         assert(suggested >= 0); /* Can't function like this */
166     }
167     va_end(args);
168
169     return actual_length;
170 }
171 #endif