The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
pair_print.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/*
18 * Groups are printed from the referenced attribute.
19 *
20 * @todo - parent should _never_ be vp->da.
21 */
22#define fr_pair_reset_parent(parent) do { \
23 if (!parent) break; \
24 fr_assert(parent != vp->da); \
25 fr_assert(fr_type_is_structural(parent->type)); \
26 if (parent->type == FR_TYPE_GROUP) { \
27 parent = fr_dict_attr_ref(parent); \
28 if (parent->flags.is_root) { \
29 parent = NULL; \
30 break; \
31 } \
32 } \
33 if (parent->dict != vp->da->dict) parent = NULL; \
34 } while (0)
35
36/** Pair serialisation API
37 *
38 * @file src/lib/util/pair_print.c
39 *
40 * @copyright 2020 The FreeRADIUS server project
41 */
42#include <freeradius-devel/util/pair.h>
43#include <freeradius-devel/util/talloc.h>
44#include <freeradius-devel/util/proto.h>
45#include <freeradius-devel/util/pair_legacy.h>
46
47/** Print the value of an attribute to a string
48 *
49 * @param[in] out Where to write the string.
50 * @param[in] vp to print.
51 * @param[in] quote Char to add before and after printed value,
52 * if 0 no char will be added, if < 0 raw string
53 * will be added.
54 * @return
55 * - >= 0 length of data written to out.
56 * - <0 the number of bytes we would have needed to write
57 * the complete string to out.
58 */
60{
61 fr_sbuff_t our_out;
62 ssize_t slen;
63
65
66 our_out = FR_SBUFF(out);
67
68 switch (vp->vp_type) {
69 /*
70 * For structural types descend down
71 */
73 if (fr_pair_list_empty(&vp->vp_group)) {
74 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' ', '}');
75
76 } else {
77 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' ');
78
79 FR_SBUFF_RETURN(fr_pair_list_print, &our_out, vp->da, &vp->vp_group);
80
81 FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ', '}');
82 }
83
84 FR_SBUFF_SET_RETURN(out, &our_out);
85
86 /*
87 * For simple types just print the box
88 */
89 default:
90 /*
91 * If it's raw / unknown and not octets, print the cast before the type.
92 *
93 * Otherwise on parsing, we don't know how to interpret the value. :(
94 */
95 if ((vp->da->flags.is_raw || vp->da->flags.is_unknown) &&
96 (vp->vp_type != FR_TYPE_OCTETS)) {
97 FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "(%s) ", fr_type_to_str(vp->vp_type));
98 }
99
100 slen = fr_value_box_print_quoted(&our_out, &vp->data, quote);
101 if (slen <= 0) return slen;
102 }
103
104 FR_SBUFF_SET_RETURN(out, &our_out);
105}
106
107/** Print either a quoted value, an enum, or a normal value.
108 *
109 */
111{
112 fr_sbuff_t our_out = FR_SBUFF(out);
113 char const *name;
114
115 if ((name = fr_value_box_enum_name(&vp->data)) != NULL) {
116 FR_SBUFF_IN_CHAR_RETURN(&our_out, ':', ':');
118 } else {
119
121 }
122
123 FR_SBUFF_SET_RETURN(out, &our_out);
124}
125
126/** Print an attribute name.
127 *
128 * @param[in] out Where to write the string.
129 * @param[in] parent If not NULL, only print OID components from
130 * this parent to the VP.
131 * @param[in,out] vp_p to print.
132 * @return
133 * - Length of data written to out.
134 * - value >= outlen on truncation.
135 */
137{
138 char const *token;
139 fr_pair_t const *vp = *vp_p;
140 fr_sbuff_t our_out = FR_SBUFF(out);
141
142 /*
143 * Omit the union if we can. But if the child is raw, then always print it. That way it's
144 * clearer what's going on.
145 */
146 if (vp->vp_type == FR_TYPE_UNION) {
147 fr_pair_t *child = fr_pair_list_head(&vp->vp_group);
148
149 if (!child->da->flags.is_unknown &&
150 (fr_pair_list_num_elements(&vp->vp_group) == 1)) {
151 parent = vp->da;
152 vp = fr_pair_list_head(&vp->vp_group);
153 }
154 }
155
157
158 if (vp->vp_raw) FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "raw.");
159 FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent, vp->da, false);
160
161 /*
162 * Mash the nesting levels if we're asked to do that, and if each structural child has only one
163 * member.
164 */
165 if (vp->da->flags.allow_flat) {
166 bool raw = vp->vp_raw;
167 fr_dict_attr_t const *root = parent;
169
170 fr_sbuff_marker(&m, &our_out);
171
172 while (fr_type_is_structural(vp->vp_type) &&
173 (fr_pair_list_num_elements(&vp->vp_group) == 1)) {
174 parent = vp->da;
175 vp = fr_pair_list_head(&vp->vp_group);
176
178
179 FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
180 FR_DICT_ATTR_OID_PRINT_RETURN(&our_out, parent, vp->da, false);
181 }
182
183 /*
184 * If the root attribute is an internal group, then look for aliases in the protocol
185 * root.
186 *
187 * Otherwise the root attribute is a protocol group. The protocol dictionary or library
188 * can add aliases.
189 */
190 if (!root || root->flags.internal) root = fr_dict_root(vp->da->dict);
191
192 if (!raw && (vp->da->depth > (root->depth + 1)) && (fr_dict_attr_by_name(NULL, root, vp->da->name) == vp->da)) {
193 fr_sbuff_set(&our_out, &m);
194 FR_SBUFF_IN_CHAR_RETURN(&our_out, '.');
195 FR_SBUFF_IN_STRCPY_RETURN(&our_out, vp->da->name);
196 }
197 }
198
199 /*
200 * Print the operator for the _last_ attribute, which is generally what we want.
201 */
202 if ((vp->op > T_INVALID) && (vp->op < T_TOKEN_LAST)) {
203 token = fr_tokens[vp->op];
204 } else {
205 token = "<INVALID-TOKEN>";
206 }
207
208 FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ');
209 FR_SBUFF_IN_STRCPY_RETURN(&our_out, token);
210 FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ');
211
212 *vp_p = vp;
213 FR_SBUFF_SET_RETURN(out, &our_out);
214}
215
216/** Print one attribute and value to a string
217 *
218 * Print a fr_pair_t in the format:
219@verbatim
220 <attribute_name> <op> <value>
221@endverbatim
222 * to a string.
223 *
224 * @param[in] out Where to write the string.
225 * @param[in] parent If not NULL, only print OID components from
226 * this parent to the VP.
227 * @param[in] vp to print.
228 * @return
229 * - Length of data written to out.
230 * - value >= outlen on truncation.
231 */
233{
234 fr_sbuff_t our_out = FR_SBUFF(out);
235
237
239
241
242 FR_SBUFF_SET_RETURN(out, &our_out);
243}
244
245/** Print one attribute and value to a string with escape rules
246 *
247 * Similar to fr_pair_print(), but secrets are omitted. This function duplicates parts of the functionality
248 * of fr_pair_print(). fr_pair_print_value_quoted(), and fr_value_box_print_quoted(), but for the special
249 * case of secure strings.
250 *
251 * Note that only secrets of type "string" and "octets" are omitted. Other "secret" data types are still
252 * printed as-is.
253 *
254 * "octets" are still printed as "<<< secret >>>". Which won't parse correctly, but that's fine. Because
255 * omitted data is not meant to be parsed into real data.
256 *
257 * @param[in] out Where to write the string.
258 * @param[in] parent If not NULL, only print OID components from
259 * this parent to the VP.
260 * @param[in] vp to print.
261
262 * @return
263 * - < 0 on error
264 * - Length of data written to out.
265 * - value >= outlen on truncation.
266 */
268{
269 fr_sbuff_t our_out = FR_SBUFF(out);
270
272
274
275 if (fr_type_is_leaf(vp->vp_type)) {
276 if (!vp->data.secret) {
278
279 } else {
280 switch (vp->vp_type) {
281 case FR_TYPE_STRING:
282 case FR_TYPE_OCTETS:
283 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "<<< secret >>>");
284 break;
285
286 default:
287 fr_assert(0); /* see dict_tokenize.c, which enforces parsing of "secret" in dictionaries */
288 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "<<< secret >>>");
289 break;
290 }
291 }
292 } else {
293 fr_pair_t *child;
294 fr_dcursor_t cursor;
295
297
298 FR_SBUFF_IN_CHAR_RETURN(&our_out, '{', ' ');
299 for (child = fr_pair_dcursor_init(&cursor, &vp->vp_group);
300 child != NULL;
301 child = fr_dcursor_next(&cursor)) {
302 FR_SBUFF_RETURN(fr_pair_print_secure, &our_out, vp->da, child);
303 if (fr_dcursor_next_peek(&cursor)) FR_SBUFF_IN_CHAR_RETURN(&our_out, ',', ' ');
304 }
305 FR_SBUFF_IN_CHAR_RETURN(&our_out, ' ', '}');
306 }
307
308 FR_SBUFF_SET_RETURN(out, &our_out);
309}
310
311/** Print a pair list
312 *
313 * @param[in] out Where to write the string.
314 * @param[in] parent parent da to start from
315 * @param[in] list pair list
316 * @return
317 * - Length of data written to out.
318 * - value >= outlen on truncation.
319 */
321{
322 fr_pair_t *vp;
323 fr_sbuff_t our_out = FR_SBUFF(out);
324
325 vp = fr_pair_list_head(list);
326 if (!vp) {
328 return fr_sbuff_used(out);
329 }
330
332
333 while (true) {
335 vp = fr_pair_list_next(list, vp);
336 if (!vp) break;
337
338 FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, ", ");
339 }
340
341 FR_SBUFF_SET_RETURN(out, &our_out);
342}
343
344static void fr_pair_list_log_sbuff(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line, fr_sbuff_t *sbuff)
345{
346 fr_dict_attr_t const *parent_da = NULL;
347
348 fr_pair_list_foreach(list, vp) {
350
351 fr_sbuff_set_to_start(sbuff);
352
353 if (vp->vp_raw) (void) fr_sbuff_in_strcpy(sbuff, "raw.");
354
355 if (parent && (parent->vp_type != FR_TYPE_GROUP)) parent_da = parent->da;
356 if (fr_dict_attr_oid_print(sbuff, parent_da, vp->da, false) <= 0) return;
357
358 /*
359 * Recursively print grouped attributes.
360 */
361 switch (vp->vp_type) {
363 fr_log(log, L_DBG, file, line, "%*s%*s {", lvl * 2, "",
364 (int) fr_sbuff_used(sbuff), fr_sbuff_start(sbuff));
365 _fr_pair_list_log(log, lvl + 1, vp, &vp->vp_group, file, line);
366 fr_log(log, L_DBG, file, line, "%*s}", lvl * 2, "");
367 break;
368
369 default:
370 (void) fr_sbuff_in_strcpy(sbuff, " = ");
371 if (fr_pair_print_value(sbuff, vp) < 0) break;
372
373 fr_log(log, L_DBG, file, line, "%*s%*s", lvl * 2, "",
374 (int) fr_sbuff_used(sbuff), fr_sbuff_start(sbuff));
375 }
376 }
377}
378
379
380/** Print a list of attributes and enumv
381 *
382 * @param[in] log to output to.
383 * @param[in] lvl depth in structural attribute.
384 * @param[in] parent parent attribute
385 * @param[in] list to print.
386 * @param[in] file where the message originated
387 * @param[in] line where the message originated
388 */
389void _fr_pair_list_log(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line)
390{
391 fr_sbuff_t sbuff;
392 char buffer[1024];
393
394 buffer[0] = '\0';
395
396 fr_sbuff_init_out(&sbuff, buffer, sizeof(buffer));
397
398 fr_pair_list_log_sbuff(log, lvl, parent, list, file, line, &sbuff);
399}
400
401static void fr_pair_list_debug_sbuff(FILE *fp, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, fr_sbuff_t *sbuff)
402{
403 fr_dict_attr_t const *parent_da = NULL;
404
405 fr_pair_list_foreach(list, vp) {
407
408 fr_sbuff_set_to_start(sbuff);
409
410 if (vp->vp_raw) (void) fr_sbuff_in_strcpy(sbuff, "raw.");
411
412 if (parent && (parent->vp_type != FR_TYPE_GROUP)) parent_da = parent->da;
413 if (fr_dict_attr_oid_print(sbuff, parent_da, vp->da, false) <= 0) return;
414
415 /*
416 * Recursively print grouped attributes.
417 */
418 switch (vp->vp_type) {
420 fprintf(fp, "%*s%*s {\n", lvl * 2, "", (int) fr_sbuff_used(sbuff), fr_sbuff_start(sbuff));
421 _fr_pair_list_debug(fp, lvl + 1, vp, &vp->vp_group);
422 fprintf(fp, "%*s}\n", lvl * 2, "");
423 break;
424
425 default:
426 (void) fr_sbuff_in_strcpy(sbuff, " = ");
427 if (fr_value_box_print_quoted(sbuff, &vp->data, T_DOUBLE_QUOTED_STRING)< 0) break;
428
429 fprintf(fp, "%*s%*s\n", lvl * 2, "", (int) fr_sbuff_used(sbuff), fr_sbuff_start(sbuff));
430 }
431 }
432}
433
434/** Print a list of attributes and enumv
435 *
436 * @param[in] fp to output to.
437 * @param[in] lvl depth in structural attribute.
438 * @param[in] parent parent attribute
439 * @param[in] list to print.
440 */
441void _fr_pair_list_debug(FILE *fp, int lvl, fr_pair_t *parent, fr_pair_list_t const *list)
442{
443 fr_sbuff_t sbuff;
444 char buffer[1024];
445
446 buffer[0] = '\0';
447
448 fr_sbuff_init_out(&sbuff, buffer, sizeof(buffer));
449
450 fr_pair_list_debug_sbuff(fp, lvl, parent, list, &sbuff);
451}
452
453/** Dumps a list to the default logging destination - Useful for calling from debuggers
454 *
455 */
456void fr_pair_list_debug(FILE *fp, fr_pair_list_t const *list)
457{
458 _fr_pair_list_debug(fp, 0, NULL, list);
459}
460
461
462/** Dumps a pair to the default logging destination - Useful for calling from debuggers
463 *
464 */
465void fr_pair_debug(FILE *fp, fr_pair_t const *pair)
466{
467 fr_sbuff_t sbuff;
468 char buffer[1024];
469
470 buffer[0] = '\0';
471
472 fr_sbuff_init_out(&sbuff, buffer, sizeof(buffer));
473
474 (void) fr_pair_print(&sbuff, NULL, pair);
475
476 fprintf(fp, "%pV\n", fr_box_strvalue_len(fr_sbuff_start(&sbuff), fr_sbuff_used(&sbuff)));
477}
478
479static const char spaces[] = " ";
480
481static void fprintf_pair_list(FILE *fp, fr_pair_list_t const *list, int depth)
482{
483 fr_pair_list_foreach(list, vp) {
484 fprintf(fp, "%.*s", depth, spaces);
485
486 if (fr_type_is_leaf(vp->vp_type)) {
487 fr_fprintf(fp, "%s %s %pV\n", vp->da->name, fr_tokens[vp->op], &vp->data);
488 continue;
489 }
490
492
493 fprintf(fp, "%s = {\n", vp->da->name);
494 fprintf_pair_list(fp, &vp->vp_group, depth + 1);
495 fprintf(fp, "%.*s}\n", depth, spaces);
496 }
497}
498
499void fr_fprintf_pair_list(FILE *fp, fr_pair_list_t const *list)
500{
501 fprintf_pair_list(fp, list, 0);
502}
503
504/*
505 * print.c doesn't include pair.h, and doing so causes too many knock-on effects.
506 */
507void fr_fprintf_pair(FILE *fp, char const *msg, fr_pair_t const *vp)
508{
509 if (msg) fputs(msg, fp);
510
511 if (fr_type_is_leaf(vp->vp_type)) {
512 fr_fprintf(fp, "%s %s %pV\n", vp->da->name, fr_tokens[vp->op], &vp->data);
513 } else {
515
516 fprintf(fp, "%s = {\n", vp->da->name);
517 fprintf_pair_list(fp, &vp->vp_group, 1);
518 fprintf(fp, "}\n");
519 }
520}
static int const char char buffer[256]
Definition acutest.h:578
int const char * file
Definition acutest.h:704
log_entry msg
Definition acutest.h:796
int const char int line
Definition acutest.h:704
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
static void * fr_dcursor_next_peek(fr_dcursor_t *cursor)
Return the next iterator item without advancing the cursor.
Definition dcursor.h:305
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3532
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2669
#define FR_DICT_ATTR_OID_PRINT_RETURN(...)
Definition dict.h:752
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:577
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
ssize_t fr_dict_attr_oid_print(fr_sbuff_t *out, fr_dict_attr_t const *ancestor, fr_dict_attr_t const *da, bool numeric)
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
void _fr_pair_list_debug(FILE *fp, int lvl, fr_pair_t *parent, fr_pair_list_t const *list)
Print a list of attributes and enumv.
Definition pair_print.c:441
static void fprintf_pair_list(FILE *fp, fr_pair_list_t const *list, int depth)
Definition pair_print.c:481
void fr_fprintf_pair_list(FILE *fp, fr_pair_list_t const *list)
Definition pair_print.c:499
void fr_pair_debug(FILE *fp, fr_pair_t const *pair)
Dumps a pair to the default logging destination - Useful for calling from debuggers.
Definition pair_print.c:465
static void fr_pair_list_debug_sbuff(FILE *fp, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, fr_sbuff_t *sbuff)
Definition pair_print.c:401
#define fr_pair_reset_parent(parent)
Definition pair_print.c:22
static void fr_pair_list_log_sbuff(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line, fr_sbuff_t *sbuff)
Definition pair_print.c:344
void fr_pair_list_debug(FILE *fp, fr_pair_list_t const *list)
Dumps a list to the default logging destination - Useful for calling from debuggers.
Definition pair_print.c:456
void _fr_pair_list_log(fr_log_t const *log, int lvl, fr_pair_t *parent, fr_pair_list_t const *list, char const *file, int line)
Print a list of attributes and enumv.
Definition pair_print.c:389
ssize_t fr_pair_print(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_t const *vp)
Print one attribute and value to a string.
Definition pair_print.c:232
void fr_fprintf_pair(FILE *fp, char const *msg, fr_pair_t const *vp)
Definition pair_print.c:507
ssize_t fr_pair_print_secure(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_t const *vp)
Print one attribute and value to a string with escape rules.
Definition pair_print.c:267
static ssize_t fr_pair_print_name(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_t const **vp_p)
Print an attribute name.
Definition pair_print.c:136
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition pair_print.c:59
static const char spaces[]
Definition pair_print.c:479
static ssize_t fr_pair_print_value(fr_sbuff_t *out, fr_pair_t const *vp)
Print either a quoted value, an enum, or a normal value.
Definition pair_print.c:110
ssize_t fr_pair_list_print(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_list_t const *list)
Print a pair list.
Definition pair_print.c:320
ssize_t fr_fprintf(FILE *fp, char const *fmt,...)
Special version of fprintf which implements custom format specifiers.
Definition print.c:907
#define fr_assert(_expr)
Definition rad_assert.h:38
static char const * name
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1459
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN_STRCPY_LITERAL_RETURN(_sbuff, _str)
#define fr_sbuff_init_out(_out, _start, _len_or_end)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_IN_STRCPY_RETURN(...)
fr_pair_t * vp
Definition log.h:96
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
char const * fr_tokens[T_TOKEN_LAST]
Definition token.c:79
enum fr_token fr_token_t
@ T_INVALID
Definition token.h:39
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
#define T_TOKEN_LAST
Definition token.h:129
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
#define PAIR_VERIFY(_x)
Definition pair.h:204
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition pair_inline.c:69
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:279
#define PAIR_VERIFY_WITH_LIST(_l, _x)
Definition pair.h:205
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:605
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:42
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
static fr_slen_t parent
Definition pair.h:857
#define fr_type_is_structural(_x)
Definition types.h:393
@ FR_TYPE_UNION
A union of limited children.
Definition types.h:82
#define FR_TYPE_STRUCTURAL
Definition types.h:317
#define fr_type_is_leaf(_x)
Definition types.h:394
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
ssize_t fr_value_box_print_quoted(fr_sbuff_t *out, fr_value_box_t const *data, fr_token_t quote)
Print one boxed value to a string with quotes (where needed)
Definition value.c:6255
#define fr_box_strvalue_len(_val, _len)
Definition value.h:308
static char const * fr_value_box_enum_name(fr_value_box_t const *box)
Decide if we need an enum prefix.
Definition value.h:1137
static size_t char ** out
Definition value.h:1023