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