]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/Formatter.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / common / Formatter.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#define LARGE_SIZE 1024
16
7c673cae
FG
17#include "HTMLFormatter.h"
18#include "common/escape.h"
19#include "include/buffer.h"
20
f67539c2 21#include <fmt/format.h>
7c673cae 22#include <set>
11fdf7f2 23#include <limits>
7c673cae 24
7c673cae
FG
25// -----------------------
26namespace ceph {
27
eafe8130
TL
28std::string
29fixed_u_to_string(uint64_t num, int scale)
30{
31 std::ostringstream t;
32
33 t.fill('0');
34 t.width(scale + 1);
35 t << num;
36 int len = t.str().size();
37 return t.str().substr(0,len - scale) + "." + t.str().substr(len - scale);
38}
39
40std::string
41fixed_to_string(int64_t num, int scale)
42{
43 std::ostringstream t;
44 bool neg = num < 0;
45 if (neg) num = -num;
46
47 t.fill('0');
48 t.width(scale + 1);
49 t << num;
50 int len = t.str().size();
51 return (neg ? "-" : "") + t.str().substr(0,len - scale) + "." + t.str().substr(len - scale);
52}
53
7c673cae
FG
54/*
55 * FormatterAttrs(const char *attr, ...)
56 *
57 * Requires a list of attrs followed by NULL. The attrs should be char *
58 * pairs, first one is the name, second one is the value. E.g.,
59 *
60 * FormatterAttrs("name1", "value1", "name2", "value2", NULL);
61 */
62FormatterAttrs::FormatterAttrs(const char *attr, ...)
63{
64 const char *s = attr;
65 va_list ap;
66 va_start(ap, attr);
67 do {
68 const char *val = va_arg(ap, char *);
69 if (!val)
70 break;
71
72 attrs.push_back(make_pair(std::string(s), std::string(val)));
73 s = va_arg(ap, char *);
74 } while (s);
75 va_end(ap);
76}
77
f67539c2
TL
78void Formatter::write_bin_data(const char*, int){}
79
7c673cae
FG
80Formatter::Formatter() { }
81
82Formatter::~Formatter() { }
83
11fdf7f2
TL
84Formatter *Formatter::create(std::string_view type,
85 std::string_view default_type,
86 std::string_view fallback)
7c673cae 87{
f67539c2
TL
88 std::string_view mytype(type);
89 if (mytype.empty()) {
11fdf7f2 90 mytype = default_type;
f67539c2 91 }
7c673cae
FG
92
93 if (mytype == "json")
94 return new JSONFormatter(false);
95 else if (mytype == "json-pretty")
96 return new JSONFormatter(true);
97 else if (mytype == "xml")
98 return new XMLFormatter(false);
99 else if (mytype == "xml-pretty")
100 return new XMLFormatter(true);
101 else if (mytype == "table")
102 return new TableFormatter();
103 else if (mytype == "table-kv")
104 return new TableFormatter(true);
105 else if (mytype == "html")
106 return new HTMLFormatter(false);
107 else if (mytype == "html-pretty")
108 return new HTMLFormatter(true);
109 else if (fallback != "")
110 return create(fallback, "", "");
111 else
112 return (Formatter *) NULL;
113}
114
115
116void Formatter::flush(bufferlist &bl)
117{
118 std::stringstream os;
119 flush(os);
120 bl.append(os.str());
121}
122
9f95a23c 123void Formatter::dump_format(std::string_view name, const char *fmt, ...)
7c673cae
FG
124{
125 va_list ap;
126 va_start(ap, fmt);
127 dump_format_va(name, NULL, true, fmt, ap);
128 va_end(ap);
129}
130
9f95a23c 131void Formatter::dump_format_ns(std::string_view name, const char *ns, const char *fmt, ...)
7c673cae
FG
132{
133 va_list ap;
134 va_start(ap, fmt);
135 dump_format_va(name, ns, true, fmt, ap);
136 va_end(ap);
137
138}
139
9f95a23c 140void Formatter::dump_format_unquoted(std::string_view name, const char *fmt, ...)
7c673cae
FG
141{
142 va_list ap;
143 va_start(ap, fmt);
144 dump_format_va(name, NULL, false, fmt, ap);
145 va_end(ap);
146}
147
148// -----------------------
149
150JSONFormatter::JSONFormatter(bool p)
151: m_pretty(p), m_is_pending_string(false)
152{
153 reset();
154}
155
156void JSONFormatter::flush(std::ostream& os)
157{
158 finish_pending_string();
159 os << m_ss.str();
181888fb
FG
160 if (m_line_break_enabled)
161 os << "\n";
7c673cae
FG
162 m_ss.clear();
163 m_ss.str("");
164}
165
166void JSONFormatter::reset()
167{
168 m_stack.clear();
169 m_ss.clear();
170 m_ss.str("");
171 m_pending_string.clear();
172 m_pending_string.str("");
173}
174
175void JSONFormatter::print_comma(json_formatter_stack_entry_d& entry)
176{
177 if (entry.size) {
178 if (m_pretty) {
179 m_ss << ",\n";
180 for (unsigned i = 1; i < m_stack.size(); i++)
181 m_ss << " ";
182 } else {
183 m_ss << ",";
184 }
185 } else if (m_pretty) {
186 m_ss << "\n";
187 for (unsigned i = 1; i < m_stack.size(); i++)
188 m_ss << " ";
189 }
190 if (m_pretty && entry.is_array)
191 m_ss << " ";
192}
193
11fdf7f2 194void JSONFormatter::print_quoted_string(std::string_view s)
7c673cae 195{
11fdf7f2 196 m_ss << '\"' << json_stream_escaper(s) << '\"';
7c673cae
FG
197}
198
9f95a23c 199void JSONFormatter::print_name(std::string_view name)
7c673cae
FG
200{
201 finish_pending_string();
202 if (m_stack.empty())
203 return;
204 struct json_formatter_stack_entry_d& entry = m_stack.back();
205 print_comma(entry);
206 if (!entry.is_array) {
207 if (m_pretty) {
208 m_ss << " ";
209 }
210 m_ss << "\"" << name << "\"";
211 if (m_pretty)
212 m_ss << ": ";
213 else
214 m_ss << ':';
215 }
216 ++entry.size;
217}
218
9f95a23c 219void JSONFormatter::open_section(std::string_view name, const char *ns, bool is_array)
7c673cae 220{
11fdf7f2
TL
221 if (handle_open_section(name, ns, is_array)) {
222 return;
223 }
224 if (ns) {
225 std::ostringstream oss;
226 oss << name << " " << ns;
227 print_name(oss.str().c_str());
228 } else {
229 print_name(name);
230 }
7c673cae
FG
231 if (is_array)
232 m_ss << '[';
233 else
234 m_ss << '{';
235
236 json_formatter_stack_entry_d n;
237 n.is_array = is_array;
238 m_stack.push_back(n);
239}
240
9f95a23c 241void JSONFormatter::open_array_section(std::string_view name)
7c673cae 242{
11fdf7f2 243 open_section(name, nullptr, true);
7c673cae
FG
244}
245
9f95a23c 246void JSONFormatter::open_array_section_in_ns(std::string_view name, const char *ns)
7c673cae 247{
11fdf7f2 248 open_section(name, ns, true);
7c673cae
FG
249}
250
9f95a23c 251void JSONFormatter::open_object_section(std::string_view name)
7c673cae 252{
11fdf7f2 253 open_section(name, nullptr, false);
7c673cae
FG
254}
255
9f95a23c 256void JSONFormatter::open_object_section_in_ns(std::string_view name, const char *ns)
7c673cae 257{
11fdf7f2 258 open_section(name, ns, false);
7c673cae
FG
259}
260
261void JSONFormatter::close_section()
262{
11fdf7f2
TL
263
264 if (handle_close_section()) {
265 return;
266 }
267 ceph_assert(!m_stack.empty());
7c673cae
FG
268 finish_pending_string();
269
270 struct json_formatter_stack_entry_d& entry = m_stack.back();
271 if (m_pretty && entry.size) {
272 m_ss << "\n";
273 for (unsigned i = 1; i < m_stack.size(); i++)
274 m_ss << " ";
275 }
276 m_ss << (entry.is_array ? ']' : '}');
277 m_stack.pop_back();
278 if (m_pretty && m_stack.empty())
279 m_ss << "\n";
280}
281
282void JSONFormatter::finish_pending_string()
283{
284 if (m_is_pending_string) {
7c673cae 285 m_is_pending_string = false;
11fdf7f2
TL
286 add_value(m_pending_name.c_str(), m_pending_string.str(), true);
287 m_pending_string.str("");
7c673cae
FG
288 }
289}
290
11fdf7f2 291template <class T>
9f95a23c 292void JSONFormatter::add_value(std::string_view name, T val)
11fdf7f2
TL
293{
294 std::stringstream ss;
295 ss.precision(std::numeric_limits<T>::max_digits10);
296 ss << val;
297 add_value(name, ss.str(), false);
298}
299
9f95a23c 300void JSONFormatter::add_value(std::string_view name, std::string_view val, bool quoted)
7c673cae 301{
11fdf7f2
TL
302 if (handle_value(name, val, quoted)) {
303 return;
304 }
7c673cae 305 print_name(name);
11fdf7f2
TL
306 if (!quoted) {
307 m_ss << val;
308 } else {
309 print_quoted_string(val);
310 }
311}
312
9f95a23c 313void JSONFormatter::dump_unsigned(std::string_view name, uint64_t u)
11fdf7f2
TL
314{
315 add_value(name, u);
7c673cae
FG
316}
317
9f95a23c 318void JSONFormatter::dump_int(std::string_view name, int64_t s)
7c673cae 319{
11fdf7f2 320 add_value(name, s);
7c673cae
FG
321}
322
9f95a23c 323void JSONFormatter::dump_float(std::string_view name, double d)
7c673cae 324{
11fdf7f2 325 add_value(name, d);
7c673cae
FG
326}
327
9f95a23c 328void JSONFormatter::dump_string(std::string_view name, std::string_view s)
7c673cae 329{
11fdf7f2 330 add_value(name, s, true);
7c673cae
FG
331}
332
9f95a23c 333std::ostream& JSONFormatter::dump_stream(std::string_view name)
7c673cae 334{
11fdf7f2
TL
335 finish_pending_string();
336 m_pending_name = name;
7c673cae
FG
337 m_is_pending_string = true;
338 return m_pending_string;
339}
340
9f95a23c 341void JSONFormatter::dump_format_va(std::string_view name, const char *ns, bool quoted, const char *fmt, va_list ap)
7c673cae
FG
342{
343 char buf[LARGE_SIZE];
344 vsnprintf(buf, LARGE_SIZE, fmt, ap);
345
11fdf7f2 346 add_value(name, buf, quoted);
7c673cae
FG
347}
348
349int JSONFormatter::get_len() const
350{
351 return m_ss.str().size();
352}
353
354void JSONFormatter::write_raw_data(const char *data)
355{
356 m_ss << data;
357}
358
359const char *XMLFormatter::XML_1_DTD =
360 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
361
362XMLFormatter::XMLFormatter(bool pretty, bool lowercased, bool underscored)
363: m_pretty(pretty),
364 m_lowercased(lowercased),
365 m_underscored(underscored)
366{
367 reset();
368}
369
370void XMLFormatter::flush(std::ostream& os)
371{
372 finish_pending_string();
373 std::string m_ss_str = m_ss.str();
374 os << m_ss_str;
375 /* There is a small catch here. If the rest of the formatter had NO output,
376 * we should NOT output a newline. This primarily triggers on HTTP redirects */
377 if (m_pretty && !m_ss_str.empty())
378 os << "\n";
181888fb
FG
379 else if (m_line_break_enabled)
380 os << "\n";
7c673cae
FG
381 m_ss.clear();
382 m_ss.str("");
383}
384
385void XMLFormatter::reset()
386{
387 m_ss.clear();
388 m_ss.str("");
389 m_pending_string.clear();
390 m_pending_string.str("");
391 m_sections.clear();
392 m_pending_string_name.clear();
393 m_header_done = false;
394}
395
396void XMLFormatter::output_header()
397{
398 if(!m_header_done) {
399 m_header_done = true;
11fdf7f2 400 write_raw_data(XMLFormatter::XML_1_DTD);
7c673cae
FG
401 if (m_pretty)
402 m_ss << "\n";
403 }
404}
405
406void XMLFormatter::output_footer()
407{
408 while(!m_sections.empty()) {
409 close_section();
410 }
411}
412
9f95a23c 413void XMLFormatter::open_object_section(std::string_view name)
7c673cae
FG
414{
415 open_section_in_ns(name, NULL, NULL);
416}
417
9f95a23c 418void XMLFormatter::open_object_section_with_attrs(std::string_view name, const FormatterAttrs& attrs)
7c673cae
FG
419{
420 open_section_in_ns(name, NULL, &attrs);
421}
422
9f95a23c 423void XMLFormatter::open_object_section_in_ns(std::string_view name, const char *ns)
7c673cae
FG
424{
425 open_section_in_ns(name, ns, NULL);
426}
427
9f95a23c 428void XMLFormatter::open_array_section(std::string_view name)
7c673cae
FG
429{
430 open_section_in_ns(name, NULL, NULL);
431}
432
9f95a23c 433void XMLFormatter::open_array_section_with_attrs(std::string_view name, const FormatterAttrs& attrs)
7c673cae
FG
434{
435 open_section_in_ns(name, NULL, &attrs);
436}
437
9f95a23c 438void XMLFormatter::open_array_section_in_ns(std::string_view name, const char *ns)
7c673cae
FG
439{
440 open_section_in_ns(name, ns, NULL);
441}
442
443void XMLFormatter::close_section()
444{
11fdf7f2 445 ceph_assert(!m_sections.empty());
7c673cae
FG
446 finish_pending_string();
447
448 std::string section = m_sections.back();
449 std::transform(section.begin(), section.end(), section.begin(),
450 [this](char c) { return this->to_lower_underscore(c); });
451 m_sections.pop_back();
452 print_spaces();
453 m_ss << "</" << section << ">";
454 if (m_pretty)
455 m_ss << "\n";
456}
457
11fdf7f2 458template <class T>
9f95a23c 459void XMLFormatter::add_value(std::string_view name, T val)
7c673cae
FG
460{
461 std::string e(name);
462 std::transform(e.begin(), e.end(), e.begin(),
463 [this](char c) { return this->to_lower_underscore(c); });
464
465 print_spaces();
11fdf7f2
TL
466 m_ss.precision(std::numeric_limits<T>::max_digits10);
467 m_ss << "<" << e << ">" << val << "</" << e << ">";
7c673cae
FG
468 if (m_pretty)
469 m_ss << "\n";
470}
471
9f95a23c 472void XMLFormatter::dump_unsigned(std::string_view name, uint64_t u)
7c673cae 473{
11fdf7f2
TL
474 add_value(name, u);
475}
7c673cae 476
9f95a23c 477void XMLFormatter::dump_int(std::string_view name, int64_t s)
11fdf7f2
TL
478{
479 add_value(name, s);
7c673cae
FG
480}
481
9f95a23c 482void XMLFormatter::dump_float(std::string_view name, double d)
7c673cae 483{
11fdf7f2 484 add_value(name, d);
7c673cae
FG
485}
486
9f95a23c 487void XMLFormatter::dump_string(std::string_view name, std::string_view s)
7c673cae
FG
488{
489 std::string e(name);
490 std::transform(e.begin(), e.end(), e.begin(),
491 [this](char c) { return this->to_lower_underscore(c); });
492
493 print_spaces();
11fdf7f2 494 m_ss << "<" << e << ">" << xml_stream_escaper(s) << "</" << e << ">";
7c673cae
FG
495 if (m_pretty)
496 m_ss << "\n";
497}
498
9f95a23c 499void XMLFormatter::dump_string_with_attrs(std::string_view name, std::string_view s, const FormatterAttrs& attrs)
7c673cae
FG
500{
501 std::string e(name);
502 std::transform(e.begin(), e.end(), e.begin(),
503 [this](char c) { return this->to_lower_underscore(c); });
504
505 std::string attrs_str;
506 get_attrs_str(&attrs, attrs_str);
507 print_spaces();
11fdf7f2 508 m_ss << "<" << e << attrs_str << ">" << xml_stream_escaper(s) << "</" << e << ">";
7c673cae
FG
509 if (m_pretty)
510 m_ss << "\n";
511}
512
9f95a23c 513std::ostream& XMLFormatter::dump_stream(std::string_view name)
7c673cae
FG
514{
515 print_spaces();
516 m_pending_string_name = name;
517 m_ss << "<" << m_pending_string_name << ">";
518 return m_pending_string;
519}
520
9f95a23c 521void XMLFormatter::dump_format_va(std::string_view name, const char *ns, bool quoted, const char *fmt, va_list ap)
7c673cae
FG
522{
523 char buf[LARGE_SIZE];
11fdf7f2 524 size_t len = vsnprintf(buf, LARGE_SIZE, fmt, ap);
7c673cae
FG
525 std::string e(name);
526 std::transform(e.begin(), e.end(), e.begin(),
527 [this](char c) { return this->to_lower_underscore(c); });
528
529 print_spaces();
530 if (ns) {
9f95a23c 531 m_ss << "<" << e << " xmlns=\"" << ns << "\">" << xml_stream_escaper(std::string_view(buf, len)) << "</" << e << ">";
7c673cae 532 } else {
11fdf7f2 533 m_ss << "<" << e << ">" << xml_stream_escaper(std::string_view(buf, len)) << "</" << e << ">";
7c673cae
FG
534 }
535
536 if (m_pretty)
537 m_ss << "\n";
538}
539
540int XMLFormatter::get_len() const
541{
542 return m_ss.str().size();
543}
544
545void XMLFormatter::write_raw_data(const char *data)
546{
547 m_ss << data;
548}
549
f67539c2
TL
550void XMLFormatter::write_bin_data(const char* buff, int buf_len)
551{
552 std::stringbuf *pbuf = m_ss.rdbuf();
553 pbuf->sputn(buff, buf_len);
554 m_ss.seekg(buf_len);
555}
556
7c673cae
FG
557void XMLFormatter::get_attrs_str(const FormatterAttrs *attrs, std::string& attrs_str)
558{
559 std::stringstream attrs_ss;
560
561 for (std::list<std::pair<std::string, std::string> >::const_iterator iter = attrs->attrs.begin();
562 iter != attrs->attrs.end(); ++iter) {
563 std::pair<std::string, std::string> p = *iter;
564 attrs_ss << " " << p.first << "=" << "\"" << p.second << "\"";
565 }
566
567 attrs_str = attrs_ss.str();
568}
569
9f95a23c 570void XMLFormatter::open_section_in_ns(std::string_view name, const char *ns, const FormatterAttrs *attrs)
7c673cae
FG
571{
572 print_spaces();
573 std::string attrs_str;
574
575 if (attrs) {
576 get_attrs_str(attrs, attrs_str);
577 }
578
579 std::string e(name);
580 std::transform(e.begin(), e.end(), e.begin(),
581 [this](char c) { return this->to_lower_underscore(c); });
582
583 if (ns) {
584 m_ss << "<" << e << attrs_str << " xmlns=\"" << ns << "\">";
585 } else {
586 m_ss << "<" << e << attrs_str << ">";
587 }
588 if (m_pretty)
589 m_ss << "\n";
9f95a23c 590 m_sections.push_back(std::string(name));
7c673cae
FG
591}
592
593void XMLFormatter::finish_pending_string()
594{
595 if (!m_pending_string_name.empty()) {
11fdf7f2 596 m_ss << xml_stream_escaper(m_pending_string.str())
7c673cae
FG
597 << "</" << m_pending_string_name << ">";
598 m_pending_string_name.clear();
599 m_pending_string.str(std::string());
600 if (m_pretty) {
601 m_ss << "\n";
602 }
603 }
604}
605
606void XMLFormatter::print_spaces()
607{
608 finish_pending_string();
609 if (m_pretty) {
610 std::string spaces(m_sections.size(), ' ');
611 m_ss << spaces;
612 }
613}
614
7c673cae
FG
615char XMLFormatter::to_lower_underscore(char c) const
616{
617 if (m_underscored && c == ' ') {
618 return '_';
619 } else if (m_lowercased) {
620 return std::tolower(c);
621 }
622 return c;
623}
624
625TableFormatter::TableFormatter(bool keyval) : m_keyval(keyval)
626{
627 reset();
628}
629
630void TableFormatter::flush(std::ostream& os)
631{
632 finish_pending_string();
633 std::vector<size_t> column_size = m_column_size;
634 std::vector<std::string> column_name = m_column_name;
635
636 std::set<int> need_header_set;
637
638 // auto-sizing columns
639 for (size_t i = 0; i < m_vec.size(); i++) {
640 for (size_t j = 0; j < m_vec[i].size(); j++) {
641 column_size.resize(m_vec[i].size());
642 column_name.resize(m_vec[i].size());
643 if (i > 0) {
644 if (m_vec[i - 1][j] != m_vec[i][j]) {
645 // changing row labels require to show the header
646 need_header_set.insert(i);
647 column_name[i] = m_vec[i][j].first;
648 }
649 } else {
650 column_name[i] = m_vec[i][j].first;
651 }
652
653 if (m_vec[i][j].second.length() > column_size[j])
654 column_size[j] = m_vec[i][j].second.length();
655 if (m_vec[i][j].first.length() > column_size[j])
656 column_size[j] = m_vec[i][j].first.length();
657 }
658 }
659
660 bool need_header = false;
661 if ((column_size.size() == m_column_size.size())) {
662 for (size_t i = 0; i < column_size.size(); i++) {
663 if (column_size[i] != m_column_size[i]) {
664 need_header = true;
665 break;
666 }
667 }
668 } else {
669 need_header = true;
670 }
671
672 if (need_header) {
673 // first row always needs a header if there wasn't one before
674 need_header_set.insert(0);
675 }
676
677 m_column_size = column_size;
678 for (size_t i = 0; i < m_vec.size(); i++) {
679 if (i == 0) {
680 if (need_header_set.count(i)) {
681 // print the header
682 if (!m_keyval) {
683 os << "+";
684 for (size_t j = 0; j < m_vec[i].size(); j++) {
685 for (size_t v = 0; v < m_column_size[j] + 3; v++)
686 os << "-";
687 os << "+";
688 }
689 os << "\n";
690 os << "|";
691
692 for (size_t j = 0; j < m_vec[i].size(); j++) {
f67539c2
TL
693 os << fmt::format(" {:<{}}|",
694 m_vec[i][j].first, m_column_size[j] + 2);
7c673cae
FG
695 }
696 os << "\n";
697 os << "+";
698 for (size_t j = 0; j < m_vec[i].size(); j++) {
699 for (size_t v = 0; v < m_column_size[j] + 3; v++)
700 os << "-";
701 os << "+";
702 }
703 os << "\n";
704 }
705 }
706 }
707 // print body
708 if (!m_keyval)
709 os << "|";
710 for (size_t j = 0; j < m_vec[i].size(); j++) {
711 if (!m_keyval)
712 os << " ";
7c673cae
FG
713 if (m_keyval) {
714 os << "key::";
715 os << m_vec[i][j].first;
716 os << "=";
717 os << "\"";
718 os << m_vec[i][j].second;
719 os << "\" ";
720 } else {
f67539c2 721 os << fmt::format("{:<{}}|", m_vec[i][j].second, m_column_size[j] + 2);
7c673cae
FG
722 }
723 }
724
725 os << "\n";
726 if (!m_keyval) {
727 if (i == (m_vec.size() - 1)) {
728 // print trailer
729 os << "+";
730 for (size_t j = 0; j < m_vec[i].size(); j++) {
731 for (size_t v = 0; v < m_column_size[j] + 3; v++)
732 os << "-";
733 os << "+";
734 }
735 os << "\n";
736 }
737 }
738 m_vec[i].clear();
739 }
740 m_vec.clear();
741}
742
743void TableFormatter::reset()
744{
745 m_ss.clear();
746 m_ss.str("");
747 m_section_cnt.clear();
748 m_column_size.clear();
749 m_section_open = 0;
750}
751
9f95a23c 752void TableFormatter::open_object_section(std::string_view name)
7c673cae
FG
753{
754 open_section_in_ns(name, NULL, NULL);
755}
756
9f95a23c 757void TableFormatter::open_object_section_with_attrs(std::string_view name, const FormatterAttrs& attrs)
7c673cae
FG
758{
759 open_section_in_ns(name, NULL, NULL);
760}
761
9f95a23c 762void TableFormatter::open_object_section_in_ns(std::string_view name, const char *ns)
7c673cae
FG
763{
764 open_section_in_ns(name, NULL, NULL);
765}
766
9f95a23c 767void TableFormatter::open_array_section(std::string_view name)
7c673cae
FG
768{
769 open_section_in_ns(name, NULL, NULL);
770}
771
9f95a23c 772void TableFormatter::open_array_section_with_attrs(std::string_view name, const FormatterAttrs& attrs)
7c673cae
FG
773{
774 open_section_in_ns(name, NULL, NULL);
775}
776
9f95a23c 777void TableFormatter::open_array_section_in_ns(std::string_view name, const char *ns)
7c673cae
FG
778{
779 open_section_in_ns(name, NULL, NULL);
780}
781
9f95a23c 782void TableFormatter::open_section_in_ns(std::string_view name, const char *ns, const FormatterAttrs *attrs)
7c673cae 783{
9f95a23c 784 m_section.push_back(std::string(name));
7c673cae
FG
785 m_section_open++;
786}
787
788void TableFormatter::close_section()
789{
790 //
791 m_section_open--;
792 if (m_section.size()) {
793 m_section_cnt[m_section.back()] = 0;
794 m_section.pop_back();
795 }
796}
797
9f95a23c 798size_t TableFormatter::m_vec_index(std::string_view name)
7c673cae
FG
799{
800 std::string key(name);
801
802 size_t i = m_vec.size();
803 if (i)
804 i--;
805
806 // make sure there are vectors to push back key/val pairs
807 if (!m_vec.size())
808 m_vec.resize(1);
809
810 if (m_vec.size()) {
811 if (m_vec[i].size()) {
812 if (m_vec[i][0].first == key) {
813 // start a new column if a key is repeated
814 m_vec.resize(m_vec.size() + 1);
815 i++;
816 }
817 }
818 }
819
820 return i;
821}
822
9f95a23c 823std::string TableFormatter::get_section_name(std::string_view name)
7c673cae 824{
9f95a23c 825 std::string t_name{name};
7c673cae
FG
826 for (size_t i = 0; i < m_section.size(); i++) {
827 t_name.insert(0, ":");
828 t_name.insert(0, m_section[i]);
829 }
830 if (m_section_open) {
831 std::stringstream lss;
832 lss << t_name;
833 lss << "[";
834 lss << m_section_cnt[t_name]++;
835 lss << "]";
836 return lss.str();
837 } else {
838 return t_name;
839 }
840}
841
11fdf7f2 842template <class T>
9f95a23c 843void TableFormatter::add_value(std::string_view name, T val) {
7c673cae
FG
844 finish_pending_string();
845 size_t i = m_vec_index(name);
11fdf7f2
TL
846 m_ss.precision(std::numeric_limits<double>::max_digits10);
847 m_ss << val;
848
7c673cae
FG
849 m_vec[i].push_back(std::make_pair(get_section_name(name), m_ss.str()));
850 m_ss.clear();
851 m_ss.str("");
852}
853
9f95a23c 854void TableFormatter::dump_unsigned(std::string_view name, uint64_t u)
7c673cae 855{
11fdf7f2 856 add_value(name, u);
7c673cae
FG
857}
858
9f95a23c 859void TableFormatter::dump_int(std::string_view name, int64_t s)
7c673cae 860{
11fdf7f2
TL
861 add_value(name, s);
862}
7c673cae 863
9f95a23c 864void TableFormatter::dump_float(std::string_view name, double d)
11fdf7f2
TL
865{
866 add_value(name, d);
7c673cae
FG
867}
868
9f95a23c 869void TableFormatter::dump_string(std::string_view name, std::string_view s)
7c673cae
FG
870{
871 finish_pending_string();
872 size_t i = m_vec_index(name);
873 m_ss << s;
874
875 m_vec[i].push_back(std::make_pair(get_section_name(name), m_ss.str()));
876 m_ss.clear();
877 m_ss.str("");
878}
879
9f95a23c 880void TableFormatter::dump_string_with_attrs(std::string_view name, std::string_view s, const FormatterAttrs& attrs)
7c673cae
FG
881{
882 finish_pending_string();
883 size_t i = m_vec_index(name);
884
885 std::string attrs_str;
886 get_attrs_str(&attrs, attrs_str);
887 m_ss << attrs_str << s;
888
889 m_vec[i].push_back(std::make_pair(get_section_name(name), m_ss.str()));
890 m_ss.clear();
891 m_ss.str("");
892}
893
9f95a23c
TL
894void TableFormatter::dump_format_va(std::string_view name,
895 const char *ns, bool quoted,
896 const char *fmt, va_list ap)
7c673cae
FG
897{
898 finish_pending_string();
899 char buf[LARGE_SIZE];
900 vsnprintf(buf, LARGE_SIZE, fmt, ap);
901
902 size_t i = m_vec_index(name);
903 if (ns) {
904 m_ss << ns << "." << buf;
905 } else
906 m_ss << buf;
907
908 m_vec[i].push_back(std::make_pair(get_section_name(name), m_ss.str()));
909 m_ss.clear();
910 m_ss.str("");
911}
912
9f95a23c 913std::ostream& TableFormatter::dump_stream(std::string_view name)
7c673cae
FG
914{
915 finish_pending_string();
916 // we don't support this
917 m_pending_name = name;
918 return m_ss;
919}
920
921int TableFormatter::get_len() const
922{
923 // we don't know the size until flush is called
924 return 0;
925}
926
927void TableFormatter::write_raw_data(const char *data) {
928 // not supported
929}
930
931void TableFormatter::get_attrs_str(const FormatterAttrs *attrs, std::string& attrs_str)
932{
933 std::stringstream attrs_ss;
934
935 for (std::list<std::pair<std::string, std::string> >::const_iterator iter = attrs->attrs.begin();
936 iter != attrs->attrs.end(); ++iter) {
937 std::pair<std::string, std::string> p = *iter;
938 attrs_ss << " " << p.first << "=" << "\"" << p.second << "\"";
939 }
940
941 attrs_str = attrs_ss.str();
942}
943
944void TableFormatter::finish_pending_string()
945{
946 if (m_pending_name.length()) {
947 std::string ss = m_ss.str();
948 m_ss.clear();
949 m_ss.str("");
950 std::string pending_name = m_pending_name;
951 m_pending_name = "";
952 dump_string(pending_name.c_str(), ss);
953 }
954}
955}
956