1 /*
2 * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
3 *
4 * Jansson is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7 /**
8 * License: MIT
9 */
10 module jansson_d.strbuffer;
11
12
13 package:
14
15 private static import core.stdc.string;
16 private static import jansson_d.jansson;
17 private static import jansson_d.jansson_private;
18
19 struct strbuffer_t
20 {
21 char* value;
22
23 /* bytes used */
24 size_t length_;
25
26 @disable
27 alias length = length_;
28
29 /* bytes allocated */
30 size_t size;
31 }
32
33 private enum STRBUFFER_MIN_SIZE = 16;
34 private enum STRBUFFER_FACTOR = 2;
35 private enum size_t STRBUFFER_SIZE_MAX = size_t.max;
36
37 nothrow @trusted @nogc //ToDo: @nodiscard
38 int strbuffer_init(scope strbuffer_t* strbuff)
39
40 in
41 {
42 assert(strbuff != null);
43 }
44
45 do
46 {
47 strbuff.size = STRBUFFER_MIN_SIZE;
48 strbuff.length_ = 0;
49
50 strbuff.value = cast(char*)(jansson_d.jansson_private.jsonp_malloc(strbuff.size));
51
52 if (strbuff.value == null) {
53 return -1;
54 }
55
56 /* initialize to empty */
57 strbuff.value[0] = '\0';
58
59 return 0;
60 }
61
62 nothrow @trusted @nogc
63 void strbuffer_close(scope strbuffer_t* strbuff)
64
65 in
66 {
67 assert(strbuff != null);
68 }
69
70 do
71 {
72 jansson_d.jansson_private.jsonp_free(strbuff.value);
73 strbuff.size = 0;
74 strbuff.length_ = 0;
75 strbuff.value = null;
76 }
77
78 pure nothrow @trusted @nogc @live
79 void strbuffer_clear(scope strbuffer_t* strbuff)
80
81 in
82 {
83 assert(strbuff != null);
84 }
85
86 do
87 {
88 strbuff.length_ = 0;
89 strbuff.value[0] = '\0';
90 }
91
92 pure nothrow @trusted @nogc @live
93 const (char)* strbuffer_value(return scope const strbuffer_t* strbuff)
94
95 in
96 {
97 assert(strbuff != null);
98 }
99
100 do
101 {
102 return strbuff.value;
103 }
104
105 /* Steal the value and close the strbuffer */
106 pure nothrow @trusted @nogc @live
107 char* strbuffer_steal_value(scope strbuffer_t* strbuff)
108
109 in
110 {
111 assert(strbuff != null);
112 }
113
114 do
115 {
116 char* result = strbuff.value;
117 strbuff.value = null;
118
119 return result;
120 }
121
122 nothrow @trusted @nogc
123 int strbuffer_append_byte(scope strbuffer_t* strbuff, char byte_)
124
125 do
126 {
127 return .strbuffer_append_bytes(strbuff, &byte_, 1);
128 }
129
130 nothrow @trusted @nogc
131 int strbuffer_append_bytes(scope strbuffer_t* strbuff, scope const char* data, size_t size)
132
133 in
134 {
135 assert(strbuff != null);
136 }
137
138 do
139 {
140 if (size >= (strbuff.size - strbuff.length_)) {
141 /* avoid integer overflow */
142 if ((strbuff.size > (STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR)) || (size > (STRBUFFER_SIZE_MAX - 1)) || (strbuff.length_ > (STRBUFFER_SIZE_MAX - 1 - size))) {
143 return -1;
144 }
145
146 size_t new_size = mixin (jansson_d.jansson_private.max!("strbuff.size * STRBUFFER_FACTOR", "strbuff.length_ + size + 1"));
147
148 char* new_value = cast(char*)(jansson_d.jansson_private.jsonp_malloc(new_size));
149
150 if (new_value == null) {
151 return -1;
152 }
153
154 core.stdc..string.memcpy(new_value, strbuff.value, strbuff.length_);
155
156 jansson_d.jansson_private.jsonp_free(strbuff.value);
157 strbuff.value = new_value;
158 strbuff.size = new_size;
159 }
160
161 core.stdc..string.memcpy(strbuff.value + strbuff.length_, data, size);
162 strbuff.length_ += size;
163 strbuff.value[strbuff.length_] = '\0';
164
165 return 0;
166 }
167
168 pure nothrow @trusted @nogc @live
169 char strbuffer_pop(scope strbuffer_t* strbuff)
170
171 in
172 {
173 assert(strbuff != null);
174 }
175
176 do
177 {
178 if (strbuff.length_ > 0) {
179 char c = strbuff.value[--strbuff.length_];
180 strbuff.value[strbuff.length_] = '\0';
181
182 return c;
183 } else {
184 return '\0';
185 }
186 }