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