2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include "cave/cavetypes.hpp"
27 #include "misc/printf.hpp"
29 /// All conversion specifiers which are recognized by the class in the format string, eg. printf %s, %d, %c etc.
30 const char *Printf::conv_specifiers
="sdiucfgx";
31 /// Conversion modifiers supported.
32 std::string
Printf::flag_characters
="0-+lhm";
36 * @brief This function html-markups a string.
37 * It will change <, >, &, and \n characters into < > & and <br>.
39 std::string
Printf::html_markup_text(const std::string
& of_what
) {
42 for (unsigned i
=0; i
<of_what
.size(); ++i
) {
66 /// Printf object constructor.
67 /// @param percent Character which specifies a conversion. Default is %, as in misc/printf.
68 /// @param format The format string.
69 Printf::Printf(const std::string
& format_
, char percent
)
73 size_t pos
, nextpos
=0;
74 // search for the next conversion specifier.
75 // the position is stored in pos.
76 // if a %% is found, it is replaced with %, and the search is continued.
77 while ((pos
=format
.find(percent
, nextpos
))!=std::string::npos
) {
78 if (pos
+1==format
.length())
79 throw std::runtime_error("unterminated conversion specifier at the end of the string");
80 if (format
[pos
+1]==percent
) {
81 /* this is just a percent sign */
85 /* this is a conversion specifier. */
86 size_t last
=format
.find_first_of(conv_specifiers
, pos
+1);
87 if (last
==std::string::npos
)
88 throw std::runtime_error("unterminated conversion specifier");
90 // ok we found something like %-5s. get the conversion type (s), and get
91 // the manipulator (-5).
94 c
.conv
= format
[last
];
95 c
.manip
= format
.substr(pos
+1, last
-pos
-1);
96 c
.html_markup
= format
.find('m') != std::string::npos
;
97 conversions
.push_back(c
);
98 // now delete the conversion specifier from the string.
99 format
.erase(pos
, last
-pos
+1);
105 /// This function finds the next conversion specifier in the format string,
106 /// and sets the ostringstream accordingly.
107 /// This is put in a separate function, so the templated function (operator%) is
108 /// not too long - to prevent code bloat.
109 /// Also it removes the conversion specifier from the format string.
110 /// @param os The ostringstream to setup according to the next found conversion specifier.
111 /// @param pos The position, which is the char position of the original conversion specifier.
112 void Printf::configure_ostream(std::ostringstream
& os
, Conversion
&conversion
) const {
113 // process format specifier.
114 // the type of the variable to be written is mainly handled by
115 // the c++ type system. here we only take care of the small
117 if (conversion
.conv
=='x')
118 os
<<std::hex
; // %x used to print in hexadecimal
120 // if we have a manipulator, is it at the beginning of the string
121 while (flag_characters
.find_first_of(conversion
.manip
[0])!=std::string::npos
) {
122 switch(conversion
.manip
[0]) {
134 // do nothing; for compatibility with printf;
137 // html markup; already noted it in the conversion
140 assert(!"don't know how to process flag character");
143 conversion
.manip
.erase(0, 1); // erase processed flag from the string
145 // if the manipulator is not empty, it must be a width [. precision].
146 if (!conversion
.manip
.empty()) {
147 std::istringstream
is(conversion
.manip
);
152 is
.clear(); // clear error state, as we might not have had a width specifier
158 throw std::runtime_error("invalid precision");
159 os
<< std::fixed
; // so it is the same as printf %6.4 -> [3.1400]
160 os
.precision(precision
);
165 /// This function puts the contents of the ostringstream to the
166 /// string at the given position.
167 /// @param os The ostringstream, which should already contain the data formatted.
168 /// @param pos The position to insert the contents of the string at.
169 void Printf::insert_converted(std::string
const &str
, Conversion
&conversion
) const {
170 // add inserted_chars to the originally calculated position - as
171 // before this conversion, the already finished conversions added that much characters before the current position
172 format
.insert(conversion
.pos
+ inserted_chars
, str
);
173 // and remember the next successive position
174 inserted_chars
+= str
.length();