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