The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
sbuff.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/** A generic buffer structure for string printing and parsing strings
19 *
20 * Because doing manual length checks is error prone and a waste of everyones time.
21 *
22 * @file src/lib/util/sbuff.h
23 *
24 * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
25 */
26RCSIDH(sbuff_h, "$Id: 694e69a2d97e30d90489cedc6c0aee885df49668 $")
27
28# ifdef __cplusplus
29extern "C" {
30# endif
31
32#include <ctype.h>
33#include <errno.h>
34#include <limits.h>
35#include <stdio.h>
36#include <sys/types.h>
37
38/** Represents number of bytes parsed or location of parse error
39 *
40 * Number of bytes parsed will be >= 0.
41 *
42 * If a parse error occurs the value will be the negative offset
43 * of the error -1. i.e. offset 0 will be -1.
44 *
45 * This is to disambiguate between 0 bytes parsed and error at
46 * offset 0.
47 */
49typedef struct fr_sbuff_s fr_sbuff_t;
51
52#include <freeradius-devel/util/atexit.h>
53#include <freeradius-devel/util/strerror.h>
54#include <freeradius-devel/util/table.h>
55#include <freeradius-devel/util/talloc.h>
56
57/** Whether the buffer is currently extendable and whether it was extended
58 *
59 */
60DIAG_OFF(attributes)
61DIAG_OFF(cast-align)
62typedef enum CC_HINT(flag_enum) {
63 FR_SBUFF_FLAG_EXTENDED = 0x01, //!< The last call to extend function actually extended the buffer.
64 FR_SBUFF_FLAG_EXTEND_ERROR = 0x02 //!< The last call to an extend function resulted in an error.
65 ///< Error should be provided using fr_strerror_const/fr_strerror_printf
66 ///< by the extension function.
68DIAG_OFF(attributes)
69
70/** Extension callback
71 *
72 * Retrieves additional data from a source and adds it to a buffer.
73 */
74typedef size_t(*fr_sbuff_extend_t)(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t req_extension);
75
76/** For a given extension function, returns whether it is at EOF
77 *
78 */
79typedef bool(*fr_sbuff_eof_t)(fr_sbuff_t *sbuff);
80
81
83 union {
84 char const *p_i; //!< Immutable position pointer.
85 char *p; //!< Mutable position pointer.
86 };
87 fr_sbuff_marker_t *next; //!< Next m in the list.
88 fr_sbuff_t *parent; //!< Owner of the marker
89};
90
91struct fr_sbuff_s {
92 union {
93 char const *buff_i; //!< Immutable buffer pointer.
94 char *buff; //!< Mutable buffer pointer.
95 };
96
97 union {
98 char const *start_i; //!< Immutable start pointer.
99 char *start; //!< Mutable start pointer.
100 };
101
102 union {
103 char const *end_i; //!< Immutable end pointer.
104 char *end; //!< Mutable end pointer.
105 };
106
107 union {
108 char const *p_i; //!< Immutable position pointer.
109 char *p; //!< Mutable position pointer.
110 };
111
112 char const *err; //!< Where the last error occurred.
113
114 unsigned int is_const:1; //!< Can't be modified.
115 unsigned int adv_parent:1; //!< If true, advance the parent.
116 size_t shifted; //!< How many bytes this sbuff has been
117 ///< shifted since its creation.
118
119 fr_sbuff_extend_t extend; //!< Function to re-populate or extend
120 ///< the buffer.
121
122 fr_sbuff_eof_t eof; //!< Function to determine if the buffer is at EOF.
123
124 void *uctx; //!< Extend uctx data.
125
126 fr_sbuff_t *parent; //!< sbuff this sbuff was copied from.
127
128 fr_sbuff_marker_t *m; //!< Pointers to update if the underlying
129 ///< buffer changes.
130};
131
132/** Talloc sbuff extension structure
133 *
134 * Holds the data necessary for creating dynamically
135 * extensible buffers.
136 */
137typedef struct {
138 TALLOC_CTX *ctx; //!< Context to alloc new buffers in.
139 size_t init; //!< How much to allocate initially.
140 size_t max; //!< Maximum size of the buffer.
142
143/** File sbuff extension structure
144 *
145 * Holds the data necessary for creating dynamically
146 * extensible file buffers.
147 */
148typedef struct {
149 FILE *file; //!< FILE * we're reading from.
150 char *buff_end; //!< The true end of the buffer.
151 size_t max; //!< Maximum number of bytes to read.
152 size_t shifted; //!< How much we've read from this file.
153 bool eof; //!< are we at EOF?
155
156/** Terminal element with pre-calculated lengths
157 *
158 */
159typedef struct {
160 char const *str; //!< Terminal string
161 size_t len; //!< Length of string
163
164/** Set of terminal elements
165 *
166 * The elements MUST be listed in sorted order. If the inputs are
167 * not sorted, then all kinds of things will break.
168 */
169typedef struct {
170 size_t len; //!< Length of the list.
171 fr_sbuff_term_elem_t *elem; //!< A sorted list of terminal strings.
173
174/** Initialise a terminal structure with a single string
175 *
176 * @param[in] _str terminal string.
177 */
178#define FR_SBUFF_TERM(_str) \
179(fr_sbuff_term_t){ \
180 .len = 1, \
181 .elem = (fr_sbuff_term_elem_t[]){ L(_str) }, \
182}
183
184/** Initialise a terminal structure with a list of sorted strings
185 *
186 * Strings must be lexicographically sorted.
187 *
188 * @param[in] ... Lexicographically sorted list of terminal strings.
189 */
190#define FR_SBUFF_TERMS(...) \
191(fr_sbuff_term_t){ \
192 .len = (sizeof((fr_sbuff_term_elem_t[]){ __VA_ARGS__ }) / sizeof(fr_sbuff_term_elem_t)), \
193 .elem = (fr_sbuff_term_elem_t[]){ __VA_ARGS__ }, \
194}
195
196/*
197 * We can't put this into a typdef:
198 *
199 * typedef bool sbuff_char_class_t[static UINT8_MAX + 1];
200 *
201 * So we use a macro instead.
202 */
203#define SBUFF_CHAR_CLASS UINT8_MAX + 1
204
205/** Set of parsing rules for *unescape_until functions
206 *
207 */
208typedef struct {
209 char const *name; //!< Name for rule set to aid we debugging.
210
211 char chr; //!< Character at the start of an escape sequence.
212 char subs[SBUFF_CHAR_CLASS]; //!< Special characters and their substitutions.
213 ///< Indexed by the printable representation i.e.
214 ///< 'n' for \n.
215 bool skip[SBUFF_CHAR_CLASS]; //!< Characters that are escaped, but left in the
216 ///< output along with the escape character.
217 ///< This is useful where we need to interpret escape
218 ///< sequences for parsing, but where the string will
219 ///< be passed off to a 3rd party library which will
220 ///< need to interpret the same sequences.
221
222 bool do_hex; //!< Process hex sequences i.e. @verbatim\x<hex><hex>.@endverbatim
223 bool do_oct; //!< Process oct sequences i.e. @verbatim<oct><oct><oct>.@endverbatim
225
226/** Set of parsing rules for *unescape_until functions
227 *
228 */
229typedef struct {
230 char const *name; //!< Name for rule set to aid we debugging.
231
232 char chr; //!< Character at the start of an escape sequence.
233
234 char subs[SBUFF_CHAR_CLASS]; //!< Special characters and their substitutions.
235 ///< Indexed by the binary representation i.e.
236 ///< 0x0a for \n.
237 bool esc[SBUFF_CHAR_CLASS]; //!< Characters that should be translated to hex or
238 ///< octal escape sequences.
239 bool do_utf8; //!< If true Don't apply escaping rules to valid UTF-8 sequences.
240
241 bool do_hex; //!< Represent escaped chars as hex sequences i.e.
242 ///< @verbatim\x<hex><hex>@endverbatim
243 bool do_oct; //!< Represent escapes chars as octal sequences i.e.
244 ///< @verbatim<oct><oct><oct>@endvertbatim
246
247/** A set of terminal sequences, and escape rules
248 *
249 */
250typedef struct {
251 fr_sbuff_unescape_rules_t const *escapes; //!< Escape characters
252
253 fr_sbuff_term_t const *terminals; //!< Terminal characters used as a hint
254 ///< that a token is not complete.
255} fr_sbuff_parse_rules_t;
256
257/** Standard parsing errors to be used by sbuff functions and other sbuff based parsing functions
258 *
259 */
260typedef enum {
261 FR_SBUFF_PARSE_OK = 0, //!< No error.
262 FR_SBUFF_PARSE_ERROR_NOT_FOUND = -1, //!< String does not contain a token
263 ///< matching the output type.
264 FR_SBUFF_PARSE_ERROR_TRAILING = -2, //!< Trailing characters found.
265 FR_SBUFF_PARSE_ERROR_FORMAT = -3, //!< Format of data was invalid.
266 FR_SBUFF_PARSE_ERROR_OUT_OF_SPACE = -4, //!< No space available in output buffer.
267 FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW = -5, //!< Integer type would overflow.
268 FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW = -6, //!< Integer type would underflow.
269 FR_SBUFF_PARSE_ERROR_INPUT_EMPTY = -7, //!< Input is empty, and should not be empty
271
273extern size_t sbuff_parse_error_table_len;
274
275/** Replace the contents of the thread local error stack with the string representation of a parse error
276 */
277static inline void fr_sbuff_parse_error_to_strerror(fr_sbuff_parse_error_t err)
278{
280}
281
282/** Return whether the sbuff is extendable
283 */
284static inline bool fr_sbuff_is_extendable(fr_sbuff_t *sbuff)
285{
286 return sbuff->extend && (!sbuff->eof || (sbuff->eof(sbuff) == false));
287}
288
289#define fr_sbuff_was_extended(_status) (_status & FR_SBUFF_FLAG_EXTENDED)
290
291extern bool const sbuff_char_class_uint[SBUFF_CHAR_CLASS];
292extern bool const sbuff_char_class_int[SBUFF_CHAR_CLASS];
294extern bool const sbuff_char_class_zero[SBUFF_CHAR_CLASS];
295extern bool const sbuff_char_class_hex[SBUFF_CHAR_CLASS];
296extern bool const sbuff_char_alpha_num[SBUFF_CHAR_CLASS];
297extern bool const sbuff_char_word[SBUFF_CHAR_CLASS];
298extern bool const sbuff_char_whitespace[SBUFF_CHAR_CLASS];
300extern bool const sbuff_char_blank[SBUFF_CHAR_CLASS];
302
303/** Matches a-z,A-Z
304 */
305#define SBUFF_CHAR_CLASS_ALPHA \
306 ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true, \
307 ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true, \
308 ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true, \
309 ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true, \
310 ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true, \
311 ['z'] = true, \
312 ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true, \
313 ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true, \
314 ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true, \
315 ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true, \
316 ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true, \
317 ['Z'] = true
318
319/** Matches 0-9
320 */
321#define SBUFF_CHAR_CLASS_NUM \
322 ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, \
323 ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true
324
325/** Matches 0-9,a-z,A-Z
326 */
327#define SBUFF_CHAR_CLASS_ALPHA_NUM \
328 SBUFF_CHAR_CLASS_ALPHA, \
329 SBUFF_CHAR_CLASS_NUM
330
331/** Matches 0-9,a-f,A-F
332 */
333#define SBUFF_CHAR_CLASS_HEX \
334 SBUFF_CHAR_CLASS_NUM, \
335 ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true, \
336 ['f'] = true, \
337 ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true, \
338 ['F'] = true
339
340#define SBUFF_CHAR_CLASS_SYMBOLS \
341 ['!'] = true, ['"'] = true, ['#'] = true, ['$'] = true, ['%'] = true, \
342 ['&'] = true, ['/'] = true, ['('] = true, [')'] = true, ['*'] = true, \
343 ['+'] = true, ['`'] = true, ['-'] = true, ['.'] = true, ['/'] = true, \
344 [':'] = true, [';'] = true, ['<'] = true, ['='] = true, ['>'] = true, \
345 ['?'] = true, ['@'] = true, ['['] = true, ['\''] = true, [']'] = true, \
346 ['^'] = true, ['_'] = true, ['`'] = true, ['{'] = true, ['|'] = true, \
347 ['}'] = true, ['~'] = true \
348
349/*
350 * If the additional tables need to be generated feel free to use this
351 * code snippet.
352 *
353 * @verbatim
354 #include <stdio.h>
355 #include <stdlib.h>
356
357 int main(int argc, char **argv)
358 {
359 int start, end, i;
360 start = atoi(argv[1]);
361 end = atoi(argv[2]);
362 for (i = start; i <= end; i++) {
363 printf("[0x%02x] = true, ", i);
364 if (!(i % 8)) printf("\\\n");
365 }
366 return 0;
367 }
368 * @endverbatim
369 */
370
371/** Unprintables (ascii range)
372 *
373 * We don't include characters in the extended range (128-255) as they're
374 * likely part of a multi-byte sequence and we don't want to break UTF8 strings.
375 */
376#define SBUFF_CHAR_UNPRINTABLES_LOW \
377 [0x00] = true, \
378 [0x01] = true, [0x02] = true, [0x03] = true, [0x04] = true, [0x05] = true, [0x06] = true, [0x07] = true, [0x08] = true, \
379 [0x09] = true, [0x0a] = true, [0x0b] = true, [0x0c] = true, [0x0d] = true, [0x0e] = true, [0x0f] = true, [0x10] = true, \
380 [0x11] = true, [0x12] = true, [0x13] = true, [0x14] = true, [0x15] = true, [0x16] = true, [0x17] = true, [0x18] = true, \
381 [0x19] = true, [0x1a] = true, [0x1b] = true, [0x1c] = true, [0x1d] = true, [0x1e] = true, [0x1f] = true, \
382 [0x7f] = true
383
384/** Unprintables (extended range)
385 *
386 * If these characters are being escaped, the function should also be passed
387 * the 'do_utf8' flag.
388 */
389#define SBUFF_CHAR_UNPRINTABLES_EXTENDED \
390 [0x80] = true, \
391 [0x81] = true, [0x82] = true, [0x83] = true, [0x84] = true, [0x85] = true, [0x86] = true, [0x87] = true, [0x88] = true, \
392 [0x89] = true, [0x8a] = true, [0x8b] = true, [0x8c] = true, [0x8d] = true, [0x8e] = true, [0x8f] = true, [0x90] = true, \
393 [0x91] = true, [0x92] = true, [0x93] = true, [0x94] = true, [0x95] = true, [0x96] = true, [0x97] = true, [0x98] = true, \
394 [0x99] = true, [0x9a] = true, [0x9b] = true, [0x9c] = true, [0x9d] = true, [0x9e] = true, [0x9f] = true, [0xa0] = true, \
395 [0xa1] = true, [0xa2] = true, [0xa3] = true, [0xa4] = true, [0xa5] = true, [0xa6] = true, [0xa7] = true, [0xa8] = true, \
396 [0xa9] = true, [0xaa] = true, [0xab] = true, [0xac] = true, [0xad] = true, [0xae] = true, [0xaf] = true, [0xb0] = true, \
397 [0xb1] = true, [0xb2] = true, [0xb3] = true, [0xb4] = true, [0xb5] = true, [0xb6] = true, [0xb7] = true, [0xb8] = true, \
398 [0xb9] = true, [0xba] = true, [0xbb] = true, [0xbc] = true, [0xbd] = true, [0xbe] = true, [0xbf] = true, [0xc0] = true, \
399 [0xc1] = true, [0xc2] = true, [0xc3] = true, [0xc4] = true, [0xc5] = true, [0xc6] = true, [0xc7] = true, [0xc8] = true, \
400 [0xc9] = true, [0xca] = true, [0xcb] = true, [0xcc] = true, [0xcd] = true, [0xce] = true, [0xcf] = true, [0xd0] = true, \
401 [0xd1] = true, [0xd2] = true, [0xd3] = true, [0xd4] = true, [0xd5] = true, [0xd6] = true, [0xd7] = true, [0xd8] = true, \
402 [0xd9] = true, [0xda] = true, [0xdb] = true, [0xdc] = true, [0xdd] = true, [0xde] = true, [0xdf] = true, [0xe0] = true, \
403 [0xe1] = true, [0xe2] = true, [0xe3] = true, [0xe4] = true, [0xe5] = true, [0xe6] = true, [0xe7] = true, [0xe8] = true, \
404 [0xe9] = true, [0xea] = true, [0xeb] = true, [0xec] = true, [0xed] = true, [0xee] = true, [0xef] = true, [0xf0] = true, \
405 [0xf1] = true, [0xf2] = true, [0xf3] = true, [0xf4] = true, [0xf5] = true, [0xf6] = true, [0xf7] = true, [0xf8] = true, \
406 [0xf9] = true, [0xfa] = true, [0xfb] = true, [0xfc] = true, [0xfd] = true, [0xfe] = true, [0xff] = true
407
408/** Generic wrapper macro to return if there's insufficient memory to satisfy the request on the sbuff
409 *
410 */
411#define FR_SBUFF_RETURN(_func, _sbuff, ...) \
412do { \
413 ssize_t _slen; \
414 _slen = _func(_sbuff, ## __VA_ARGS__ ); \
415 if (_slen < 0) return _slen; \
416} while (0)
417
418/** @name Ephemeral copying macros
419 * @{
420 */
421
422/** @cond */
423
424/** Copy another fr_sbuff_t, modifying it.
425 *
426 * @private
427 */
428#define _FR_SBUFF(_sbuff_or_marker, _start, _current, _end, _extend, _eof, _adv_parent) \
429((fr_sbuff_t){ \
430 .buff = fr_sbuff_buff(_sbuff_or_marker), \
431 .start = (_start), \
432 .end = (_end), \
433 .p = (_current), \
434 .is_const = fr_sbuff_ptr(_sbuff_or_marker)->is_const, \
435 .adv_parent = (_adv_parent), \
436 .shifted = 0, \
437 .extend = (_extend), \
438 .eof = (_eof), \
439 .uctx = fr_sbuff_ptr(_sbuff_or_marker)->uctx, \
440 .parent = fr_sbuff_ptr(_sbuff_or_marker) \
441})
442/* @endcond */
443
444/** Create a new sbuff pointing to the same underlying buffer
445 *
446 * - Parent will _NOT_ be advanced by operations on its child.
447 * - Child will have its `start` pointer set to the `p` pointer of the parent.
448 *
449 * @param[in] _sbuff_or_marker to make an ephemeral copy of.
450 */
451#define FR_SBUFF(_sbuff_or_marker) _FR_SBUFF(_sbuff_or_marker, \
452 fr_sbuff_current(_sbuff_or_marker), \
453 fr_sbuff_current(_sbuff_or_marker), \
454 fr_sbuff_end(_sbuff_or_marker), \
455 fr_sbuff_ptr(_sbuff_or_marker)->extend, \
456 fr_sbuff_ptr(_sbuff_or_marker)->eof, \
457 0x00)
458
459/** Create a new sbuff pointing to the same underlying buffer
460 *
461 * - Parent will _NOT_ be advanced by operations on its child.
462 * - Child will have its `start` pointer set to the `start` pointer of the parent.
463 *
464 * @param[in] _sbuff_or_marker to make an ephemeral copy of.
465 */
466#define FR_SBUFF_ABS(_sbuff_or_marker) _FR_SBUFF(_sbuff_or_marker, \
467 fr_sbuff_start(_sbuff_or_marker), \
468 fr_sbuff_current(_sbuff_or_marker), \
469 fr_sbuff_end(_sbuff_or_marker), \
470 fr_sbuff_ptr(_sbuff_or_marker)->extend, \
471 0x00)
472
473/** Create a new sbuff pointing to the same underlying buffer
474 *
475 * The intent of this sbuff type is to allow parsing operations to be performed
476 * on a subset of the buffer data.
477 *
478 * - Parent will _NOT_ be advanced by operations on its child.
479 * - Child will have its `start` pointer set to the `start` pointer of the parent.
480 * - Child will have its `end` pointer set to the `p` pointer of the parent.
481 * - Child will not extend parent.
482 *
483 * @param[in] _sbuff_or_marker to make an ephemeral copy of.
484 */
485#define FR_SBUFF_REPARSE(_sbuff_or_marker) _FR_SBUFF(_sbuff_or_marker, \
486 fr_sbuff_start(_sbuff_or_marker), \
487 fr_sbuff_start(_sbuff_or_marker), \
488 fr_sbuff_current(_sbuff_or_marker), \
489 NULL, \
490 NULL, \
491 0x00)
492
493/** Create a new sbuff pointing to the same underlying buffer
494 *
495 * - Parent `p` pointer will be advanced with child's `p` pointer.
496 * - Child will have its `start` pointer set to the `p` pointer of the parent.
497 *
498 * @param[in] _sbuff_or_marker to make an ephemeral copy of.
499 */
500#define FR_SBUFF_BIND_CURRENT(_sbuff_or_marker) _FR_SBUFF(_sbuff_or_marker, \
501 fr_sbuff_current(_sbuff_or_marker), \
502 fr_sbuff_current(_sbuff_or_marker), \
503 fr_sbuff_end(_sbuff_or_marker), \
504 fr_sbuff_ptr(_sbuff_or_marker)->extend, \
505 fr_sbuff_ptr(_sbuff_or_marker)->eof, \
506 0x01)
507
508/** Create a new sbuff pointing to the same underlying buffer
509 *
510 * - Parent `p` pointer will be advanced with child's `p` pointer.
511 * - Child will have its `start` pointer set to the `start` pointer of the parent.
512 *
513 * @param[in] _sbuff_or_marker to make an ephemeral copy of.
514 */
515#define FR_SBUFF_BIND_CURRENT_ABS(_sbuff_or_marker) FR_SBUFF_ABS(_sbuff_or_marker, \
516 fr_sbuff_start(_sbuff_or_marker), \
517 fr_sbuff_current(_sbuff_or_marker), \
518 fr_sbuff_end(_sbuff_or_marker), \
519 fr_sbuff_ptr(_sbuff_or_marker)->extend, \
520 fr_sbuff_ptr(_sbuff_or_marker)->eof, \
521 0x01)
522
523/** Creates an empty sbuff which can then be used as a destination for printing
524 *
525 * @note The return value of the function should be used to determine how much
526 * data was written to the buffer.
527 *
528 * @param[in] _start of the buffer.
529 * @param[in] _len_or_end Length of the buffer or the end pointer.
530 */
531#define FR_SBUFF_OUT(_start, _len_or_end) \
532((fr_sbuff_t){ \
533 .buff_i = _start, \
534 .start_i = _Generic((_start), \
535 char * : _start, \
536 uint8_t * : _start \
537 ), \
538 .end_i = _Generic((_len_or_end), \
539 size_t : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
540 long : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
541 int : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
542 unsigned int : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
543 char * : (char const *)(_len_or_end), \
544 char const * : (char const *)(_len_or_end) \
545 ), \
546 .p_i = _start, \
547 .is_const = false, \
548})
549
550/** Creates an sbuff from existing data, so the caller can read from it.
551 *
552 * @note The return value of the function should be used to determine how much
553 * data was written to the buffer.
554 *
555 * @param[in] _start of the buffer.
556 * @param[in] _len_or_end Length of the buffer or the end pointer.
557 */
558#define FR_SBUFF_IN(_start, _len_or_end) \
559((fr_sbuff_t){ \
560 .buff_i = _start, \
561 .start_i = _Generic((_start), \
562 char * : _start, \
563 char const * : _start, \
564 uint8_t * : _start, \
565 uint8_t const * : _start \
566 ), \
567 .end_i = _Generic((_len_or_end), \
568 size_t : (char const *)(_start) + (size_t)(_len_or_end), \
569 long : (char const *)(_start) + (size_t)(_len_or_end), \
570 int : (char const *)(_start) + (size_t)(_len_or_end), \
571 unsigned int : (char const *)(_start) + (size_t)(_len_or_end), \
572 char * : (char const *)(_len_or_end), \
573 char const * : (char const *)(_len_or_end) \
574 ), \
575 .p_i = _start, \
576 .is_const = true, \
577})
578
579#define FR_SBUFF_IN_STR(_start) FR_SBUFF_IN(_start, strlen(_start))
580
581/** Structure to encapsulate a thread local sbuff information
582 *
583 */
584typedef struct {
585 fr_sbuff_t sbuff; //!< Thread local sbuff.
586 fr_sbuff_uctx_talloc_t tctx; //!< Thread local tctx.
587} fr_sbuff_thread_local_t;
588
589static inline int _sbuff_thread_local_free(void *sbtl)
590{
591 return talloc_free(sbtl);
592}
593
594/** Create a function local and thread local extensible sbuff
595 *
596 * @param[out] _sbuff_out Where to write a pointer to the thread local sbuff
597 * @param[in] _init Initial size for the sbuff buffer.
598 * @param[in] _max Maximum size of the sbuff buffer.
599 */
600#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max) \
601do { \
602 static _Thread_local fr_sbuff_thread_local_t *_sbuff_t_local; \
603 if (!_sbuff_t_local) { \
604 fr_sbuff_thread_local_t *sbtl = talloc_zero(NULL, fr_sbuff_thread_local_t); \
605 fr_sbuff_init_talloc(sbtl, &sbtl->sbuff, &sbtl->tctx, _init, _max); \
606 fr_atexit_thread_local(_sbuff_t_local, _sbuff_thread_local_free, sbtl); \
607 *(_out) = &_sbuff_t_local->sbuff; \
608 } else { \
609 fr_sbuff_reset_talloc(&_sbuff_t_local->sbuff); \
610 *(_out) = &_sbuff_t_local->sbuff; \
611 } \
612} while (0)
613
614void fr_sbuff_update(fr_sbuff_t *sbuff, char *new_buff, size_t new_len);
615
616size_t fr_sbuff_shift(fr_sbuff_t *sbuff, size_t shift, bool move_end);
617
618size_t fr_sbuff_extend_file(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t extension);
619
620bool fr_sbuff_eof_file(fr_sbuff_t *sbuff);
621
622size_t fr_sbuff_extend_talloc(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t extension);
623
624int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len);
625
626int fr_sbuff_reset_talloc(fr_sbuff_t *sbuff);
627
628static inline void fr_sbuff_terminate(fr_sbuff_t *sbuff)
629{
630 *sbuff->p = '\0';
631}
632
633static inline void _fr_sbuff_init(fr_sbuff_t *out, char const *start, char const *end, bool is_const)
634{
635 if (unlikely(end < start)) end = start; /* Could be an assert? */
636
637 *out = (fr_sbuff_t){
638 .buff_i = start,
639 .start_i = start,
640 .p_i = start,
641 .end_i = end,
642 .is_const = is_const
643 };
644}
645
646/*
647 * GCC is stupid and will warn about output variables
648 * being unnitialised, even if they're not dereferenced.
649 */
650#if defined(__GNUC__) && __GNUC__ >= 11
651DIAG_OFF(maybe-uninitialized)
652#endif
653
654/** Initialise an sbuff around a stack allocated buffer for printing
655 *
656 * Will \0 terminate the output buffer.
657 *
658 * @param[out] _out Pointer to buffer.
659 * @param[in] _start Start of the buffer. Cannot be const.
660 * @param[in] _len_or_end Either an end pointer or the length
661 * of the buffer. 'end' can be const.
662 */
663#define fr_sbuff_init_out(_out, _start, _len_or_end) \
664do { \
665 *(_start) = '\0'; \
666 _fr_sbuff_init(_out, _start, \
667 _Generic((_len_or_end), \
668 size_t : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
669 long : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
670 int : (char const *)(_start) + ((size_t)(_len_or_end) - 1), \
671 char * : (char const *)(_len_or_end), \
672 char const * : (char const *)(_len_or_end) \
673 ), \
674 false); \
675} while (0)
676
677#if defined(__GNUC__) && __GNUC__ >= 11
678DIAG_ON(maybe-uninitialized)
679#endif
680
681/** Initialise an sbuff around a stack allocated buffer for parsing
682 *
683 * @param[out] _out Pointer to buffer.
684 * @param[in] _start Start of the buffer.
685 * @param[in] _len_or_end Either an end pointer or the length
686 * of the buffer.
687 */
688#define fr_sbuff_init_in(_out, _start, _len_or_end) \
689_fr_sbuff_init(_out, _start, \
690_Generic((_len_or_end), \
691 size_t : (char const *)(_start) + (size_t)(_len_or_end), \
692 long : (char const *)(_start) + (size_t)(_len_or_end), \
693 int : (char const *)(_start) + (size_t)(_len_or_end), \
694 char * : (char const *)(_len_or_end), \
695 char const * : (char const *)(_len_or_end) \
696), \
697IS_CONST(char *, _start))
698
699/** Initialise a special sbuff which automatically reads in more data as the buffer is exhausted
700 *
701 * @param[out] sbuff to initialise.
702 * @param[out] fctx to initialise. Must have a lifetime >= to the sbuff.
703 * @param[in] buff Temporary buffer to use for storing file contents.
704 * @param[in] len Length of the temporary buffer.
705 * @param[in] file to read from.
706 * @param[in] max The maximum length of data to read from the file.
707 * @return
708 * - The passed sbuff on success.
709 * - NULL on failure.
710 */
711static inline fr_sbuff_t *fr_sbuff_init_file(fr_sbuff_t *sbuff, fr_sbuff_uctx_file_t *fctx,
712 char *buff, size_t len, FILE *file, size_t max)
713{
714 *fctx = (fr_sbuff_uctx_file_t){
715 .file = file,
716 .max = max,
717 .buff_end = buff + len //!< Store the real end
718 };
719
720 *sbuff = (fr_sbuff_t){
721 .buff = buff,
722 .start = buff,
723 .p = buff,
724 .end = buff, //!< Starts with 0 bytes available
725 .extend = fr_sbuff_extend_file,
726 .eof = fr_sbuff_eof_file,
727 .uctx = fctx
728 };
729
730 return sbuff;
731}
732
733/** Initialise a special sbuff which automatically extends as additional data is written
734 *
735 * @param[in] ctx to allocate buffer in.
736 * @param[out] sbuff to initialise.
737 * @param[out] tctx to initialise. Must have a lifetime >= to the sbuff.
738 * @param[in] init The length of the initial buffer, excluding \0 byte.
739 * @param[in] max The maximum length of the buffer.
740 * @return
741 * - The passed sbuff on success.
742 * - NULL on failure.
743 */
744static inline fr_sbuff_t *fr_sbuff_init_talloc(TALLOC_CTX *ctx,
745 fr_sbuff_t *sbuff, fr_sbuff_uctx_talloc_t *tctx,
746 size_t init, size_t max)
747{
748 char *buff;
749
750 *tctx = (fr_sbuff_uctx_talloc_t){
751 .ctx = ctx,
752 .init = init,
753 .max = max
754 };
755
756 /*
757 * Allocate the initial buffer
758 *
759 * We always allocate a buffer so we don't
760 * trigger ubsan errors by performing
761 * arithmetic on NULL pointers.
762 */
763 buff = talloc_zero_array(ctx, char, init + 1);
764 if (!buff) {
765 fr_strerror_printf("Failed allocating buffer of %zu bytes", init + 1);
766 memset(sbuff, 0, sizeof(*sbuff)); /* clang scan */
767 return NULL;
768 }
769
770 *sbuff = (fr_sbuff_t){
771 .buff = buff,
772 .start = buff,
773 .p = buff,
774 .end = buff + init,
775 .extend = fr_sbuff_extend_talloc,
776 .uctx = tctx
777 };
778
779 return sbuff;
780}
781/** @} */
782
783/** @name Accessors
784 *
785 * Caching the values of these pointers or the pointer values from the sbuff
786 * directly is strongly discouraged as they can become invalidated during
787 * stream parsing or when printing to an auto-expanding buffer.
788 *
789 * These functions should only be used to pass sbuff pointers into 3rd party
790 * APIs.
791 *
792 * @{
793 */
794
795/** Return a pointer to the sbuff
796 *
797 * @param[in] _sbuff_or_marker to return a pointer to.
798 * @return A pointer to the sbuff.
799 */
800#define fr_sbuff_ptr(_sbuff_or_marker) \
801 _Generic((_sbuff_or_marker), \
802 fr_sbuff_t * : ((fr_sbuff_t *)(_sbuff_or_marker)), \
803 fr_sbuff_marker_t * : ((fr_sbuff_marker_t *)(_sbuff_or_marker))->parent \
804 )
805
806/** Return a pointer to the start of the underlying buffer in an sbuff or one of its markers
807 *
808 * @param[in] _sbuff_or_marker to return the buffer for.
809 * @return A pointer to the start of the buffer.
810 */
811#define fr_sbuff_buff(_sbuff_or_marker) \
812 _Generic((_sbuff_or_marker), \
813 fr_sbuff_t * : ((fr_sbuff_t const *)(_sbuff_or_marker))->buff, \
814 fr_sbuff_t const * : ((fr_sbuff_t const *)(_sbuff_or_marker))->buff, \
815 fr_sbuff_marker_t * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->buff, \
816 fr_sbuff_marker_t const * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->buff \
817 )
818
819/** Return a pointer to the 'start' position of an sbuff or one of its markers
820 *
821 * The start position is not necessarily the start of the buffer, and is
822 * advanced every time an sbuff is copied.
823 *
824 * @param[in] _sbuff_or_marker to return the start position of.
825 * @return A pointer to the start position of the buffer.
826 */
827#define fr_sbuff_start(_sbuff_or_marker) \
828 (_Generic((_sbuff_or_marker), \
829 fr_sbuff_t * : ((fr_sbuff_t const *)(_sbuff_or_marker))->start, \
830 fr_sbuff_t const * : ((fr_sbuff_t const *)(_sbuff_or_marker))->start, \
831 fr_sbuff_marker_t * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->start, \
832 fr_sbuff_marker_t const * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->start \
833 ))
834
835/** Return a pointer to the 'current' position of an sbuff or one of its markers
836 *
837 * @note Should not be derferenced as it may point past the end of the buffer.
838 * Use #fr_sbuff_char to get the current char.
839 *
840 * @param[in] _sbuff_or_marker to return the current position of.
841 * @return A pointer to the current position of the buffer or marker.
842 */
843#define fr_sbuff_current(_sbuff_or_marker) \
844 (_Generic((_sbuff_or_marker), \
845 fr_sbuff_t * : ((fr_sbuff_t const *)(_sbuff_or_marker))->p, \
846 fr_sbuff_t const * : ((fr_sbuff_t const *)(_sbuff_or_marker))->p, \
847 fr_sbuff_marker_t * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->p, \
848 fr_sbuff_marker_t const * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->p \
849 ))
850
851/** Return a pointer to the 'end' position of an sbuff or one of its markers
852 *
853 * @param[in] _sbuff_or_marker to return the end position of.
854< * @return A pointer to the end position of the buffer or marker.
855 */
856#define fr_sbuff_end(_sbuff_or_marker) \
857 (_Generic((_sbuff_or_marker), \
858 fr_sbuff_t * : ((fr_sbuff_t const *)(_sbuff_or_marker))->end, \
859 fr_sbuff_t const * : ((fr_sbuff_t const *)(_sbuff_or_marker))->end, \
860 fr_sbuff_marker_t * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->end, \
861 fr_sbuff_marker_t const * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->end \
862 ))
863
864/** Return the value of the shifted field
865 *
866 * @param[in] _sbuff_or_marker to return the position of.
867 * @return the number of bytes the buffer has been shifted.
868 */
869#define fr_sbuff_shifted(_sbuff_or_marker) \
870 (_Generic((_sbuff_or_marker), \
871 fr_sbuff_t * : ((fr_sbuff_t const *)(_sbuff_or_marker))->shifted, \
872 fr_sbuff_t const * : ((fr_sbuff_t const *)(_sbuff_or_marker))->shifted, \
873 fr_sbuff_marker_t * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->shifted, \
874 fr_sbuff_marker_t const * : ((fr_sbuff_marker_t const *)(_sbuff_or_marker))->parent->shifted \
875 ))
876
877/** Return the current char pointed to by the sbuff or '\0' if no more chars remain
878 *
879 * @note Should be used in place of #fr_sbuff_current if switching over the current char.
880 *
881 * @param[in] _sbuff_or_marker to return the current char from.
882 * @param[in] _eob char used to indicate End of Buffer, usually '\0'.
883 * @return The current char pointed to be the sbuff.
884 */
885#define fr_sbuff_char(_sbuff_or_marker, _eob) \
886 (fr_sbuff_current(_sbuff_or_marker) >= fr_sbuff_end(_sbuff_or_marker) ? _eob : *fr_sbuff_current(_sbuff_or_marker))
887
888/** Start a switch block over the current sbuff char
889 *
890 * @note '\0' is used to indicate EOB.
891 *
892 * @param[in] _sbuff_or_marker to return the current char from.
893 * @param[in] _eob char used to indicate End of Buffer, usually '\0'.
894 */
895#define fr_sbuff_switch(_sbuff_or_marker, _eob) \
896 switch (fr_sbuff_char(_sbuff_or_marker, _eob))
897/** @} */
898
899/** @name Length calculations
900 * @{
901 */
902
903/** Return the difference in position between the two sbuffs or markers
904 *
905 * @param[in] _a The first sbuff or marker.
906 * @param[in] _b The second sbuff or marker.
907 * @return
908 * - >0 the number of bytes _a is ahead of _b.
909 * - 0 _a and _b are the same position.
910 * - <0 the number of bytes _a is behind of _b.
911 */
912#define fr_sbuff_diff(_a, _b) \
913 ((ssize_t)(fr_sbuff_current(_a) - fr_sbuff_current(_b)))
914
915/** Return the number of bytes remaining between the sbuff or marker and the end of the buffer
916 *
917 * @note Do not use this in functions that may be used for stream parsing
918 * unless you're sure you know what you're doing.
919 * The value return does not reflect the number of bytes that may
920 * be potentially read from the stream, only the number of bytes
921 * until the end of the current chunk.
922 *
923 * @param[in] _sbuff_or_marker to return the number of bytes remaining for.
924 * @return
925 * - >0 the number of bytes remaining before we reach the end of the buffer.
926 * - -0 we're at the end of the buffer.
927 */
928#define fr_sbuff_remaining(_sbuff_or_marker) \
929 ((size_t)(fr_sbuff_end(_sbuff_or_marker) < fr_sbuff_current(_sbuff_or_marker) ? \
930 0 : (fr_sbuff_end(_sbuff_or_marker) - fr_sbuff_current(_sbuff_or_marker))))
931
932/** Return the number of bytes remaining between the start of the sbuff or marker and the current position
933 *
934 * @param[in] _sbuff_or_marker to return the number of bytes used for.
935 * @return
936 * - >0 the number of bytes the current position has advanced past the start.
937 * - -0 the current position is at the start of the buffer.
938 */
939#define fr_sbuff_used(_sbuff_or_marker) \
940 ((size_t)(fr_sbuff_start(_sbuff_or_marker) > fr_sbuff_current(_sbuff_or_marker) ? \
941 0 : (fr_sbuff_current(_sbuff_or_marker) - fr_sbuff_start(_sbuff_or_marker))))
942
943/** Sets an error marker in the parent
944 *
945 * If an error already exists at this level it will be used instead of the provided error.
946 *
947 * @param[in] sbuff who's parent we'll set the error marker in.
948 * @param[in] err marker to set.
949 * @return <0 the negative offset of the error.
950 */
951static inline fr_slen_t _fr_sbuff_error(fr_sbuff_t *sbuff, char const *err)
952{
953 fr_sbuff_t *parent = sbuff->parent;
954 fr_slen_t slen;
955
956 if (sbuff->err) err = sbuff->err;
957 if (parent) parent->err = err;
958
959 slen = -((err - fr_sbuff_start(sbuff)) + 1);
960
961#ifdef __clang_analyzer__
962 /*
963 * Convince clang that the return value
964 * is always negative. It never can be
965 * else the sbuff code is very broken.
966 */
967 if (slen >= 0) return -1;
968#endif
969
970 return slen;
971}
972
973/** Return the current position as an error marker
974 *
975 * @param[in] _sbuff_or_marker Error marker will be set from the current position of this sbuff.
976 *
977 * +1 is added to the position to disambiguate with 0 meaning "parsed no data".
978 *
979 * An error at offset 0 will be returned as -1.
980 */
981#define fr_sbuff_error(_sbuff_or_marker) \
982 _fr_sbuff_error(fr_sbuff_ptr(_sbuff_or_marker), fr_sbuff_current(_sbuff_or_marker))
983
984/** Like fr_sbuff_used, but adjusts for the value returned for the amount shifted
985 *
986 * @param[in] _sbuff_or_marker to return the number of bytes used for.
987 * @return
988 * - >0 the number of bytes the current position has advanced past the start +
989 * the amount the buffer has shifted.
990 * - -0 the current position is at the start of the buffer (and hasn't been shifted).
991 */
992#define fr_sbuff_used_total(_sbuff_or_marker) \
993 ((size_t)((fr_sbuff_current(_sbuff_or_marker) + fr_sbuff_shifted(_sbuff_or_marker)) - fr_sbuff_start(_sbuff_or_marker)))
994
995/** The length of the underlying buffer
996 *
997 * @param[in] _sbuff_or_marker to return the length of.
998 * @return The length of the underlying buffer (minus 1 byte for \0).
999 */
1000#define fr_sbuff_len(_sbuff_or_marker) \
1001 ((size_t)(fr_sbuff_end(_sbuff_or_marker) - fr_sbuff_buff(_sbuff_or_marker)))
1002
1003/** How many bytes the sbuff or marker is behind its parent
1004 *
1005 * @param[in] _sbuff_or_marker
1006 * @return
1007 * - 0 the sbuff or marker is ahead of its parent.
1008 * - >0 the number of bytes the marker is behind its parent.
1009 */
1010#define fr_sbuff_behind(_sbuff_or_marker) \
1011 (fr_sbuff_current(_sbuff_or_marker) > fr_sbuff_current((_sbuff_or_marker)->parent) ? \
1012 0 : fr_sbuff_current((_sbuff_or_marker)->parent) - fr_sbuff_current(_sbuff_or_marker))
1013
1014/** How many bytes the sbuff or marker is ahead of its parent
1015 *
1016 * @return
1017 * - 0 the sbuff or marker is behind its parent.
1018 * - >0 the number of bytes the marker is ahead of its parent.
1019 */
1020#define fr_sbuff_ahead(_sbuff_or_marker) \
1021 (fr_sbuff_current((_sbuff_or_marker)->parent) > fr_sbuff_current(_sbuff_or_marker) ? \
1022 0 : fr_sbuff_current(_sbuff_or_marker) - fr_sbuff_current((_sbuff_or_marker)->parent))
1023
1024/** Return the current position in the sbuff as a negative offset
1025 *
1026 */
1027#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker) return fr_sbuff_error(_sbuff_or_marker)
1028
1029/** Check if _len bytes are available in the sbuff, and if not return the number of bytes we'd need
1030 *
1031 */
1032#define FR_SBUFF_CHECK_REMAINING_RETURN(_sbuff, _len) \
1033 if ((_len) > fr_sbuff_remaining(_sbuff)) return -((_len) - fr_sbuff_remaining(_sbuff))
1034
1035static inline size_t _fr_sbuff_extend_lowat(fr_sbuff_extend_status_t *status, fr_sbuff_t *in, size_t remaining, size_t lowat)
1036{
1037 size_t extended;
1038 fr_sbuff_extend_status_t our_status = 0;
1039
1040 if (!fr_sbuff_is_extendable(in)) {
1041 no_extend:
1042 if (status) *status = our_status;
1043 return remaining;
1044 }
1045
1046 /* Still have data remaining, no need to try and extend */
1047 if (remaining >= lowat) goto no_extend;
1048
1049 if (!in->extend || ((extended = in->extend(&our_status, in, lowat - remaining)) == 0)) {
1050 goto no_extend;
1051 }
1052
1053 our_status |= FR_SBUFF_FLAG_EXTENDED;
1054
1055 if (status) *status = our_status;
1056 return remaining + extended;
1057}
1058
1059/** Extend a buffer if we're below the low water mark
1060 *
1061 * @param[out] _status Should be initialised to FR_SBUFF_EXTENDABLE
1062 * for the first call to this function if used
1063 * as a loop condition.
1064 * Will be filled with the result of the previous
1065 * call, and can be used to determine if the buffer
1066 * was extended.
1067 * @param[in] _sbuff_or_marker to extend.
1068 * @param[in] _lowat If bytes remaining are below the amount, extend.
1069 * @return
1070 * - 0 if there are no bytes left in the buffer and we couldn't extend.
1071 * - >0 the number of bytes in the buffer after extending.
1072 */
1073#define fr_sbuff_extend_lowat(_status, _sbuff_or_marker, _lowat) \
1074 _fr_sbuff_extend_lowat(_status, \
1075 fr_sbuff_ptr(_sbuff_or_marker), \
1076 fr_sbuff_remaining(_sbuff_or_marker), _lowat)
1077
1078/** Check if _len bytes are available in the sbuff and extend the buffer if possible
1079 *
1080 * If we do not have _len bytes in the sbuff after extending, then return.
1081 *
1082 * @param[in] _sbuff to extend.
1083 * @param[in] _len The minimum amount the sbuff should be extended by.
1084 * @return The number of bytes we would need to satisfy _len as a negative integer.
1085 */
1086#define FR_SBUFF_EXTEND_LOWAT_OR_RETURN(_sbuff, _len) \
1087do { \
1088 size_t _remaining = fr_sbuff_extend_lowat(NULL, _sbuff, _len); \
1089 if (_remaining < _len) return -(_len - _remaining); \
1090} while (0)
1091
1092/** Extend a buffer if no space remains
1093 *
1094 * @param[in] _sbuff_or_marker to extend.
1095 * @return
1096 * - 0 if there are no bytes left in the buffer and we couldn't extend.
1097 * - >0 the number of bytes in the buffer after extending.
1098 */
1099#define fr_sbuff_extend(_sbuff_or_marker) fr_sbuff_extend_lowat(NULL, _sbuff_or_marker, 1)
1100
1101/** @} */
1102
1103/** @name Position modification (recursive)
1104 *
1105 * Change the current position of pointers in the sbuff and their children.
1106 * @{
1107 */
1108
1109/** Update the position of p in a list of sbuffs
1110 *
1111 * @note Do not call directly.
1112 */
1113static inline void _fr_sbuff_set_recurse(fr_sbuff_t *sbuff, char const *p)
1114{
1115 sbuff->p_i = p;
1116 sbuff->err = NULL; /* Modifying the position of the sbuff clears the error */
1117
1118 if (sbuff->adv_parent && sbuff->parent) _fr_sbuff_set_recurse(sbuff->parent, p);
1119}
1120
1121static inline ssize_t _fr_sbuff_marker_set(fr_sbuff_marker_t *m, char const *p)
1122{
1123 fr_sbuff_t *sbuff = m->parent;
1124 char *current = m->p;
1125
1126 if (unlikely(p > sbuff->end)) return -(p - sbuff->end);
1127 if (unlikely(p < sbuff->start)) return 0;
1128
1129 sbuff->err = NULL; /* Modifying the position of any markers clears the error, unsure if this is correct? */
1130 m->p_i = p;
1131
1132 return p - current;
1133}
1134
1135static inline ssize_t _fr_sbuff_set(fr_sbuff_t *sbuff, char const *p)
1136{
1137 char const *c;
1138
1139 if (unlikely(p > sbuff->end)) return -(p - sbuff->end);
1140 if (unlikely(p < sbuff->start)) return 0;
1141
1142 c = sbuff->p;
1143 _fr_sbuff_set_recurse(sbuff, p);
1144
1145 return p - c;
1146}
1147
1148/** Set the position in a sbuff using another sbuff, a char pointer, or a length
1149 *
1150 * @param[in] _dst sbuff or marker to set the position for.
1151 * @param[in] _src Variable to glean new position from. Behaviour here
1152 * depends on the type of the variable.
1153 * - sbuff, the current position of the sbuff.
1154 * - marker, the current position of the marker.
1155 * - pointer, the position of the pointer.
1156 * - size_t, _dst->start + _src.
1157 * @return
1158 * - 0 not advanced.
1159 * - >0 the number of bytes the sbuff was advanced by.
1160 * - <0 the number of bytes required to complete the advancement
1161 */
1162#define fr_sbuff_set(_dst, _src) \
1163_Generic((_dst), \
1164 fr_sbuff_t * : _fr_sbuff_set, \
1165 fr_sbuff_marker_t * : _fr_sbuff_marker_set \
1166)(_dst, \
1167_Generic((_src), \
1168 fr_sbuff_t * : fr_sbuff_current((fr_sbuff_t const *)(_src)), \
1169 fr_sbuff_t const * : fr_sbuff_current((fr_sbuff_t const *)(_src)), \
1170 fr_sbuff_marker_t * : fr_sbuff_current((fr_sbuff_marker_t const *)(_src)), \
1171 fr_sbuff_marker_t const * : fr_sbuff_current((fr_sbuff_marker_t const *)(_src)), \
1172 char const * : (char const *)(_src), \
1173 char * : (char const *)(_src), \
1174 size_t : (fr_sbuff_start(_dst) + (uintptr_t)(_src)) \
1175))
1176
1177/** Set an sbuff to a given position, and return how much it was advanced
1178 *
1179 * @param[in] _dst to modify.
1180 * @param[in] _src position to set it too.
1181 * @return The number of bytes _dst was advanced.
1182 */
1183#define FR_SBUFF_SET_RETURN(_dst, _src) return fr_sbuff_set(_dst, _src)
1184
1185/** Advance position in sbuff by N bytes
1186 *
1187 * @param[in] _sbuff_or_marker to advance.
1188 * @param[in] _len How much to advance sbuff by.
1189 * @return
1190 * - 0 not advanced.
1191 * - >0 the number of bytes the sbuff was advanced by.
1192 * - <0 the number of bytes required to complete the advancement
1193 */
1194#define fr_sbuff_advance(_sbuff_or_marker, _len) fr_sbuff_set(_sbuff_or_marker, (fr_sbuff_current(_sbuff_or_marker) + (_len)))
1195#define FR_SBUFF_ADVANCE_RETURN(_sbuff, _len) FR_SBUFF_RETURN(fr_sbuff_advance, _sbuff, _len)
1196
1197/** Reset the current position of the sbuff to the start of the string
1198 *
1199 */
1200static inline void fr_sbuff_set_to_start(fr_sbuff_t *sbuff)
1201{
1202 _fr_sbuff_set_recurse(sbuff, sbuff->start);
1203}
1204
1205/** Reset the current position of the sbuff to the end of the string
1206 *
1207 */
1208static inline void fr_sbuff_set_to_end(fr_sbuff_t *sbuff)
1209{
1210 _fr_sbuff_set_recurse(sbuff, sbuff->end);
1211}
1212/** @} */
1213
1214/** @name Add a marker to an sbuff
1215 *
1216 * Markers are used to indicate an area of the code is working at a particular
1217 * point in a string buffer.
1218 *
1219 * If the sbuff is performing stream parsing, then markers are used to update
1220 * any pointers to the buffer, as the data in the buffer is shifted to make
1221 * room for new data from the stream.
1222 *
1223 * If the sbuff is being used to create strings, then the markers are updated
1224 * if the buffer is re-allocated.
1225 * @{
1226 */
1227
1228/** Adds a new pointer to the beginning of the list of pointers to update
1229 *
1230 * @param[out] m to initialise.
1231 * @param[in] sbuff to associate marker with.
1232 * @return The position the marker was set to.
1233 */
1234static inline char *fr_sbuff_marker(fr_sbuff_marker_t *m, fr_sbuff_t *sbuff)
1235{
1236 *m = (fr_sbuff_marker_t){
1237 .next = sbuff->m, /* Link into the head */
1238 .p = sbuff->p, /* Set the current position in the sbuff */
1239 .parent = sbuff /* Record which sbuff this marker was associated with */
1240 };
1241 sbuff->m = m;
1242
1243 return sbuff->p;
1244}
1245
1246/** Used to update the position of an 'end' position marker
1247 *
1248 * Updates a marker so that it represents a 'constrained' end.
1249 * If max > fr_sbuff_remaining() + fr_sbuff_used_total(), then the marker will
1250 * be set to the end of the sbuff.
1251 *
1252 * Otherwise the marker will be set to the position indicated by
1253 * start + (max - fr_sbuff_used_total()).
1254 *
1255 * This is used to add a constraint on the amount data that can be copied from
1256 * an extendable buffer.
1257 *
1258 * @param[in] m Marker created with #fr_sbuff_marker.
1259 * @param[in] max amount of data we allow to be read from
1260 * the sbuff. May be SIZE_MAX in which
1261 * case there is no constraint imposed
1262 * and the marker is set to the end of the buffer.
1263 */
1264static inline char *fr_sbuff_marker_update_end(fr_sbuff_marker_t *m, size_t max)
1265{
1266 fr_sbuff_t *sbuff = m->parent;
1267 size_t used = fr_sbuff_used_total(sbuff);
1268
1269 m->p = (((max) - (used)) > fr_sbuff_remaining(sbuff) ?
1270 fr_sbuff_end(sbuff) :
1271 fr_sbuff_current(sbuff) + ((max) - (used)));
1272
1273 return m->p;
1274}
1275
1276/** Trims the linked list back to the specified pointer
1277 *
1278 * Pointers should be released in the inverse order to allocation.
1279 *
1280 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1281 * also being removed from the list.
1282 *
1283 * @param[in] m to release.
1284 */
1285static inline void fr_sbuff_marker_release(fr_sbuff_marker_t *m)
1286{
1287 m->parent->m = m->next;
1288
1289#ifndef NDEBUG
1290 memset(m, 0, sizeof(*m)); /* Use after release */
1291#endif
1292}
1293
1294/** Trims the linked list back to the specified pointer and return how many bytes marker was behind p
1295 *
1296 * Pointers should be released in the inverse order to allocation.
1297 *
1298 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1299 * also being removed from the list.
1300 *
1301 * @param[in] m to release.
1302 * @return
1303 * - 0 marker is ahead of p.
1304 * - >0 the number of bytes the marker is behind p.
1305 */
1306static inline size_t fr_sbuff_marker_release_behind(fr_sbuff_marker_t *m)
1307{
1308 size_t len = fr_sbuff_behind(m);
1309 fr_sbuff_marker_release(m);
1310 return len;
1311}
1312
1313/** Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p
1314 *
1315 * Pointers should be released in the inverse order to allocation.
1316 *
1317 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1318 * also being removed from the list.
1319 *
1320 * @param[in] m to release.
1321 * @return
1322 * - 0 marker is ahead of p.
1323 * - >0 the number of bytes the marker is behind p.
1324 */
1325static inline size_t fr_sbuff_marker_release_ahead(fr_sbuff_marker_t *m)
1326{
1327 size_t len = fr_sbuff_ahead(m);
1328 fr_sbuff_marker_release(m);
1329 return len;
1330}
1331
1332/** Trims the linked list back to the specified pointer and return how many bytes marker was behind p
1333 *
1334 * Pointers should be released in the inverse order to allocation.
1335 *
1336 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1337 * also being removed from the list.
1338 *
1339 * @param[in] m to release.
1340 * @return
1341 * - 0 marker is ahead of p.
1342 * - >0 the number of bytes the marker is behind p.
1343 */
1344static inline size_t fr_sbuff_marker_release_reset_behind(fr_sbuff_marker_t *m)
1345{
1346 size_t len = fr_sbuff_behind(m);
1347 fr_sbuff_set(m->parent, m);
1348 fr_sbuff_marker_release(m);
1349 return len;
1350}
1351
1352/** Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p
1353 *
1354 * Pointers should be released in the inverse order to allocation.
1355 *
1356 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1357 * also being removed from the list.
1358 *
1359 * @param[in] m to release.
1360 * @return
1361 * - 0 marker is ahead of p.
1362 * - >0 the number of bytes the marker is behind p.
1363 */
1364static inline size_t fr_sbuff_marker_release_reset_ahead(fr_sbuff_marker_t *m)
1365{
1366 size_t len = fr_sbuff_ahead(m);
1367 fr_sbuff_set(m->parent, m);
1368 fr_sbuff_marker_release(m);
1369 return len;
1370}
1371/** @} */
1372
1373/** @name Copy data between an sbuff/marker
1374 *
1375 * These functions are typically used for moving data between sbuffs
1376 *
1377 * @{
1378 */
1379size_t _fr_sbuff_move_sbuff_to_sbuff(fr_sbuff_t *out, fr_sbuff_t *in, size_t len);
1380
1381size_t _fr_sbuff_move_marker_to_sbuff(fr_sbuff_t *out, fr_sbuff_marker_t *in, size_t len);
1382
1383size_t _fr_sbuff_move_marker_to_marker(fr_sbuff_marker_t *out, fr_sbuff_marker_t *in, size_t len);
1384
1385size_t _fr_sbuff_move_sbuff_to_marker(fr_sbuff_marker_t *out, fr_sbuff_t *in, size_t len);
1386
1387/** Copy in as many bytes as possible from one sbuff or marker to another
1388 *
1389 * @param[in] _out to copy into.
1390 * @param[in] _in to copy from.
1391 * @param[in] _len The maximum length to copy.
1392 * @return Number of bytes copied.
1393 */
1394#define fr_sbuff_move(_out, _in, _len) \
1395 _Generic((_out), \
1396 fr_sbuff_t * : \
1397 _Generic((_in), \
1398 fr_sbuff_t * : _fr_sbuff_move_sbuff_to_sbuff((fr_sbuff_t *)_out, (fr_sbuff_t *)_in, _len), \
1399 fr_sbuff_marker_t * : _fr_sbuff_move_marker_to_sbuff((fr_sbuff_t *)_out, (fr_sbuff_marker_t *)_in, _len) \
1400 ), \
1401 fr_sbuff_marker_t * : \
1402 _Generic((_in), \
1403 fr_sbuff_t * : _fr_sbuff_move_sbuff_to_marker((fr_sbuff_marker_t *)_out, (fr_sbuff_t *)_in, _len), \
1404 fr_sbuff_marker_t * : _fr_sbuff_move_marker_to_marker((fr_sbuff_marker_t *)_out, (fr_sbuff_marker_t *)_in, _len) \
1405 ) \
1406 )
1407/** @} */
1408
1409/** @name Copy/print complete input data to an sbuff
1410 *
1411 * These functions are typically used for printing.
1412 *
1413 * @{
1414 */
1415#define fr_sbuff_in_char(_sbuff, ...) fr_sbuff_in_bstrncpy(_sbuff, ((char []){ __VA_ARGS__ }), sizeof((char []){ __VA_ARGS__ }))
1416#define FR_SBUFF_IN_CHAR_RETURN(_sbuff, ...) FR_SBUFF_RETURN(fr_sbuff_in_bstrncpy, _sbuff, ((char []){ __VA_ARGS__ }), sizeof((char []){ __VA_ARGS__ }))
1417
1418ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str);
1419#define FR_SBUFF_IN_STRCPY_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_strcpy, ##__VA_ARGS__)
1420
1421ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len);
1422#define FR_SBUFF_IN_BSTRNCPY_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_bstrncpy, ##__VA_ARGS__)
1423
1424#define fr_sbuff_in_strcpy_literal(_sbuff, _str) fr_sbuff_in_bstrncpy(_sbuff, _str, sizeof(_str) - 1)
1425#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str) FR_SBUFF_RETURN(fr_sbuff_in_bstrncpy, _sbuff, _str, sizeof(_str) - 1)
1426
1427ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str);
1428#define FR_SBUFF_IN_BSTRCPY_BUFFER_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_bstrcpy_buffer, ##__VA_ARGS__)
1429
1430ssize_t fr_sbuff_in_vsprintf(fr_sbuff_t *sbuff, char const *fmt, va_list ap);
1431#define FR_SBUFF_IN_VSPRINTF_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_vsprintf, ##__VA_ARGS__)
1432
1433ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt, ...);
1434#define FR_SBUFF_IN_SPRINTF_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_sprintf, ##__VA_ARGS__)
1435
1436ssize_t fr_sbuff_in_escape(fr_sbuff_t *sbuff, char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules);
1437#define FR_SBUFF_IN_ESCAPE_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_escape, ##__VA_ARGS__)
1438
1439ssize_t fr_sbuff_in_escape_buffer(fr_sbuff_t *sbuff, char const *in, fr_sbuff_escape_rules_t const *e_rules);
1440#define FR_SBUFF_IN_ESCAPE_BUFFER_RETURN(...) FR_SBUFF_RETURN(fr_sbuff_in_escape_buffer, ##__VA_ARGS__)
1441
1442ssize_t fr_sbuff_in_array(fr_sbuff_t *sbuff, char const * const *array, char const *sep);
1443#define FR_SBUFF_IN_ARRAY(...) FR_SBUFF_RETURN(fr_sbuff_in_array, ##__VA_ARGS__)
1444
1445/** Lookup a string in a table using an integer value, and copy it to the sbuff
1446 *
1447 * @param[out] _slen Where to write the return value.
1448 * @param[in] _sbuff to search in.
1449 * @param[in] _table to search for number in.
1450 * @param[in] _number to search for.
1451 * @param[in] _def Default string value.
1452 */
1453#define fr_sbuff_in_table_str(_slen, _sbuff, _table, _number, _def) \
1454 _slen = fr_sbuff_in_strcpy(_sbuff, fr_table_str_by_value(_table, _number, _def))
1455#define FR_SBUFF_IN_TABLE_STR_RETURN(_sbuff, _table, _number, _def) \
1456do { \
1457 ssize_t _slen; \
1458 fr_sbuff_in_table_str(_slen, _sbuff, _table, _number, _def); \
1459 if (_slen < 0) return _slen; \
1460} while (0)
1461/** @} */
1462
1463/** @name Copy data out of an sbuff
1464 *
1465 * These functions are typically used for parsing.
1466 *
1467 * @{
1468 */
1469
1470/** Toggle any chars to 'true' in out, that were present in, out or in
1471 *
1472 */
1473static inline void fr_sbuff_allowed_merge(bool out[static SBUFF_CHAR_CLASS], bool const in[static SBUFF_CHAR_CLASS])
1474{
1475 for (size_t i = 0; i <= UINT8_MAX; i++) out[i] = out[i] || in[i];
1476}
1477
1478fr_sbuff_term_t *fr_sbuff_terminals_amerge(TALLOC_CTX *ctx,
1479 fr_sbuff_term_t const *a, fr_sbuff_term_t const *b);
1480
1481size_t fr_sbuff_out_bstrncpy(fr_sbuff_t *out, fr_sbuff_t *in, size_t len);
1482
1483ssize_t fr_sbuff_out_bstrncpy_exact(fr_sbuff_t *out, fr_sbuff_t *in, size_t len);
1484
1485size_t fr_sbuff_out_bstrncpy_allowed(fr_sbuff_t *out, fr_sbuff_t *in, size_t len,
1486 bool const allowed[static SBUFF_CHAR_CLASS]);
1487
1488size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len,
1489 fr_sbuff_term_t const *tt,
1490 fr_sbuff_unescape_rules_t const *u_rules);
1491
1492size_t fr_sbuff_out_unescape_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len,
1493 fr_sbuff_term_t const *tt,
1494 fr_sbuff_unescape_rules_t const *u_rules);
1495
1496/** Find the longest prefix in an sbuff
1497 *
1498 * @param[out] _match_len The length of the matched string.
1499 * May be NULL.
1500 * @param[out] _out The value resolved in the table.
1501 * @param[in] _table to find longest match in.
1502 * @param[in] _sbuff containing the needle.
1503 * @param[in] _def Default value if no match is found.
1504 */
1505#define fr_sbuff_out_by_longest_prefix(_match_len, _out, _table, _sbuff, _def) \
1506do { \
1507 size_t _match_len_tmp; \
1508 fr_sbuff_extend_lowat(NULL, _sbuff, fr_table_max_needle_len(_table)); \
1509 *(_out) = fr_table_value_by_longest_prefix(&_match_len_tmp, _table, \
1510 fr_sbuff_current(_sbuff), fr_sbuff_remaining(_sbuff), \
1511 _def); \
1512 (void) fr_sbuff_advance(_sbuff, _match_len_tmp); /* can't fail */ \
1513 *(_match_len) = _match_len_tmp; \
1514} while (0)
1515
1516/** Build a talloc wrapper function for a fr_sbuff_out_* function
1517 *
1518 * @param[in] _func to call.
1519 * @param[in] _in input sbuff arg.
1520 * @param[in] _len expected output len.
1521 * @param[in] ... additional arguments to pass to _func.
1522 */
1523#define SBUFF_OUT_TALLOC_ERR_FUNC_DEF(_func, _in, _len, ...) \
1524{ \
1525 fr_sbuff_t sbuff; \
1526 fr_sbuff_uctx_talloc_t tctx; \
1527 fr_sbuff_parse_error_t err; \
1528 fr_slen_t slen = -1; \
1529 if (unlikely(fr_sbuff_init_talloc(ctx, &sbuff, &tctx, \
1530 ((_len) != SIZE_MAX) ? (_len) : 1024, \
1531 ((_len) != SIZE_MAX) ? (_len) : SIZE_MAX) == NULL)) { \
1532 error: \
1533 TALLOC_FREE(sbuff.buff); \
1534 *out = NULL; \
1535 return slen; \
1536 } \
1537 slen = _func(&err, &sbuff, _in, _len, ##__VA_ARGS__); \
1538 if (slen < 0) goto error; \
1539 if (unlikely(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) < 0)) { \
1540 slen = -1; \
1541 goto error; \
1542 } \
1543 *out = sbuff.buff; \
1544 return slen; \
1545}
1546
1547/** Build a talloc wrapper function for a fr_sbuff_out_* function
1548 *
1549 * @param[in] _func to call.
1550 * @param[in] _in input sbuff arg.
1551 * @param[in] _len expected output len.
1552 * @param[in] ... additional arguments to pass to _func.
1553 */
1554#define SBUFF_OUT_TALLOC_FUNC_DEF(_func, _in, _len, ...) \
1555{ \
1556 fr_sbuff_t sbuff; \
1557 fr_sbuff_uctx_talloc_t tctx; \
1558 fr_slen_t slen = -1; \
1559 if (unlikely(fr_sbuff_init_talloc(ctx, &sbuff, &tctx, \
1560 ((_len) != SIZE_MAX) ? (_len) : 1024, \
1561 ((_len) != SIZE_MAX) ? (_len) : SIZE_MAX) == NULL)) { \
1562 error: \
1563 TALLOC_FREE(sbuff.buff); \
1564 *out = NULL; \
1565 return slen; \
1566 } \
1567 slen = _func(&sbuff, _in, _len, ##__VA_ARGS__); \
1568 if (slen < 0) goto error; \
1569 if (unlikely(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) < 0)) { \
1570 slen = -1; \
1571 goto error; \
1572 } \
1573 *out = sbuff.buff; \
1574 return slen; \
1575}
1576
1577/** Build a talloc wrapper function for a fr_sbuff_out_* function
1578 *
1579 * @param[in] _func to call.
1580 * @param[in] ... additional arguments to pass to _func.
1581 */
1582#define SBUFF_OUT_TALLOC_FUNC_NO_LEN_DEF(_func, ...) \
1583{ \
1584 fr_sbuff_t sbuff; \
1585 fr_sbuff_uctx_talloc_t tctx; \
1586 fr_slen_t slen = -1; \
1587 if (unlikely(fr_sbuff_init_talloc(ctx, &sbuff, &tctx, 0, SIZE_MAX) == NULL)) { \
1588 error: \
1589 TALLOC_FREE(sbuff.buff); \
1590 *out = NULL; \
1591 return slen; \
1592 } \
1593 slen = _func(&sbuff, ##__VA_ARGS__); \
1594 if (slen < 0) goto error; \
1595 if (unlikely(fr_sbuff_trim_talloc(&sbuff, SIZE_MAX) < 0)) { \
1596 slen = -1; \
1597 goto error; \
1598 } \
1599 *out = sbuff.buff; \
1600 return slen; \
1601}
1602
1603static inline fr_slen_t fr_sbuff_out_abstrncpy(TALLOC_CTX *ctx, char **out, fr_sbuff_t *in, size_t len)
1604SBUFF_OUT_TALLOC_FUNC_DEF(fr_sbuff_out_bstrncpy, in, len)
1605
1606static inline fr_slen_t fr_sbuff_out_abstrncpy_exact(TALLOC_CTX *ctx, char **out, fr_sbuff_t *in, size_t len)
1607SBUFF_OUT_TALLOC_FUNC_DEF(fr_sbuff_out_bstrncpy_exact, in, len)
1608
1609static inline fr_slen_t fr_sbuff_out_abstrncpy_allowed(TALLOC_CTX *ctx, char **out, fr_sbuff_t *in, size_t len,
1610 bool const allowed[static SBUFF_CHAR_CLASS])
1611SBUFF_OUT_TALLOC_FUNC_DEF(fr_sbuff_out_bstrncpy_allowed, in, len, allowed)
1612
1613static inline fr_slen_t fr_sbuff_out_abstrncpy_until(TALLOC_CTX *ctx, char **out, fr_sbuff_t *in, size_t len,
1614 fr_sbuff_term_t const *tt,
1615 fr_sbuff_unescape_rules_t const *u_rules)
1616SBUFF_OUT_TALLOC_FUNC_DEF(fr_sbuff_out_bstrncpy_until, in, len, tt, u_rules)
1617
1618static inline fr_slen_t fr_sbuff_out_aunescape_until(TALLOC_CTX *ctx, char **out, fr_sbuff_t *in, size_t len,
1619 fr_sbuff_term_t const *tt,
1620 fr_sbuff_unescape_rules_t const *u_rules)
1621SBUFF_OUT_TALLOC_FUNC_DEF(fr_sbuff_out_unescape_until, in, len, tt, u_rules)
1622/** @} */
1623
1624/** @name Look for a token in a particular format, parse it, and write it to the output pointer
1625 *
1626 * These functions should not be called directly. #fr_sbuff_out should be used instead
1627 * so that if the output variable type changes, the parse rules are automatically changed.
1628 * @{
1629 */
1630fr_slen_t fr_sbuff_out_bool(bool *out, fr_sbuff_t *in);
1631
1632fr_slen_t fr_sbuff_out_int8(fr_sbuff_parse_error_t *err, int8_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1633fr_slen_t fr_sbuff_out_int16(fr_sbuff_parse_error_t *err, int16_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1634fr_slen_t fr_sbuff_out_int32(fr_sbuff_parse_error_t *err, int32_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1635fr_slen_t fr_sbuff_out_int64(fr_sbuff_parse_error_t *err, int64_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1636fr_slen_t fr_sbuff_out_ssize(fr_sbuff_parse_error_t *err, ssize_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1637fr_slen_t fr_sbuff_out_uint8(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1638fr_slen_t fr_sbuff_out_uint16(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1639fr_slen_t fr_sbuff_out_uint32(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1640fr_slen_t fr_sbuff_out_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1641fr_slen_t fr_sbuff_out_size(fr_sbuff_parse_error_t *err, size_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1642
1643fr_slen_t fr_sbuff_out_uint8_dec(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1644fr_slen_t fr_sbuff_out_uint16_dec(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1645fr_slen_t fr_sbuff_out_uint32_dec(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1646fr_slen_t fr_sbuff_out_uint64_dec(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1647fr_slen_t fr_sbuff_out_size_dec(fr_sbuff_parse_error_t *err, size_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1648
1649fr_slen_t fr_sbuff_out_uint8_oct(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1650fr_slen_t fr_sbuff_out_uint16_oct(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1651fr_slen_t fr_sbuff_out_uint32_oct(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1652fr_slen_t fr_sbuff_out_uint64_oct(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1653fr_slen_t fr_sbuff_out_size_oct(fr_sbuff_parse_error_t *err, size_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1654
1655fr_slen_t fr_sbuff_out_uint8_hex(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1656fr_slen_t fr_sbuff_out_uint16_hex(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1657fr_slen_t fr_sbuff_out_uint32_hex(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1658fr_slen_t fr_sbuff_out_uint64_hex(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1659fr_slen_t fr_sbuff_out_size_hex(fr_sbuff_parse_error_t *err, size_t *out, fr_sbuff_t *sbuff, bool no_trailing);
1660
1661fr_slen_t fr_sbuff_out_float32(fr_sbuff_parse_error_t *err, float *out, fr_sbuff_t *sbuff, bool no_trailing);
1662fr_slen_t fr_sbuff_out_float64(fr_sbuff_parse_error_t *err, double *out, fr_sbuff_t *sbuff, bool no_trailing);
1663
1664#ifndef SIZE_SAME_AS_UINT64
1665# define _fr_sbuff_out_size(_err, _out, _in) size_t * : fr_sbuff_out_size(_err, (size_t *)_out, _in, true),
1666#else
1667# define _fr_sbuff_out_size(_err, _out, _in)
1668#endif
1669
1670#ifndef SSIZE_SAME_AS_INT64
1671# define _fr_sbuff_out_ssize(_err, _out, _in) ssize_t * : fr_sbuff_out_ssize(_err, (ssize_t *)_out, _in, true),
1672#else
1673# define _fr_sbuff_out_ssize(_err, _out, _in)
1674#endif
1675
1676/** Parse a value based on the output type
1677 *
1678 * @param[out] _err If not NULL a value describing the parse error
1679 * will be written to err.
1680 * @param[out] _out Pointer to an integer type.
1681 * @param[in] _in Sbuff to parse integer from.
1682 * @return The number of bytes parsed (even on error).
1683 */
1684#define fr_sbuff_out(_err, _out, _in) \
1685 _Generic((_out), \
1686 bool * : fr_sbuff_out_bool((bool *)_out, _in), \
1687 int8_t * : fr_sbuff_out_int8(_err, (int8_t *)_out, _in, true), \
1688 int16_t * : fr_sbuff_out_int16(_err, (int16_t *)_out, _in, true), \
1689 int32_t * : fr_sbuff_out_int32(_err, (int32_t *)_out, _in, true), \
1690 int64_t * : fr_sbuff_out_int64(_err, (int64_t *)_out, _in, true), \
1691 _fr_sbuff_out_ssize(_err, _out, _in) \
1692 uint8_t * : fr_sbuff_out_uint8(_err, (uint8_t *)_out, _in, true), \
1693 uint16_t * : fr_sbuff_out_uint16(_err, (uint16_t *)_out, _in, true), \
1694 uint32_t * : fr_sbuff_out_uint32(_err, (uint32_t *)_out, _in, true), \
1695 uint64_t * : fr_sbuff_out_uint64(_err, (uint64_t *)_out, _in, true), \
1696 _fr_sbuff_out_size(_err, _out, _in) \
1697 float * : fr_sbuff_out_float32(_err, (float *)_out, _in, true), \
1698 double * : fr_sbuff_out_float64(_err, (double *)_out, _in, true) \
1699 )
1700/** @} */
1701
1702
1703/** @name Conditional advancement
1704 *
1705 * These functions are typically used for parsing when trying to locate
1706 * a sequence of characters in the sbuff.
1707 *
1708 * @{
1709 */
1710size_t fr_sbuff_adv_past_str(fr_sbuff_t *sbuff, char const *needle, size_t need_len);
1711
1712#define fr_sbuff_adv_past_str_literal(_sbuff, _needle) fr_sbuff_adv_past_str(_sbuff, _needle, sizeof(_needle) - 1)
1713
1714size_t fr_sbuff_adv_past_strcase(fr_sbuff_t *sbuff, char const *needle, size_t need_len);
1715
1716#define fr_sbuff_adv_past_strcase_literal(_sbuff, _needle) fr_sbuff_adv_past_strcase(_sbuff, _needle, sizeof(_needle) - 1)
1717
1718size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len,
1719 bool const allowed[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *tt);
1720
1721#define fr_sbuff_adv_past_zeros(_sbuff, _len, _tt) fr_sbuff_adv_past_allowed(_sbuff, _len, sbuff_char_class_zero, _tt)
1722
1723#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt) fr_sbuff_adv_past_allowed(_sbuff, _len, sbuff_char_whitespace, _tt)
1724
1725#define fr_sbuff_adv_past_blank(_sbuff, _len, _tt) fr_sbuff_adv_past_allowed(_sbuff, _len, sbuff_char_blank, _tt)
1726
1727size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr);
1728
1729char *fr_sbuff_adv_to_chr_utf8(fr_sbuff_t *in, size_t len, char const *chr);
1730
1731char *fr_sbuff_adv_to_chr(fr_sbuff_t *in, size_t len, char c);
1732
1733char *fr_sbuff_adv_to_str(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len);
1734
1735#define fr_sbuff_adv_to_str_literal(_sbuff, _len, _needle) fr_sbuff_adv_to_str(_sbuff, _len, _needle, sizeof(_needle) - 1)
1736
1737char *fr_sbuff_adv_to_strcase(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len);
1738
1739#define fr_sbuff_adv_to_strcase_literal(_sbuff, _len, _needle) fr_sbuff_adv_to_strcase(_sbuff, _len, _needle, sizeof(_needle) - 1)
1740
1741bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c);
1742
1743bool fr_sbuff_next_unless_char(fr_sbuff_t *sbuff, char c);
1744
1745/** Advance the sbuff by one char
1746 *
1747 */
1748static inline char fr_sbuff_next(fr_sbuff_t *sbuff)
1749{
1750 if (!fr_sbuff_extend(sbuff)) return '\0';
1751 return fr_sbuff_advance(sbuff, 1);
1752}
1753/** @} */
1754
1755/** @name Remove chars from a buffer and re-terminate
1756 *
1757 * @{
1758 */
1759size_t fr_sbuff_trim(fr_sbuff_t *sbuff, bool const to_trim[static SBUFF_CHAR_CLASS]);
1760/** @} */
1761
1762/** @name Conditions
1763 *
1764 * These functions are typically used in recursive decent parsing for
1765 * look ahead.
1766 * @{
1767 */
1768bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt);
1769
1770static inline bool fr_sbuff_is_in_charset(fr_sbuff_t *sbuff, bool const chars[static SBUFF_CHAR_CLASS])
1771{
1772 if (!fr_sbuff_extend(sbuff)) return false;
1773 return chars[(uint8_t)*sbuff->p];
1774}
1775
1776static inline bool fr_sbuff_is_str(fr_sbuff_t *sbuff, char const *str, size_t len)
1777{
1778 if (len == SIZE_MAX) len = strlen(str);
1779 if (fr_sbuff_extend_lowat(NULL, sbuff, len) < len) return false;
1780 return memcmp(sbuff->p, str, len) == 0;
1781}
1782#define fr_sbuff_is_str_literal(_sbuff, _str) fr_sbuff_is_str(_sbuff, _str, sizeof(_str) - 1)
1783
1784#define fr_sbuff_eof(_x) (!fr_sbuff_extend(_x))
1785
1786static inline bool _fr_sbuff_is_char(fr_sbuff_t *sbuff, char *p, char c)
1787{
1788 if (!fr_sbuff_extend(sbuff)) return false;
1789 return *p == c;
1790}
1791static inline bool _fr_marker_is_char(fr_sbuff_marker_t *marker, char *p, char c)
1792{
1793 if (!fr_sbuff_extend(marker)) return false;
1794 return *p == c;
1795}
1796#define fr_sbuff_is_char(_sbuff_or_marker, _c) \
1797 _Generic((_sbuff_or_marker), \
1798 fr_sbuff_t * : _fr_sbuff_is_char((fr_sbuff_t *)(_sbuff_or_marker), fr_sbuff_current(_sbuff_or_marker), _c), \
1799 fr_sbuff_marker_t * : _fr_marker_is_char((fr_sbuff_marker_t *)(_sbuff_or_marker), fr_sbuff_current(_sbuff_or_marker), _c) \
1800 )
1801
1802#define SBUFF_IS_FUNC(_name, _test) \
1803 static inline bool _fr_sbuff_is_ ## _name(fr_sbuff_t *sbuff, char *p) \
1804 { \
1805 if (!fr_sbuff_extend(sbuff)) return false; \
1806 return _test; \
1807 }\
1808 static inline bool _fr_marker_is_ ## _name(fr_sbuff_marker_t *marker, char *p) \
1809 { \
1810 if (!fr_sbuff_extend(marker)) return false; \
1811 return _test; \
1812 }
1813
1814#define SBUFF_IS_GENERIC(_sbuff_or_marker, _name) \
1815 _Generic((_sbuff_or_marker), \
1816 fr_sbuff_t * : _fr_sbuff_is_ ## _name((fr_sbuff_t *)(_sbuff_or_marker), fr_sbuff_current(_sbuff_or_marker)), \
1817 fr_sbuff_marker_t * : _fr_marker_is_ ## _name((fr_sbuff_marker_t *)(_sbuff_or_marker), fr_sbuff_current(_sbuff_or_marker)) \
1818 )
1819
1820SBUFF_IS_FUNC(digit, isdigit((uint8_t) *p))
1821#define fr_sbuff_is_digit(_sbuff_or_marker) \
1822 SBUFF_IS_GENERIC(_sbuff_or_marker, digit)
1823
1824SBUFF_IS_FUNC(upper, isupper((uint8_t) *p))
1825#define fr_sbuff_is_upper(_sbuff_or_marker) \
1826 SBUFF_IS_GENERIC(_sbuff_or_marker, upper)
1827
1828SBUFF_IS_FUNC(lower, islower((uint8_t) *p))
1829#define fr_sbuff_is_lower(_sbuff_or_marker) \
1830 SBUFF_IS_GENERIC(_sbuff_or_marker, lower)
1831
1832SBUFF_IS_FUNC(alpha, isalpha((uint8_t) *p))
1833#define fr_sbuff_is_alpha(_sbuff_or_marker) \
1834 SBUFF_IS_GENERIC(_sbuff_or_marker, alpha)
1835
1836SBUFF_IS_FUNC(alnum, isalnum((uint8_t) *p))
1837#define fr_sbuff_is_alnum(_sbuff_or_marker) \
1838 SBUFF_IS_GENERIC(_sbuff_or_marker, alnum)
1839
1840SBUFF_IS_FUNC(space, isspace((uint8_t) *p))
1841#define fr_sbuff_is_space(_sbuff_or_marker) \
1842 SBUFF_IS_GENERIC(_sbuff_or_marker, space)
1843
1844SBUFF_IS_FUNC(hex, isxdigit((uint8_t) *p))
1845#define fr_sbuff_is_hex(_sbuff_or_marker) \
1846 SBUFF_IS_GENERIC(_sbuff_or_marker, hex)
1847
1848/** @} */
1849
1850void fr_sbuff_unescape_debug(FILE *fp, fr_sbuff_unescape_rules_t const *escapes);
1851
1852void fr_sbuff_terminal_debug(FILE *fp, fr_sbuff_term_t const *tt);
1853
1854void fr_sbuff_parse_rules_debug(FILE *fp, fr_sbuff_parse_rules_t const *p_rules);
1855
1856/*
1857 * ...printf("foo %.*s", fr_sbuff_as_percent_s(&sbuff));
1858 */
1859#define fr_sbuff_as_percent_s(_sbuff) (int) fr_sbuff_remaining(_sbuff), fr_sbuff_current(_sbuff)
1860
1861fr_slen_t fr_sbuff_array_concat(fr_sbuff_t *out, char const * const *array, char const *sep) CC_HINT(nonnull(1,2));
1862
1863
1864#ifdef __cplusplus
1865}
1866#endif
#define RCSIDH(h, id)
Definition build.h:507
#define DIAG_OFF(_x)
Definition build.h:480
static fr_slen_t err
Definition dict.h:882
static const bool escapes[SBUFF_CHAR_CLASS]
Definition util.c:39
long int ssize_t
fr_sbuff_parse_error_t
@ FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW
Integer type would overflow.
@ FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW
Integer type would underflow.
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
@ FR_SBUFF_PARSE_ERROR_FORMAT
Format of data was invalid.
@ FR_SBUFF_PARSE_OK
No error.
@ FR_SBUFF_PARSE_ERROR_OUT_OF_SPACE
No space available in output buffer.
@ FR_SBUFF_PARSE_ERROR_TRAILING
Trailing characters found.
static char const * name
bool const sbuff_char_class_hex[SBUFF_CHAR_CLASS]
Definition sbuff.c:98
bool const sbuff_char_word[SBUFF_CHAR_CLASS]
Definition sbuff.c:100
bool const sbuff_char_class_float[SBUFF_CHAR_CLASS]
Definition sbuff.c:74
bool const sbuff_char_class_uint[SBUFF_CHAR_CLASS]
Definition sbuff.c:64
size_t sbuff_parse_error_table_len
Definition sbuff.c:53
bool const sbuff_char_class_hostname[SBUFF_CHAR_CLASS]
Definition sbuff.c:86
bool const sbuff_char_blank[SBUFF_CHAR_CLASS]
Definition sbuff.c:112
bool const sbuff_char_class_int[SBUFF_CHAR_CLASS]
Definition sbuff.c:69
bool const sbuff_char_whitespace[SBUFF_CHAR_CLASS]
Definition sbuff.c:104
bool const sbuff_char_line_endings[SBUFF_CHAR_CLASS]
Definition sbuff.c:108
bool const sbuff_char_alpha_num[SBUFF_CHAR_CLASS]
Definition sbuff.c:99
bool const sbuff_char_class_zero[SBUFF_CHAR_CLASS]
Definition sbuff.c:79
fr_table_num_ordered_t const sbuff_parse_error_table[]
Definition sbuff.c:43
TALLOC_CTX * ctx
Context to alloc new buffers in.
Definition sbuff.h:138
bool(* fr_sbuff_eof_t)(fr_sbuff_t *sbuff)
For a given extension function, returns whether it is at EOF.
Definition sbuff.h:79
#define SBUFF_CHAR_CLASS
Definition sbuff.h:203
size_t shifted
How much we've read from this file.
Definition sbuff.h:152
size_t shifted
How many bytes this sbuff has been shifted since its creation.
Definition sbuff.h:116
fr_sbuff_extend_t extend
Function to re-populate or extend the buffer.
Definition sbuff.h:119
unsigned int is_const
Can't be modified.
Definition sbuff.h:114
char const * str
Terminal string.
Definition sbuff.h:160
void * uctx
Extend uctx data.
Definition sbuff.h:124
size_t init
How much to allocate initially.
Definition sbuff.h:139
char chr
Character at the start of an escape sequence.
Definition sbuff.h:211
char const * name
Name for rule set to aid we debugging.
Definition sbuff.h:209
bool do_oct
Process oct sequences i.e.
Definition sbuff.h:223
fr_sbuff_marker_t * m
Pointers to update if the underlying buffer changes.
Definition sbuff.h:128
size_t len
Length of the list.
Definition sbuff.h:170
char const * err
Where the last error occurred.
Definition sbuff.h:112
bool do_hex
Process hex sequences i.e.
Definition sbuff.h:222
size_t max
Maximum size of the buffer.
Definition sbuff.h:140
size_t len
Length of string.
Definition sbuff.h:161
char * buff_end
The true end of the buffer.
Definition sbuff.h:150
fr_sbuff_t * parent
sbuff this sbuff was copied from.
Definition sbuff.h:126
fr_sbuff_marker_t * next
Next m in the list.
Definition sbuff.h:87
bool eof
are we at EOF?
Definition sbuff.h:153
fr_sbuff_term_elem_t * elem
A sorted list of terminal strings.
Definition sbuff.h:171
ssize_t fr_slen_t
Represents number of bytes parsed or location of parse error.
Definition sbuff.h:48
fr_sbuff_t * parent
Owner of the marker.
Definition sbuff.h:88
fr_sbuff_eof_t eof
Function to determine if the buffer is at EOF.
Definition sbuff.h:122
size_t(* fr_sbuff_extend_t)(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t req_extension)
Extension callback.
Definition sbuff.h:74
unsigned int adv_parent
If true, advance the parent.
Definition sbuff.h:115
FILE * file
FILE * we're reading from.
Definition sbuff.h:149
size_t max
Maximum number of bytes to read.
Definition sbuff.h:151
fr_sbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
Definition sbuff.h:62
@ FR_SBUFF_FLAG_EXTEND_ERROR
The last call to an extend function resulted in an error.
Definition sbuff.h:64
@ FR_SBUFF_FLAG_EXTENDED
The last call to extend function actually extended the buffer.
Definition sbuff.h:63
Terminal element with pre-calculated lengths.
Definition sbuff.h:159
Set of terminal elements.
File sbuff extension structure.
Definition sbuff.h:148
Talloc sbuff extension structure.
Definition sbuff.h:137
Set of parsing rules for *unescape_until functions.
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
#define fr_strerror_const(_msg)
Definition strerror.h:223