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