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