blob: cd67b8151ff3277031bab8da16f19a2469746811 [file] [log] [blame]
Lev Walkinfadb26a2017-08-23 22:44:14 -07001#define _GNU_SOURCE
Lev Walkind9221842017-08-22 01:44:56 -07002#include <sys/types.h>
3#include <stdlib.h>
4#include <stdarg.h>
5#include <string.h>
6#include <stdio.h>
7#include <assert.h>
Lev Walkina06b1b42017-10-05 23:07:22 -07008#include "config.h"
Lev Walkind9221842017-08-22 01:44:56 -07009
10#include "asn1_buffer.h"
11
Lev Walkin6bdd8c02017-10-06 16:35:45 -070012#if !defined(HAVE_DECL_VASPRINTF) || (HAVE_DECL_VASPRINTF == 0)
Lev Walkina06b1b42017-10-05 23:07:22 -070013int vasprintf(char **ret, const char *fmt, va_list args);
14#endif
15
Lev Walkind9221842017-08-22 01:44:56 -070016/*
17 * Create and destroy the buffer.
18 */
19abuf *
20abuf_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
30void 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 */
45void
46abuf_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
61static void
Lev Walkine3204e72017-08-23 06:22:53 -070062abuf_resize_by(abuf *ab, size_t size) {
Lev Walkind9221842017-08-22 01:44:56 -070063 union {
64 const char *c_buf;
65 char *nc_buf;
66 } const_cast;
67 const_cast.c_buf = ab->buffer;
68
Lev Walkine3204e72017-08-23 06:22:53 -070069 assert(!ab->buffer || ab->buffer[ab->length] == '\0');
Lev Walkind9221842017-08-22 01:44:56 -070070
Lev Walkine3204e72017-08-23 06:22:53 -070071 size_t new_size = ab->length + size;
Lev Walkind9221842017-08-22 01:44:56 -070072 char *p = realloc(const_cast.nc_buf, new_size);
73 assert(p);
Lev Walkine3204e72017-08-23 06:22:53 -070074 if(!ab->buffer) {
75 assert(ab->length == 0);
76 *p = '\0';
77 }
Lev Walkind9221842017-08-22 01:44:56 -070078 ab->buffer = p;
79 assert(ab->buffer[ab->length] == '\0');
80 ab->size = new_size;
81}
82
Lev Walkine3204e72017-08-23 06:22:53 -070083void 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
Lev Walkind9221842017-08-22 01:44:56 -070095void abuf_str(abuf *ab, const char *str) {
Lev Walkine3204e72017-08-23 06:22:53 -070096 abuf_add_bytes(ab, str, strlen(str));
Lev Walkind9221842017-08-22 01:44:56 -070097}
98
99void abuf_buf(abuf *ab, const abuf *buf) {
Lev Walkine3204e72017-08-23 06:22:53 -0700100 abuf_add_bytes(ab, buf->buffer, buf->length);
Lev Walkind9221842017-08-22 01:44:56 -0700101}
102
Lev Walkine3204e72017-08-23 06:22:53 -0700103int abuf_printf(abuf *ab, const char *fmt, ...) {
Lev Walkind9221842017-08-22 01:44:56 -0700104 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');
Lev Walkine3204e72017-08-23 06:22:53 -0700120 return ret;
Lev Walkind9221842017-08-22 01:44:56 -0700121 }
122 const_cast.nc_buf[ab->length] = '\0'; /* Restore order */
123 abuf_resize_by(ab, ret + 1);
124 }
125}
126
Lev Walkine3204e72017-08-23 06:22:53 -0700127int 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
Lev Walkin6bdd8c02017-10-06 16:35:45 -0700142#if !defined(HAVE_DECL_VASPRINTF) || (HAVE_DECL_VASPRINTF == 0)
Lev Walkina06b1b42017-10-05 23:07:22 -0700143/* Solaris doesn't have vasprintf(3). */
144int
145vasprintf(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