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