1 #include "prism/util/pm_buffer.h"
4 * Return the size of the pm_buffer_t struct.
7 pm_buffer_sizeof(void) {
8 return sizeof(pm_buffer_t
);
12 * Initialize a pm_buffer_t with the given capacity.
15 pm_buffer_init_capacity(pm_buffer_t
*buffer
, size_t capacity
) {
17 buffer
->capacity
= capacity
;
19 buffer
->value
= (char *) xmalloc(capacity
);
20 return buffer
->value
!= NULL
;
24 * Initialize a pm_buffer_t with its default values.
27 pm_buffer_init(pm_buffer_t
*buffer
) {
28 return pm_buffer_init_capacity(buffer
, 1024);
32 * Return the value of the buffer.
35 pm_buffer_value(const pm_buffer_t
*buffer
) {
40 * Return the length of the buffer.
43 pm_buffer_length(const pm_buffer_t
*buffer
) {
44 return buffer
->length
;
48 * Append the given amount of space to the buffer.
51 pm_buffer_append_length(pm_buffer_t
*buffer
, size_t length
) {
52 size_t next_length
= buffer
->length
+ length
;
54 if (next_length
> buffer
->capacity
) {
55 if (buffer
->capacity
== 0) {
59 while (next_length
> buffer
->capacity
) {
60 buffer
->capacity
*= 2;
63 buffer
->value
= xrealloc(buffer
->value
, buffer
->capacity
);
64 if (buffer
->value
== NULL
) return false;
67 buffer
->length
= next_length
;
72 * Append a generic pointer to memory to the buffer.
75 pm_buffer_append(pm_buffer_t
*buffer
, const void *source
, size_t length
) {
76 size_t cursor
= buffer
->length
;
77 if (pm_buffer_append_length(buffer
, length
)) {
78 memcpy(buffer
->value
+ cursor
, source
, length
);
83 * Append the given amount of space as zeroes to the buffer.
86 pm_buffer_append_zeroes(pm_buffer_t
*buffer
, size_t length
) {
87 size_t cursor
= buffer
->length
;
88 if (pm_buffer_append_length(buffer
, length
)) {
89 memset(buffer
->value
+ cursor
, 0, length
);
94 * Append a formatted string to the buffer.
97 pm_buffer_append_format(pm_buffer_t
*buffer
, const char *format
, ...) {
99 va_start(arguments
, format
);
100 int result
= vsnprintf(NULL
, 0, format
, arguments
);
103 if (result
< 0) return;
104 size_t length
= (size_t) (result
+ 1);
106 size_t cursor
= buffer
->length
;
107 if (pm_buffer_append_length(buffer
, length
)) {
108 va_start(arguments
, format
);
109 vsnprintf(buffer
->value
+ cursor
, length
, format
, arguments
);
116 * Append a string to the buffer.
119 pm_buffer_append_string(pm_buffer_t
*buffer
, const char *value
, size_t length
) {
120 pm_buffer_append(buffer
, value
, length
);
124 * Append a list of bytes to the buffer.
127 pm_buffer_append_bytes(pm_buffer_t
*buffer
, const uint8_t *value
, size_t length
) {
128 pm_buffer_append(buffer
, (const char *) value
, length
);
132 * Append a single byte to the buffer.
135 pm_buffer_append_byte(pm_buffer_t
*buffer
, uint8_t value
) {
136 const void *source
= &value
;
137 pm_buffer_append(buffer
, source
, sizeof(uint8_t));
141 * Append a 32-bit unsigned integer to the buffer as a variable-length integer.
144 pm_buffer_append_varuint(pm_buffer_t
*buffer
, uint32_t value
) {
146 pm_buffer_append_byte(buffer
, (uint8_t) value
);
150 pm_buffer_append_byte(buffer
, (uint8_t) (n
| 128));
153 pm_buffer_append_byte(buffer
, (uint8_t) n
);
158 * Append a 32-bit signed integer to the buffer as a variable-length integer.
161 pm_buffer_append_varsint(pm_buffer_t
*buffer
, int32_t value
) {
162 uint32_t unsigned_int
= ((uint32_t)(value
) << 1) ^ ((uint32_t)(value
>> 31));
163 pm_buffer_append_varuint(buffer
, unsigned_int
);
167 * Append a double to the buffer.
170 pm_buffer_append_double(pm_buffer_t
*buffer
, double value
) {
171 const void *source
= &value
;
172 pm_buffer_append(buffer
, source
, sizeof(double));
176 * Append a unicode codepoint to the buffer.
179 pm_buffer_append_unicode_codepoint(pm_buffer_t
*buffer
, uint32_t value
) {
181 pm_buffer_append_byte(buffer
, (uint8_t) value
); // 0xxxxxxx
183 } else if (value
<= 0x7FF) {
185 (uint8_t) (0xC0 | ((value
>> 6) & 0x3F)), // 110xxxxx
186 (uint8_t) (0x80 | (value
& 0x3F)) // 10xxxxxx
189 pm_buffer_append_bytes(buffer
, bytes
, 2);
191 } else if (value
<= 0xFFFF) {
193 (uint8_t) (0xE0 | ((value
>> 12) & 0x3F)), // 1110xxxx
194 (uint8_t) (0x80 | ((value
>> 6) & 0x3F)), // 10xxxxxx
195 (uint8_t) (0x80 | (value
& 0x3F)) // 10xxxxxx
198 pm_buffer_append_bytes(buffer
, bytes
, 3);
200 } else if (value
<= 0x10FFFF) {
202 (uint8_t) (0xF0 | ((value
>> 18) & 0x3F)), // 11110xxx
203 (uint8_t) (0x80 | ((value
>> 12) & 0x3F)), // 10xxxxxx
204 (uint8_t) (0x80 | ((value
>> 6) & 0x3F)), // 10xxxxxx
205 (uint8_t) (0x80 | (value
& 0x3F)) // 10xxxxxx
208 pm_buffer_append_bytes(buffer
, bytes
, 4);
216 * Append a slice of source code to the buffer.
219 pm_buffer_append_source(pm_buffer_t
*buffer
, const uint8_t *source
, size_t length
, pm_buffer_escaping_t escaping
) {
220 for (size_t index
= 0; index
< length
; index
++) {
221 const uint8_t byte
= source
[index
];
223 if ((byte
<= 0x06) || (byte
>= 0x0E && byte
<= 0x1F) || (byte
>= 0x7F)) {
224 if (escaping
== PM_BUFFER_ESCAPING_RUBY
) {
225 pm_buffer_append_format(buffer
, "\\x%02X", byte
);
227 pm_buffer_append_format(buffer
, "\\u%04X", byte
);
232 if (escaping
== PM_BUFFER_ESCAPING_RUBY
) {
233 pm_buffer_append_string(buffer
, "\\a", 2);
235 pm_buffer_append_format(buffer
, "\\u%04X", byte
);
239 pm_buffer_append_string(buffer
, "\\b", 2);
242 pm_buffer_append_string(buffer
, "\\t", 2);
245 pm_buffer_append_string(buffer
, "\\n", 2);
248 if (escaping
== PM_BUFFER_ESCAPING_RUBY
) {
249 pm_buffer_append_string(buffer
, "\\v", 2);
251 pm_buffer_append_format(buffer
, "\\u%04X", byte
);
255 pm_buffer_append_string(buffer
, "\\f", 2);
258 pm_buffer_append_string(buffer
, "\\r", 2);
261 pm_buffer_append_string(buffer
, "\\\"", 2);
264 if (escaping
== PM_BUFFER_ESCAPING_RUBY
&& index
+ 1 < length
) {
265 const uint8_t next_byte
= source
[index
+ 1];
266 if (next_byte
== '{' || next_byte
== '@' || next_byte
== '$') {
267 pm_buffer_append_byte(buffer
, '\\');
271 pm_buffer_append_byte(buffer
, '#');
275 pm_buffer_append_string(buffer
, "\\\\", 2);
278 pm_buffer_append_byte(buffer
, byte
);
286 * Prepend the given string to the buffer.
289 pm_buffer_prepend_string(pm_buffer_t
*buffer
, const char *value
, size_t length
) {
290 size_t cursor
= buffer
->length
;
291 if (pm_buffer_append_length(buffer
, length
)) {
292 memmove(buffer
->value
+ length
, buffer
->value
, cursor
);
293 memcpy(buffer
->value
, value
, length
);
298 * Concatenate one buffer onto another.
301 pm_buffer_concat(pm_buffer_t
*destination
, const pm_buffer_t
*source
) {
302 if (source
->length
> 0) {
303 pm_buffer_append(destination
, source
->value
, source
->length
);
308 * Clear the buffer by reducing its size to 0. This does not free the allocated
309 * memory, but it does allow the buffer to be reused.
312 pm_buffer_clear(pm_buffer_t
*buffer
) {
317 * Strip the whitespace from the end of the buffer.
320 pm_buffer_rstrip(pm_buffer_t
*buffer
) {
321 while (buffer
->length
> 0 && pm_char_is_whitespace((uint8_t) buffer
->value
[buffer
->length
- 1])) {
327 * Checks if the buffer includes the given value.
330 pm_buffer_index(const pm_buffer_t
*buffer
, char value
) {
331 const char *first
= memchr(buffer
->value
, value
, buffer
->length
);
332 return (first
== NULL
) ? SIZE_MAX
: (size_t) (first
- buffer
->value
);
336 * Insert the given string into the buffer at the given index.
339 pm_buffer_insert(pm_buffer_t
*buffer
, size_t index
, const char *value
, size_t length
) {
340 assert(index
<= buffer
->length
);
342 if (index
== buffer
->length
) {
343 pm_buffer_append_string(buffer
, value
, length
);
345 pm_buffer_append_zeroes(buffer
, length
);
346 memmove(buffer
->value
+ index
+ length
, buffer
->value
+ index
, buffer
->length
- length
- index
);
347 memcpy(buffer
->value
+ index
, value
, length
);
352 * Free the memory associated with the buffer.
355 pm_buffer_free(pm_buffer_t
*buffer
) {
356 xfree(buffer
->value
);