smartmontools SVN Rev 5640
Utility to control and monitor storage systems with "S.M.A.R.T."
json.cpp
Go to the documentation of this file.
1/*
2 * json.cpp
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2017-22 Christian Franke
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "config.h"
12#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
13
14#include "json.h"
15
16const char * json_cvsid = "$Id: json.cpp 5469 2023-03-15 20:00:35Z dpgilbert $"
18
19#include "sg_unaligned.h"
20#include "utility.h" // regular_expression, uint128_*()
21
22#include <inttypes.h>
23#include <stdexcept>
24
25static void jassert_failed(int line, const char * expr)
26{
27 char msg[128];
28 // Avoid __FILE__ as it may break reproducible builds
29 snprintf(msg, sizeof(msg), "json.cpp(%d): Assertion failed: %s", line, expr);
30 throw std::logic_error(msg);
31}
32
33#define jassert(expr) (!(expr) ? jassert_failed(__LINE__, #expr) : (void)0)
34
35/* Convert to json "snake" format. It will contains only lower case ASCII
36 * alphanumeric characters with all other characters replaced with the
37 * underscore character. Further, all leading and trailing underscores are
38 * removed and repeated underscores with the name are reduced to a single
39 * underscore.
40 * For example "$Output power (mW)" becomes "output_power_mw". */
41std::string json::str2key(const char * str)
42{
43 bool prev_underscore = false;
44 size_t i_sz = strlen(str);
45 int o_ind = 0;
46 /* resultant string's size will be <= input string */
47 std::string res(i_sz, ' ');
48 const char * cp = str;
49 static const int lower_alpha_off = 'a' - 'A';
50
51 for ( ; *cp ; ++cp) {
52 char c = *cp;
53
54 if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z')) {
55 res[o_ind++] = c;
56 prev_underscore = false;
57 } else if ('A' <= c && c <= 'Z') {
58 res[o_ind++] = c + lower_alpha_off;
59 prev_underscore = false;
60 } else {
61 if ((o_ind > 0) && ! prev_underscore) {
62 res[o_ind++] = '_';
63 prev_underscore = true;
64 }
65 }
66 }
67 if (o_ind == 0) /* leave single '_' in degenerate case */
68 res[o_ind++] = '_';
69 else if (res[o_ind - 1] == '_')
70 --o_ind; /* may be trailing underscore, remove */
71 res.erase(o_ind);
72 return res;
73}
74
76: m_js(js)
77{
78}
79
80json::ref::ref(json & js, const char * keystr)
81: m_js(js)
82{
83 jassert(keystr && *keystr);
84 m_path.push_back(node_info(keystr));
85}
86
87json::ref::ref(const ref & base, const char * keystr)
88: m_js(base.m_js), m_path(base.m_path)
89{
90 jassert(keystr && *keystr);
91 m_path.push_back(node_info(keystr));
92}
93
94json::ref::ref(const ref & base, int index)
95: m_js(base.m_js), m_path(base.m_path)
96{
97 jassert(0 <= index && index < 10000); // Limit: large arrays not supported
98 m_path.push_back(node_info(index));
99}
100
101json::ref::ref(const ref & base, const char * /*dummy*/, const char * key_suffix)
102: m_js(base.m_js), m_path(base.m_path)
103{
104 int n = (int)m_path.size(), i;
105 for (i = n; --i >= 0; ) {
106 std::string & base_key = m_path[i].key;
107 if (base_key.empty())
108 continue; // skip array
109 base_key += key_suffix;
110 break;
111 }
112 jassert(i >= 0); // Limit: top level element must be an object
113}
114
116{
117}
118
119void json::ref::operator=(bool value)
120{
121 m_js.set_bool(m_path, value);
122}
123
124void json::ref::operator=(long long value)
125{
126 m_js.set_int64(m_path, (int64_t)value);
127}
128
129void json::ref::operator=(unsigned long long value)
130{
131 m_js.set_uint64(m_path, (uint64_t)value);
132}
133
134void json::ref::operator=(int value)
135{
136 operator=((long long)value);
137}
138
139void json::ref::operator=(unsigned value)
140{
141 operator=((unsigned long long)value);
142}
143
144void json::ref::operator=(long value)
145{
146 operator=((long long)value);
147}
148
149void json::ref::operator=(unsigned long value)
150{
151 operator=((unsigned long long)value);
152}
153
154void json::ref::operator=(const char * value)
155{
156 m_js.set_cstring(m_path, value);
157}
158
159void json::ref::operator=(const std::string & value)
160{
161 m_js.set_string(m_path, value);
162}
163
164void json::ref::set_uint128(uint64_t value_hi, uint64_t value_lo)
165{
166 if (!value_hi)
167 operator=((unsigned long long)value_lo);
168 else
169 m_js.set_uint128(m_path, value_hi, value_lo);
170}
171
173{
174 if (!is_safe_uint(value))
175 return false;
176 operator=((unsigned long long)value);
177 return true;
178}
179
180bool json::ref::set_if_safe_uint128(uint64_t value_hi, uint64_t value_lo)
181{
182 if (value_hi)
183 return false;
184 return set_if_safe_uint64(value_lo);
185}
186
187bool json::ref::set_if_safe_le128(const void * pvalue)
188{
189 return set_if_safe_uint128(sg_get_unaligned_le64((const uint8_t *)pvalue + 8),
190 sg_get_unaligned_le64( pvalue ));
191}
192
194{
195 // Output as number "KEY"
196 operator=((unsigned long long)value);
197 if (!m_js.m_verbose && is_safe_uint(value))
198 return;
199 // Output as string "KEY_s"
200 char s[32];
201 snprintf(s, sizeof(s), "%" PRIu64, value);
202 with_suffix("_s") = s;
203}
204
205void json::ref::set_unsafe_uint128(uint64_t value_hi, uint64_t value_lo)
206{
207 if (!m_js.m_verbose && !value_hi)
208 set_unsafe_uint64(value_lo);
209 else {
210 // Output as number "KEY", string "KEY_s" and LE byte array "KEY_le[]"
211 m_js.m_uint128_output = true;
212 set_uint128(value_hi, value_lo);
213 char s[64];
214 with_suffix("_s") = uint128_hilo_to_str(s, value_hi, value_lo);
215 ref le = with_suffix("_le");
216 for (int i = 0; i < 8; i++) {
217 uint64_t v = (value_lo >> (i << 3));
218 if (!v && !value_hi)
219 break;
220 le[i] = v & 0xff;
221 }
222 for (int i = 0; i < 8; i++) {
223 uint64_t v = value_hi >> (i << 3);
224 if (!v)
225 break;
226 le[8 + i] = v & 0xff;
227 }
228 }
229}
230
231void json::ref::set_unsafe_le128(const void * pvalue)
232{
233 set_unsafe_uint128(sg_get_unaligned_le64((const uint8_t *)pvalue + 8),
234 sg_get_unaligned_le64( pvalue ));
235}
236
237void json::ref::operator+=(std::initializer_list<initlist_key_value_pair> ilist)
238{
239 for (const initlist_key_value_pair & kv : ilist) {
240 jassert(kv.keystr && *kv.keystr);
241 switch (kv.value.type) {
242 default: operator[](kv.keystr) = kv.value; break;
243 case nt_object: operator[](kv.keystr) += kv.object; break;
244 case nt_array: operator[](kv.keystr) += kv.array; break;
245 }
246 }
247}
248
249void json::ref::operator+=(std::initializer_list<initlist_value> ilist)
250{
251 int i = 0;
252 for (const initlist_value & v : ilist)
253 operator[](i++) = v;
254}
255
257{
258}
259
260json::node::node(const std::string & key_)
261: key(key_)
262{
263}
264
266{
267}
268
270: m_node_p(node_p),
271 m_use_map(sorted && node_p->type == nt_object)
272{
273 if (m_use_map)
274 m_key_iter = node_p->key2index.begin();
275}
276
278{
279 if (m_use_map)
280 return (m_key_iter == m_node_p->key2index.end());
281 else
282 return (m_child_idx >= m_node_p->childs.size());
283}
284
286{
287 jassert(m_node_p->type == nt_array);
288 return m_child_idx;
289}
290
292{
293 if (m_use_map)
294 ++m_key_iter;
295 else
296 ++m_child_idx;
297}
298
300{
301 if (m_use_map)
302 return m_node_p->childs[m_key_iter->second].get();
303 else
304 return m_node_p->childs[m_child_idx].get();
305}
306
308{
309 node * p = &m_root_node;
310 for (unsigned i = 0; i < path.size(); i++) {
311 const node_info & pi = path[i];
312 if (!pi.key.empty()) {
313 // Object
314 if (p->type == nt_unset)
315 p->type = nt_object;
316 else
317 jassert(p->type == nt_object); // Limit: type change not supported
318 // Existing or new object element?
319 node::keymap::iterator ni = p->key2index.find(pi.key);
320 node * p2;
321 if (ni != p->key2index.end()) {
322 // Object element exists
323 p2 = p->childs[ni->second].get();
324 }
325 else {
326 // Create new object element
327 p->key2index[pi.key] = (unsigned)p->childs.size();
328 p->childs.push_back(std::unique_ptr<node>(p2 = new node(pi.key)));
329 }
330 jassert(p2 && p2->key == pi.key);
331 p = p2;
332 }
333
334 else {
335 // Array
336 if (p->type == nt_unset)
337 p->type = nt_array;
338 else
339 jassert(p->type == nt_array); // Limit: type change not supported
340 node * p2;
341 // Existing or new array element?
342 if (pi.index < (int)p->childs.size()) {
343 // Array index exists
344 p2 = p->childs[pi.index].get();
345 if (!p2) // Already created ?
346 p->childs[pi.index].reset(p2 = new node);
347 }
348 else {
349 // Grow array, fill gap, create new element
350 p->childs.resize(pi.index + 1);
351 p->childs[pi.index].reset(p2 = new node);
352 }
353 jassert(p2 && p2->key.empty());
354 p = p2;
355 }
356 }
357
358 if ( p->type == nt_unset
359 || ( nt_int <= p->type && p->type <= nt_uint128
360 && nt_int <= type && type <= nt_uint128))
361 p->type = type;
362 else
363 jassert(p->type == type); // Limit: type change not supported
364 return p;
365}
366
367void json::set_bool(const node_path & path, bool value)
368{
369 if (!m_enabled)
370 return;
371 find_or_create_node(path, nt_bool)->intval = (value ? 1 : 0);
372}
373
374void json::set_int64(const node_path & path, int64_t value)
375{
376 if (!m_enabled)
377 return;
378 find_or_create_node(path, nt_int)->intval = (uint64_t)value;
379}
380
381void json::set_uint64(const node_path & path, uint64_t value)
382{
383 if (!m_enabled)
384 return;
385 find_or_create_node(path, nt_uint)->intval = value;
386}
387
388void json::set_uint128(const node_path & path, uint64_t value_hi, uint64_t value_lo)
389{
390 if (!m_enabled)
391 return;
393 p->intval_hi = value_hi;
394 p->intval = value_lo;
395}
396
397void json::set_cstring(const node_path & path, const char * value)
398{
399 if (!m_enabled)
400 return;
401 jassert(value != nullptr); // Limit: nullptr not supported
402 find_or_create_node(path, nt_string)->strval = value;
403}
404
405void json::set_string(const node_path & path, const std::string & value)
406{
407 if (!m_enabled)
408 return;
409 find_or_create_node(path, nt_string)->strval = value;
410}
411
412void json::set_initlist_value(const node_path & path, const initlist_value & val)
413{
414 if (!m_enabled)
415 return;
416 node * p = find_or_create_node(path, val.type);
417 switch (p->type) {
418 case nt_bool: case nt_int: case nt_uint: p->intval = val.intval; break;
419 case nt_string: p->strval = val.strval; break;
420 default: jassert(false);
421 }
422}
423
424// Return -1 if all UTF-8 sequences are valid, else return index of first invalid char
425static int check_utf8(const char * s)
426{
427 int state = 0, i;
428 for (i = 0; s[i]; i++) {
429 unsigned char c = s[i];
430 // 0xb... (C++14) not used to preserve C++11 compatibility
431 if ((c & 0xc0) == 0x80) { // 0xb10xxxxx
432 if (--state < 0)
433 return i;
434 }
435 else {
436 if (state != 0)
437 return i;
438 if (!(c & 0x80)) // 0xb0xxxxxxx
439 ;
440 else if ((c & 0xe0) == 0xc0 && (c & 0x1f)) // 0xb110xxxxx
441 state = 1;
442 else if ((c & 0xf0) == 0xe0 && (c & 0x0f)) // 0xb1110xxxx
443 state = 2;
444 else if ((c & 0xf8) == 0xf0 && (c & 0x07)) // 0xb11110xxx
445 state = 3;
446 else
447 return i;
448 }
449 }
450 if (state != 0)
451 return i;
452 return -1;
453}
454
455static void print_quoted_string(FILE * f, const char * s)
456{
457 int utf8_rc = -2;
458 putc('"', f);
459 for (int i = 0; s[i]; i++) {
460 char c = s[i];
461 if (c == '"' || c == '\\')
462 putc('\\', f);
463 else if (c == '\t') {
464 putc('\\', f); c = 't';
465 }
466 // Print as UTF-8 unless the string contains any invalid sequences
467 // "\uXXXX" is not used because it is not valid for YAML
468 if ( (' ' <= c && c <= '~')
469 || ((c & 0x80) && (utf8_rc >= -1 ? utf8_rc : (utf8_rc = check_utf8(s + i))) == -1))
470 putc(c, f);
471 else
472 // Print informal hex string for unexpected chars:
473 // Control chars (except TAB), DEL(0x7f), bit 7 set and no valid UTF-8
474 fprintf(f, "\\\\x%02x", (unsigned char)c);
475 }
476 putc('"', f);
477}
478
479static char yaml_string_needs_quotes(const char * s)
480{
481 if (!*s)
482 return '\''; // empty string
483 bool need = false; char quotes = '\'';
484 for (int i = 0; s[i]; i++) {
485 char c = s[i];
486 if (!(' ' <= c && c <= '~'))
487 return '"'; // non-ascii char
488 if ( ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z')
489 || ('a' <= c && c <= 'z') || c == '_' )
490 continue;
491 if (c == '\'') // if string contains any single quote
492 quotes = '"'; // use double quotes
493 if (i == 0)
494 need = true; // space or special char except '_' at BOL
495 else if (c == ' ' && (s[i-1] == ':' || s[i+1] == '#'))
496 need = true; // ": " or " #"
497 else if ((c == ' ' || c == ':') && !s[i+1])
498 need = true; // space or : at EOL
499 }
500 if (need)
501 return quotes;
502
503 static const regular_expression special(
504 "[0-9]+[,0-9]*(\\.[0-9]*)?([eE][-+]?[0-9]+)?|" // decimal ('^[-+.]' handled above)
505 "0x[0-7A-Fa-f]+|" // hex
506 "[Ff][Aa][Ll][Ss][Ee]|[Tt][Rr][Uu][Ee]|[Nn][Oo]|[Yy][Ee][Ss]|" // boolean
507 "[Nn][Uu][Ll][Ll]" // null
508 );
509 if (special.full_match(s))
510 return quotes; // special token
511 return 0; // none of the above
512}
513
514void json::print_json(FILE * f, bool pretty, bool sorted, const node * p, int level)
515{
516 bool is_obj = (p->type == nt_object);
517 switch (p->type) {
518 case nt_object:
519 case nt_array:
520 putc((is_obj ? '{' : '['), f);
521 if (!p->childs.empty()) {
522 bool first = true;
523 for (node::const_iterator it(p, sorted); !it.at_end(); ++it) {
524 if (!first)
525 putc(',', f);
526 if (pretty)
527 fprintf(f, "\n%*s", (level + 1) * 2, "");
528 const node * p2 = *it;
529 if (!p2) {
530 // Unset element of sparse array
531 jassert(!is_obj);
532 fputs("null", f);
533 }
534 else {
535 jassert(is_obj == !p2->key.empty());
536 if (is_obj)
537 fprintf(f, "\"%s\":%s", p2->key.c_str(), (pretty ? " " : ""));
538 // Recurse
539 print_json(f, pretty, sorted, p2, level + 1);
540 }
541 first = false;
542 }
543 if (pretty)
544 fprintf(f, "\n%*s", level * 2, "");
545 }
546 putc((is_obj ? '}' : ']'), f);
547 break;
548
549 case nt_bool:
550 fputs((p->intval ? "true" : "false"), f);
551 break;
552
553 case nt_int:
554 fprintf(f, "%" PRId64, (int64_t)p->intval);
555 break;
556
557 case nt_uint:
558 fprintf(f, "%" PRIu64, p->intval);
559 break;
560
561 case nt_uint128:
562 {
563 char buf[64];
564 fputs(uint128_hilo_to_str(buf, p->intval_hi, p->intval), f);
565 }
566 break;
567
568 case nt_string:
569 print_quoted_string(f, p->strval.c_str());
570 break;
571
572 default: jassert(false);
573 }
574}
575
576void json::print_yaml(FILE * f, bool pretty, bool sorted, const node * p, int level_o,
577 int level_a, bool cont)
578{
579 bool is_obj = (p->type == nt_object);
580 switch (p->type) {
581 case nt_object:
582 case nt_array:
583 if (!p->childs.empty()) {
584 if (!cont)
585 fputs("\n", f);
586 for (node::const_iterator it(p, sorted); !it.at_end(); ++it) {
587 int spaces = (cont ? 1 : (is_obj ? level_o : level_a) * 2);
588 if (spaces > 0)
589 fprintf(f, "%*s", spaces, "");
590 const node * p2 = *it;
591 if (!p2) {
592 // Unset element of sparse array
593 jassert(!is_obj);
594 fputs("-" /*" null"*/ "\n", f);
595 }
596 else {
597 jassert(is_obj == !p2->key.empty());
598 if (is_obj)
599 fprintf(f, "%s:", p2->key.c_str());
600 else
601 putc('-', f);
602 // Recurse
603 print_yaml(f, pretty, sorted, p2, (is_obj ? level_o : level_a) + 1,
604 (is_obj ? level_o + (pretty ? 1 : 0) : level_a + 1), !is_obj);
605 }
606 cont = false;
607 }
608 }
609 else {
610 fputs((is_obj ? "{}\n" : "[]\n"), f);
611 }
612 break;
613
614 case nt_bool:
615 fputs((p->intval ? " true\n" : " false\n"), f);
616 break;
617
618 case nt_int:
619 fprintf(f, " %" PRId64 "\n", (int64_t)p->intval);
620 break;
621
622 case nt_uint:
623 fprintf(f, " %" PRIu64 "\n", p->intval);
624 break;
625
626 case nt_uint128:
627 {
628 char buf[64];
629 fprintf(f, " %s\n", uint128_hilo_to_str(buf, p->intval_hi, p->intval));
630 }
631 break;
632
633 case nt_string:
634 putc(' ', f);
635 switch (yaml_string_needs_quotes(p->strval.c_str())) {
636 default: print_quoted_string(f, p->strval.c_str()); break;
637 case '\'': fprintf(f, "'%s'", p->strval.c_str()); break;
638 case 0: fputs(p->strval.c_str(), f); break;
639 }
640 putc('\n', f);
641 break;
642
643 default: jassert(false);
644 }
645}
646
647void json::print_flat(FILE * f, const char * assign, bool sorted, const node * p,
648 std::string & path)
649{
650 bool is_obj = (p->type == nt_object);
651 switch (p->type) {
652 case nt_object:
653 case nt_array:
654 fprintf(f, "%s%s%s;\n", path.c_str(), assign, (is_obj ? "{}" : "[]"));
655 if (!p->childs.empty()) {
656 unsigned len = path.size();
657 for (node::const_iterator it(p, sorted); !it.at_end(); ++it) {
658 const node * p2 = *it;
659 if (!is_obj) {
660 char buf[10]; snprintf(buf, sizeof(buf), "[%u]", it.array_index());
661 path += buf;
662 }
663 else {
664 path += '.'; path += p2->key;
665 }
666 if (!p2) {
667 // Unset element of sparse array
668 jassert(!is_obj);
669 fprintf(f, "%s%snull;\n", path.c_str(), assign);
670 }
671 else {
672 // Recurse
673 print_flat(f, assign, sorted, p2, path);
674 }
675 path.erase(len);
676 }
677 }
678 break;
679
680 case nt_bool:
681 fprintf(f, "%s%s%s;\n", path.c_str(), assign, (p->intval ? "true" : "false"));
682 break;
683
684 case nt_int:
685 fprintf(f, "%s%s%" PRId64 ";\n", path.c_str(), assign, (int64_t)p->intval);
686 break;
687
688 case nt_uint:
689 fprintf(f, "%s%s%" PRIu64 ";\n", path.c_str(), assign, p->intval);
690 break;
691
692 case nt_uint128:
693 {
694 char buf[64];
695 fprintf(f, "%s%s%s;\n", path.c_str(), assign,
697 }
698 break;
699
700 case nt_string:
701 fprintf(f, "%s%s", path.c_str(), assign);
702 print_quoted_string(f, p->strval.c_str());
703 fputs(";\n", f);
704 break;
705
706 default: jassert(false);
707 }
708}
709
710void json::print(FILE * f, const print_options & options) const
711{
713 return;
715
716 switch (options.format) {
717 default:
718 print_json(f, options.pretty, options.sorted, &m_root_node, 0);
719 if (options.pretty)
720 putc('\n', f);
721 break;
722 case 'y':
723 fputs("---", f);
724 print_yaml(f, options.pretty, options.sorted, &m_root_node, 0, 0, false);
725 break;
726 case 'g': {
727 std::string path("json");
728 print_flat(f, (options.pretty ? " = " : "="), options.sorted, &m_root_node, path);
729 }
730 break;
731 }
732}
bool at_end() const
Definition: json.cpp:277
unsigned array_index() const
Definition: json.cpp:285
const node * operator*() const
Definition: json.cpp:299
const_iterator(const node *node_p, bool sorted)
Definition: json.cpp:269
keymap::const_iterator m_key_iter
Definition: json.h:240
Reference to a JSON element.
Definition: json.h:105
void set_uint128(uint64_t value_hi, uint64_t value_lo)
Definition: json.cpp:164
ref(json &js)
Definition: json.cpp:75
void set_unsafe_uint128(uint64_t value_hi, uint64_t value_lo)
Definition: json.cpp:205
void operator+=(std::initializer_list< initlist_key_value_pair > ilist)
Braced-init-list support for nested objects.
Definition: json.cpp:237
node_path m_path
Definition: json.h:167
void set_unsafe_le128(const void *pvalue)
Definition: json.cpp:231
void operator=(bool value)
Definition: json.cpp:119
bool set_if_safe_le128(const void *pvalue)
Definition: json.cpp:187
void set_unsafe_uint64(uint64_t value)
Definition: json.cpp:193
bool set_if_safe_uint64(uint64_t value)
Definition: json.cpp:172
~ref()
Definition: json.cpp:115
bool set_if_safe_uint128(uint64_t value_hi, uint64_t value_lo)
Definition: json.cpp:180
Create and print JSON output.
Definition: json.h:24
static void print_flat(FILE *f, const char *assign, bool sorted, const node *p, std::string &path)
Definition: json.cpp:647
std::vector< node_info > node_path
Definition: json.h:100
node m_root_node
Definition: json.h:248
void set_uint64(const node_path &path, uint64_t value)
Definition: json.cpp:381
void set_int64(const node_path &path, int64_t value)
Definition: json.cpp:374
void set_string(const node_path &path, const std::string &value)
Definition: json.cpp:405
void set_initlist_value(const node_path &path, const initlist_value &value)
Definition: json.cpp:412
static std::string str2key(const char *str)
Replace space and non-alphanumerics with '_', upper to lower case.
Definition: json.cpp:41
bool m_enabled
Definition: json.h:244
void set_bool(const node_path &path, bool value)
Definition: json.cpp:367
void set_cstring(const node_path &path, const char *value)
Definition: json.cpp:397
static void print_json(FILE *f, bool pretty, bool sorted, const node *p, int level)
Definition: json.cpp:514
static bool is_safe_uint(unsigned long long value)
Return true if value is a safe JSON integer.
Definition: json.h:28
static void print_yaml(FILE *f, bool pretty, bool sorted, const node *p, int level_o, int level_a, bool cont)
Definition: json.cpp:576
node * find_or_create_node(const node_path &path, node_type type)
Definition: json.cpp:307
ref operator[](const char *keystr)
Return reference to element of top level object.
Definition: json.h:171
void set_uint128(const node_path &path, uint64_t value_hi, uint64_t value_lo)
Definition: json.cpp:388
void print(FILE *f, const print_options &options) const
Print JSON tree to a file.
Definition: json.cpp:710
node_type
Definition: json.h:39
@ nt_unset
Definition: json.h:40
@ nt_uint128
Definition: json.h:41
@ nt_string
Definition: json.h:41
@ nt_bool
Definition: json.h:41
@ nt_int
Definition: json.h:41
@ nt_object
Definition: json.h:40
@ nt_array
Definition: json.h:40
@ nt_uint
Definition: json.h:41
Wrapper class for POSIX regex(3) or std::regex Supports copy & assignment and is compatible with STL ...
Definition: utility.h:222
bool full_match(const char *str) const
Return true if full string matches pattern.
Definition: utility.cpp:593
static void jassert_failed(int line, const char *expr)
Definition: json.cpp:25
static char yaml_string_needs_quotes(const char *s)
Definition: json.cpp:479
#define jassert(expr)
Definition: json.cpp:33
static void print_quoted_string(FILE *f, const char *s)
Definition: json.cpp:455
const char * json_cvsid
Definition: json.cpp:16
static int check_utf8(const char *s)
Definition: json.cpp:425
#define JSON_H_CVSID
Definition: json.h:12
u16 s[6]
Definition: megaraid.h:18
static uint64_t sg_get_unaligned_le64(const void *p)
Definition: sg_unaligned.h:303
uint64_t intval
Definition: json.h:67
node_type type
Definition: json.h:66
const char * strval
Definition: json.h:68
int index
Definition: json.h:93
std::string key
Definition: json.h:92
std::string key
Definition: json.h:222
uint64_t intval_hi
Definition: json.h:219
uint64_t intval
Definition: json.h:219
std::vector< std::unique_ptr< node > > childs
Definition: json.h:223
std::string strval
Definition: json.h:220
node_type type
Definition: json.h:217
keymap key2index
Definition: json.h:225
Options for print().
Definition: json.h:199
const char * uint128_hilo_to_str(char *str, int strsize, uint64_t value_hi, uint64_t value_lo)
Definition: utility.cpp:856