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