1//
2// Format.cpp
3//
4// Library: Foundation
5// Package: Core
6// Module: Format
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Format.h"
16#include "Poco/Exception.h"
17#include "Poco/Ascii.h"
18#include <sstream>
19#if !defined(POCO_NO_LOCALE)
20#include <locale>
21#endif
22#include <cstddef>
23
24
25namespace Poco {
26
27
28namespace
29{
30 void parseFlags(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt)
31 {
32 bool isFlag = true;
33 while (isFlag && itFmt != endFmt)
34 {
35 switch (*itFmt)
36 {
37 case '-': str.setf(std::ios::left); ++itFmt; break;
38 case '+': str.setf(std::ios::showpos); ++itFmt; break;
39 case '0': str.fill('0'); str.setf(std::ios::internal); ++itFmt; break;
40 case '#': str.setf(std::ios::showpoint | std::ios::showbase); ++itFmt; break;
41 default: isFlag = false; break;
42 }
43 }
44 }
45
46
47 void parseWidth(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt, std::vector<Any>::const_iterator& itVal)
48 {
49 int width = 0;
50 if (itFmt != endFmt && *itFmt == '*')
51 {
52 ++itFmt;
53 width = AnyCast<int>(*itVal++);
54 }
55 else
56 {
57 while (itFmt != endFmt && Ascii::isDigit(*itFmt))
58 {
59 width = 10*width + *itFmt - '0';
60 ++itFmt;
61 }
62 }
63 if (width > 0) str.width(width);
64 }
65
66
67 void parsePrec(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt, std::vector<Any>::const_iterator& itVal)
68 {
69 if (itFmt != endFmt && *itFmt == '.')
70 {
71 ++itFmt;
72 int prec = 0;
73 if (itFmt != endFmt && *itFmt == '*')
74 {
75 ++itFmt;
76 prec = AnyCast<int>(*itVal++);
77 }
78 else
79 {
80 while (itFmt != endFmt && Ascii::isDigit(*itFmt))
81 {
82 prec = 10*prec + *itFmt - '0';
83 ++itFmt;
84 }
85 }
86 if (prec >= 0) str.precision(prec);
87 }
88 }
89
90 char parseMod(std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt)
91 {
92 char mod = 0;
93 if (itFmt != endFmt)
94 {
95 switch (*itFmt)
96 {
97 case 'l':
98 case 'h':
99 case 'L':
100 case '?': mod = *itFmt++; break;
101 }
102 }
103 return mod;
104 }
105
106 std::size_t parseIndex(std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt)
107 {
108 int index = 0;
109 while (itFmt != endFmt && Ascii::isDigit(*itFmt))
110 {
111 index = 10*index + *itFmt - '0';
112 ++itFmt;
113 }
114 if (itFmt != endFmt && *itFmt == ']') ++itFmt;
115 return index;
116 }
117
118 void prepareFormat(std::ostream& str, char type)
119 {
120 switch (type)
121 {
122 case 'd':
123 case 'i': str << std::dec; break;
124 case 'o': str << std::oct; break;
125 case 'x': str << std::hex; break;
126 case 'X': str << std::hex << std::uppercase; break;
127 case 'e': str << std::scientific; break;
128 case 'E': str << std::scientific << std::uppercase; break;
129 case 'f': str << std::fixed; break;
130 }
131 }
132
133
134 void writeAnyInt(std::ostream& str, const Any& any)
135 {
136 if (any.type() == typeid(char))
137 str << static_cast<int>(AnyCast<char>(any));
138 else if (any.type() == typeid(signed char))
139 str << static_cast<int>(AnyCast<signed char>(any));
140 else if (any.type() == typeid(unsigned char))
141 str << static_cast<unsigned>(AnyCast<unsigned char>(any));
142 else if (any.type() == typeid(short))
143 str << AnyCast<short>(any);
144 else if (any.type() == typeid(unsigned short))
145 str << AnyCast<unsigned short>(any);
146 else if (any.type() == typeid(int))
147 str << AnyCast<int>(any);
148 else if (any.type() == typeid(unsigned int))
149 str << AnyCast<unsigned int>(any);
150 else if (any.type() == typeid(long))
151 str << AnyCast<long>(any);
152 else if (any.type() == typeid(unsigned long))
153 str << AnyCast<unsigned long>(any);
154 else if (any.type() == typeid(Int64))
155 str << AnyCast<Int64>(any);
156 else if (any.type() == typeid(UInt64))
157 str << AnyCast<UInt64>(any);
158 else if (any.type() == typeid(bool))
159 str << AnyCast<bool>(any);
160 }
161
162
163 void formatOne(std::string& result, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt, std::vector<Any>::const_iterator& itVal)
164 {
165 std::ostringstream str;
166#if !defined(POCO_NO_LOCALE)
167 str.imbue(std::locale::classic());
168#endif
169 try
170 {
171 parseFlags(str, itFmt, endFmt);
172 parseWidth(str, itFmt, endFmt, itVal);
173 parsePrec(str, itFmt, endFmt, itVal);
174 char mod = parseMod(itFmt, endFmt);
175 if (itFmt != endFmt)
176 {
177 char type = *itFmt++;
178 prepareFormat(str, type);
179 switch (type)
180 {
181 case 'b':
182 str << AnyCast<bool>(*itVal++);
183 break;
184 case 'c':
185 str << AnyCast<char>(*itVal++);
186 break;
187 case 'd':
188 case 'i':
189 switch (mod)
190 {
191 case 'l': str << AnyCast<long>(*itVal++); break;
192 case 'L': str << AnyCast<Int64>(*itVal++); break;
193 case 'h': str << AnyCast<short>(*itVal++); break;
194 case '?': writeAnyInt(str, *itVal++); break;
195 default: str << AnyCast<int>(*itVal++); break;
196 }
197 break;
198 case 'o':
199 case 'u':
200 case 'x':
201 case 'X':
202 switch (mod)
203 {
204 case 'l': str << AnyCast<unsigned long>(*itVal++); break;
205 case 'L': str << AnyCast<UInt64>(*itVal++); break;
206 case 'h': str << AnyCast<unsigned short>(*itVal++); break;
207 case '?': writeAnyInt(str, *itVal++); break;
208 default: str << AnyCast<unsigned>(*itVal++); break;
209 }
210 break;
211 case 'e':
212 case 'E':
213 case 'f':
214 switch (mod)
215 {
216 case 'l': str << AnyCast<long double>(*itVal++); break;
217 case 'L': str << AnyCast<long double>(*itVal++); break;
218 case 'h': str << AnyCast<float>(*itVal++); break;
219 default: str << AnyCast<double>(*itVal++); break;
220 }
221 break;
222 case 's':
223 str << RefAnyCast<std::string>(*itVal++);
224 break;
225 case 'z':
226 str << AnyCast<std::size_t>(*itVal++);
227 break;
228 case 'I':
229 case 'D':
230 default:
231 str << type;
232 }
233 }
234 }
235 catch (Poco::BadCastException&)
236 {
237 str << "[ERRFMT]";
238 }
239 result.append(str.str());
240 }
241}
242
243
244std::string format(const std::string& fmt, const Any& value) {
245 std::string result;
246 format(result, fmt, value);
247 return result;
248}
249
250
251void format(std::string& result, const char *fmt, const std::vector<Any>& values)
252{
253 format(result, std::string(fmt), values);
254}
255
256
257void format(std::string& result, const std::string& fmt, const std::vector<Any>& values)
258{
259 std::string::const_iterator itFmt = fmt.begin();
260 std::string::const_iterator endFmt = fmt.end();
261 std::vector<Any>::const_iterator itVal = values.begin();
262 std::vector<Any>::const_iterator endVal = values.end();
263 while (itFmt != endFmt)
264 {
265 switch (*itFmt)
266 {
267 case '%':
268 ++itFmt;
269 if (itFmt != endFmt && (itVal != endVal || *itFmt == '['))
270 {
271 if (*itFmt == '[')
272 {
273 ++itFmt;
274 std::size_t index = parseIndex(itFmt, endFmt);
275 if (index < values.size())
276 {
277 std::vector<Any>::const_iterator it = values.begin() + index;
278 formatOne(result, itFmt, endFmt, it);
279 }
280 else throw InvalidArgumentException("format argument index out of range", fmt);
281 }
282 else
283 {
284 formatOne(result, itFmt, endFmt, itVal);
285 }
286 }
287 else if (itFmt != endFmt)
288 {
289 result += *itFmt++;
290 }
291 break;
292 default:
293 result += *itFmt;
294 ++itFmt;
295 }
296 }
297}
298
299
300} // namespace Poco
301