blob: a3d3a242da689a0814ee54c7ecb8903f5c09c009 [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>
8
9#include "asn1_buffer.h"
10
11/*
12 * Create and destroy the buffer.
13 */
14abuf *
15abuf_new() {
16 abuf *ab = calloc(1, sizeof(abuf));
17 assert(ab);
18 ab->length = 0;
19 ab->size = 32;
20 ab->buffer = calloc(1, ab->size);
21 assert(ab->buffer);
22 return ab;
23}
24
25void abuf_free(abuf *ab) {
26 if(ab) {
27 union {
28 const char *c_buf;
29 char *nc_buf;
30 } const_cast;
31 const_cast.c_buf = ab->buffer;
32 free(const_cast.nc_buf);
33 free(ab);
34 }
35}
36
37/*
38 * Erase contents of the buffer (without destroying it).
39 */
40void
41abuf_clear(abuf *ab) {
42 union {
43 const char *c_buf;
44 char *nc_buf;
45 } const_cast;
46 if(!ab->buffer) {
47 ab->size = 32;
48 ab->buffer = calloc(1, ab->size);
49 assert(ab->buffer);
50 }
51 const_cast.c_buf = ab->buffer;
52 ab->length = 0;
53 const_cast.nc_buf[0] = '\0';
54}
55
56static void
Lev Walkine3204e72017-08-23 06:22:53 -070057abuf_resize_by(abuf *ab, size_t size) {
Lev Walkind9221842017-08-22 01:44:56 -070058 union {
59 const char *c_buf;
60 char *nc_buf;
61 } const_cast;
62 const_cast.c_buf = ab->buffer;
63
Lev Walkine3204e72017-08-23 06:22:53 -070064 assert(!ab->buffer || ab->buffer[ab->length] == '\0');
Lev Walkind9221842017-08-22 01:44:56 -070065
Lev Walkine3204e72017-08-23 06:22:53 -070066 size_t new_size = ab->length + size;
Lev Walkind9221842017-08-22 01:44:56 -070067 char *p = realloc(const_cast.nc_buf, new_size);
68 assert(p);
Lev Walkine3204e72017-08-23 06:22:53 -070069 if(!ab->buffer) {
70 assert(ab->length == 0);
71 *p = '\0';
72 }
Lev Walkind9221842017-08-22 01:44:56 -070073 ab->buffer = p;
74 assert(ab->buffer[ab->length] == '\0');
75 ab->size = new_size;
76}
77
Lev Walkine3204e72017-08-23 06:22:53 -070078void abuf_add_bytes(abuf *ab, const char *str, size_t size) {
79 abuf_resize_by(ab, size + 1);
80 union {
81 const char *c_buf;
82 char *nc_buf;
83 } const_cast;
84 const_cast.c_buf = ab->buffer;
85 memcpy(&const_cast.nc_buf[ab->length], str, size);
86 ab->length += size;
87 const_cast.nc_buf[ab->length] = '\0';
88}
89
Lev Walkind9221842017-08-22 01:44:56 -070090void abuf_str(abuf *ab, const char *str) {
Lev Walkine3204e72017-08-23 06:22:53 -070091 abuf_add_bytes(ab, str, strlen(str));
Lev Walkind9221842017-08-22 01:44:56 -070092}
93
94void abuf_buf(abuf *ab, const abuf *buf) {
Lev Walkine3204e72017-08-23 06:22:53 -070095 abuf_add_bytes(ab, buf->buffer, buf->length);
Lev Walkind9221842017-08-22 01:44:56 -070096}
97
Lev Walkine3204e72017-08-23 06:22:53 -070098int abuf_printf(abuf *ab, const char *fmt, ...) {
Lev Walkind9221842017-08-22 01:44:56 -070099 va_list ap;
100
101 for(;;) {
102 union {
103 const char *c_buf;
104 char *nc_buf;
105 } const_cast;
106 const_cast.c_buf = ab->buffer;
107 va_start(ap, fmt);
108 int ret = vsnprintf(&const_cast.nc_buf[ab->length],
109 ab->size - ab->length, fmt, ap);
110 va_end(ap);
111 assert(ret >= 0);
112 if((size_t)ret < ab->size - ab->length) {
113 ab->length += ret;
114 assert(ab->buffer[ab->length] == '\0');
Lev Walkine3204e72017-08-23 06:22:53 -0700115 return ret;
Lev Walkind9221842017-08-22 01:44:56 -0700116 }
117 const_cast.nc_buf[ab->length] = '\0'; /* Restore order */
118 abuf_resize_by(ab, ret + 1);
119 }
120}
121
Lev Walkine3204e72017-08-23 06:22:53 -0700122int abuf_vprintf(abuf *ab, const char *fmt, va_list ap) {
123 int ret;
124 char *str = 0;
125
126 ret = vasprintf(&str, fmt, ap);
127 assert(ret >= 0);
128 assert(str != NULL);
129
130 abuf_add_bytes(ab, str, ret);
131
132 free(str);
133
134 return ret;
135}
136