Ruby  3.4.0dev (2024-12-06 revision 892c46283a5ea4179500d951c9d4866c0051f27b)
pm_buffer.c
1 #include "prism/util/pm_buffer.h"
2 
6 size_t
8  return sizeof(pm_buffer_t);
9 }
10 
14 bool
15 pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity) {
16  buffer->length = 0;
17  buffer->capacity = capacity;
18 
19  buffer->value = (char *) xmalloc(capacity);
20  return buffer->value != NULL;
21 }
22 
26 bool
28  return pm_buffer_init_capacity(buffer, 1024);
29 }
30 
34 char *
35 pm_buffer_value(const pm_buffer_t *buffer) {
36  return buffer->value;
37 }
38 
42 size_t
43 pm_buffer_length(const pm_buffer_t *buffer) {
44  return buffer->length;
45 }
46 
50 static inline bool
51 pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
52  size_t next_length = buffer->length + length;
53 
54  if (next_length > buffer->capacity) {
55  if (buffer->capacity == 0) {
56  buffer->capacity = 1;
57  }
58 
59  while (next_length > buffer->capacity) {
60  buffer->capacity *= 2;
61  }
62 
63  buffer->value = xrealloc(buffer->value, buffer->capacity);
64  if (buffer->value == NULL) return false;
65  }
66 
67  buffer->length = next_length;
68  return true;
69 }
70 
74 static inline void
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);
79  }
80 }
81 
85 void
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);
90  }
91 }
92 
96 void
97 pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) {
98  va_list arguments;
99  va_start(arguments, format);
100  int result = vsnprintf(NULL, 0, format, arguments);
101  va_end(arguments);
102 
103  if (result < 0) return;
104  size_t length = (size_t) (result + 1);
105 
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);
110  va_end(arguments);
111  buffer->length--;
112  }
113 }
114 
118 void
119 pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length) {
120  pm_buffer_append(buffer, value, length);
121 }
122 
126 void
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);
129 }
130 
134 void
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));
138 }
139 
143 void
144 pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value) {
145  if (value < 128) {
146  pm_buffer_append_byte(buffer, (uint8_t) value);
147  } else {
148  uint32_t n = value;
149  while (n >= 128) {
150  pm_buffer_append_byte(buffer, (uint8_t) (n | 128));
151  n >>= 7;
152  }
153  pm_buffer_append_byte(buffer, (uint8_t) n);
154  }
155 }
156 
160 void
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);
164 }
165 
169 void
170 pm_buffer_append_double(pm_buffer_t *buffer, double value) {
171  const void *source = &value;
172  pm_buffer_append(buffer, source, sizeof(double));
173 }
174 
178 void
179 pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
180  for (size_t index = 0; index < length; index++) {
181  const uint8_t byte = source[index];
182 
183  if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
184  if (escaping == PM_BUFFER_ESCAPING_RUBY) {
185  pm_buffer_append_format(buffer, "\\x%02X", byte);
186  } else {
187  pm_buffer_append_format(buffer, "\\u%04X", byte);
188  }
189  } else {
190  switch (byte) {
191  case '\a':
192  if (escaping == PM_BUFFER_ESCAPING_RUBY) {
193  pm_buffer_append_string(buffer, "\\a", 2);
194  } else {
195  pm_buffer_append_format(buffer, "\\u%04X", byte);
196  }
197  break;
198  case '\b':
199  pm_buffer_append_string(buffer, "\\b", 2);
200  break;
201  case '\t':
202  pm_buffer_append_string(buffer, "\\t", 2);
203  break;
204  case '\n':
205  pm_buffer_append_string(buffer, "\\n", 2);
206  break;
207  case '\v':
208  if (escaping == PM_BUFFER_ESCAPING_RUBY) {
209  pm_buffer_append_string(buffer, "\\v", 2);
210  } else {
211  pm_buffer_append_format(buffer, "\\u%04X", byte);
212  }
213  break;
214  case '\f':
215  pm_buffer_append_string(buffer, "\\f", 2);
216  break;
217  case '\r':
218  pm_buffer_append_string(buffer, "\\r", 2);
219  break;
220  case '"':
221  pm_buffer_append_string(buffer, "\\\"", 2);
222  break;
223  case '#': {
224  if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
225  const uint8_t next_byte = source[index + 1];
226  if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
227  pm_buffer_append_byte(buffer, '\\');
228  }
229  }
230 
231  pm_buffer_append_byte(buffer, '#');
232  break;
233  }
234  case '\\':
235  pm_buffer_append_string(buffer, "\\\\", 2);
236  break;
237  default:
238  pm_buffer_append_byte(buffer, byte);
239  break;
240  }
241  }
242  }
243 }
244 
248 void
249 pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
250  size_t cursor = buffer->length;
251  if (pm_buffer_append_length(buffer, length)) {
252  memmove(buffer->value + length, buffer->value, cursor);
253  memcpy(buffer->value, value, length);
254  }
255 }
256 
260 void
261 pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source) {
262  if (source->length > 0) {
263  pm_buffer_append(destination, source->value, source->length);
264  }
265 }
266 
271 void
273  buffer->length = 0;
274 }
275 
279 void
281  while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
282  buffer->length--;
283  }
284 }
285 
289 size_t
290 pm_buffer_index(const pm_buffer_t *buffer, char value) {
291  const char *first = memchr(buffer->value, value, buffer->length);
292  return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
293 }
294 
298 void
299 pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
300  assert(index <= buffer->length);
301 
302  if (index == buffer->length) {
303  pm_buffer_append_string(buffer, value, length);
304  } else {
305  pm_buffer_append_zeroes(buffer, length);
306  memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
307  memcpy(buffer->value + index, value, length);
308  }
309 }
310 
314 void
316  xfree(buffer->value);
317 }
#define xfree
Old name of ruby_xfree.
Definition: xmalloc.h:58
#define xrealloc
Old name of ruby_xrealloc.
Definition: xmalloc.h:56
#define xmalloc
Old name of ruby_xmalloc.
Definition: xmalloc.h:53
A wrapper around a contiguous block of allocated memory.
bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity)
Initialize a pm_buffer_t with the given capacity.
Definition: pm_buffer.c:15
PRISM_EXPORTED_FUNCTION size_t pm_buffer_sizeof(void)
Return the size of the pm_buffer_t struct.
Definition: pm_buffer.c:7
size_t pm_buffer_index(const pm_buffer_t *buffer, char value)
Checks if the buffer includes the given value.
Definition: pm_buffer.c:290
void pm_buffer_append_format(pm_buffer_t *buffer, const char *format,...) PRISM_ATTRIBUTE_FORMAT(2
Append a formatted string to the buffer.
void void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length)
Append a string to the buffer.
Definition: pm_buffer.c:119
PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
Definition: pm_buffer.c:43
pm_buffer_escaping_t
The different types of escaping that can be performed by the buffer when appending a slice of Ruby so...
Definition: pm_buffer.h:144
void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length)
Append the given amount of space as zeroes to the buffer.
Definition: pm_buffer.c:86
void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping)
Append a slice of source code to the buffer.
Definition: pm_buffer.c:179
void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value)
Append a 32-bit unsigned integer to the buffer as a variable-length integer.
Definition: pm_buffer.c:144
void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value)
Append a single byte to the buffer.
Definition: pm_buffer.c:135
PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer)
Initialize a pm_buffer_t with its default values.
Definition: pm_buffer.c:27
void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value)
Append a 32-bit signed integer to the buffer as a variable-length integer.
Definition: pm_buffer.c:161
void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length)
Prepend the given string to the buffer.
Definition: pm_buffer.c:249
void pm_buffer_rstrip(pm_buffer_t *buffer)
Strip the whitespace from the end of the buffer.
Definition: pm_buffer.c:280
void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length)
Insert the given string into the buffer at the given index.
Definition: pm_buffer.c:299
PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer)
Return the value of the buffer.
Definition: pm_buffer.c:35
PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer)
Free the memory associated with the buffer.
Definition: pm_buffer.c:315
void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length)
Append a list of bytes to the buffer.
Definition: pm_buffer.c:127
void pm_buffer_append_double(pm_buffer_t *buffer, double value)
Append a double to the buffer.
Definition: pm_buffer.c:170
void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source)
Concatenate one buffer onto another.
Definition: pm_buffer.c:261
void pm_buffer_clear(pm_buffer_t *buffer)
Clear the buffer by reducing its size to 0.
Definition: pm_buffer.c:272
bool pm_char_is_whitespace(const uint8_t b)
Returns true if the given character is a whitespace character.
Definition: pm_char.c:133
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
Definition: pm_buffer.h:22
size_t capacity
The capacity of the buffer in bytes that has been allocated.
Definition: pm_buffer.h:27
size_t length
The length of the buffer in bytes.
Definition: pm_buffer.h:24
char * value
A pointer to the start of the buffer.
Definition: pm_buffer.h:30