Whitespace
[amule.git] / src / libs / common / Format.cpp
blob433567efc1a101f638f77b087875e155d264512e
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 //
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
8 // respective authors.
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "Format.h"
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #if defined HAVE_STDINT_H
32 # include <stdint.h>
33 #elif defined HAVE_INTTYPES_H
34 # include <inttypes.h>
35 #endif
37 #include <wx/intl.h> // Needed for _()
39 #include <errno.h> // Needed for errno and EINVAL
40 #include "strerror_r.h" // Needed for mule_strerror_r()
42 /** Returns true if the char is a format-type. */
43 inline bool isTypeChar(wxChar c)
45 switch (c) {
46 case wxT('s'): // String of characters
47 case wxT('u'): // Unsigned decimal integer
48 case wxT('i'): // Signed decimal integer
49 case wxT('d'): // Signed decimal integer
50 case wxT('c'): // Character
51 case wxT('f'): // Decimal floating point
52 case wxT('F'): // Decimal floating point
53 case wxT('x'): // Unsigned hexadecimal integer
54 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
55 case wxT('o'): // Unsigned octal
56 case wxT('e'): // Scientific notation (mantise/exponent) using e character
57 case wxT('E'): // Scientific notation (mantise/exponent) using E character
58 case wxT('g'): // Use shorter %e or %f
59 case wxT('G'): // Use shorter %E or %F
60 case wxT('p'): // Pointer
61 case wxT('n'): // Not supported, still needs to be caught though
62 case wxT('a'): // (C99; not in SUSv2) Double in hexadecimal notation.
63 case wxT('A'): // (C99; not in SUSv2) Double in hexadecimal notation (capital letters).
64 case wxT('C'): // (Not in C99, but in SUSv2.) Synonym for lc. Don't use. Not supported.
65 case wxT('S'): // (Not in C99, but in SUSv2.) Synonym for ls. Don't use. Not supported.
66 case wxT('m'): // (Glibc extension.) Print output of strerror(errno). No argument is required.
67 // case wxT('%'): // A `%' is written. No argument is converted. The complete conversion specification is `%%'.
68 return true;
71 return false;
74 /** Returns true if the char is a valid flag. */
75 inline bool isFlagChar(wxChar c)
77 switch (c) {
78 // C standard flags
79 case wxT('+'): // Include sign for integers
80 case wxT('-'): // Left-align output
81 case wxT('#'): // Alternate form, varies
82 case wxT(' '): // Pad with spaces
83 case wxT('0'): // Pad with zeros
84 // SUSv2
85 case wxT('\''): // For decimal conversion (i, d, u, f, F, g, G) the output is to be grouped with thousands' grouping characters if the locale information indicates any.
86 // glibc 2.2
87 case wxT('I'): // For decimal integer conversion (i, d, u) the output uses the locale's alternative output digits, if any.
88 return true;
91 return false;
94 /** Returns true if the char is a valid length modifier. */
95 inline bool isLengthChar(wxChar c)
97 switch (c) {
98 case wxT('h'): // Short ('hh') and char ('h')
99 case wxT('l'): // Long ('l') and long long ('ll')
100 case wxT('L'): // Double long
101 case wxT('z'): // size_t
102 case wxT('j'): // intmax_t
103 case wxT('t'): // ptrdiff_t
104 case wxT('q'): // quad. Synonym for 'll'. Don't use.
105 return true;
108 return false;
111 /** Returns true if the argument is a valid length modifier */
112 inline bool isValidLength(const wxString& str)
114 return ((str == wxT("hh")) || (str == wxT("h")) ||
115 (str == wxT("l")) || (str == wxT("ll")) ||
116 (str == wxT("L")) || (str == wxT("z")) ||
117 (str == wxT("j")) || (str == wxT("t")) ||
118 (str == wxT("q")));
122 enum eStringParserStates {
123 esNonFormat = 0, // Not in a format string
124 esFormatStart, // Start of a format string
125 esFormat, // Inside a format string
126 esFormatEnd, // Finished reading a format string
127 esInvalidFormat // Invalid (incomplete) format specifier
131 * State machine to extract format specifiers from the string
133 * All format strings will be extracted, regardless whether they are valid or
134 * not. Also '%%' is considered to be special format string which requires no
135 * arguments, thus it will be extracted too (that is because it has to be
136 * converted to '%').
138 static eStringParserStates stringParser[][3] = {
139 /* %-sign, type-char, other */
140 /* esNonFormat */ { esFormatStart, esNonFormat, esNonFormat },
141 /* esFormatStart */ { esFormatEnd, esFormatEnd, esFormat },
142 /* esFormat */ { esInvalidFormat, esFormatEnd, esFormat },
143 /* esFormatEnd */ { esFormatStart, esNonFormat, esNonFormat },
144 /* esInvalidFormat */ { esFormatEnd, esFormatEnd, esFormat }
147 enum eFormatParserStates {
148 efStart = 0, // Format string start
149 efArgIndex, // Argument index
150 efArgIndexEnd, // End of the argument index ('$' sign)
151 efFlagChar, // Flag character
152 efWidth, // Width field
153 efPrecStart, // Precision field start ('.' character)
154 efPrecision, // Precision field
155 efLength, // Length field
156 // The following two are terminal states, they terminate processing
157 efType, // Type character
158 efError // Invalid format specifier
162 * State machine to parse format specifiers
164 * Format specifiers are expected to follow the following structure:
165 * %[argIndex$][Flags][Width][.Precision][Length]<Type>
167 static eFormatParserStates formatParser[][7] = {
168 /* [1-9], '0', flagChar, '.', lengthChar, typeChar, '$' */
169 /* efStart */ { efArgIndex, efFlagChar, efFlagChar, efPrecStart, efLength, efType, efError, },
170 /* efArgIndex */ { efArgIndex, efArgIndex, efError, efPrecStart, efLength, efType, efArgIndexEnd, },
171 /* efArgIndexEnd */ { efWidth, efFlagChar, efFlagChar, efPrecStart, efLength, efType, efError, },
172 /* efFlagChar */ { efWidth, efError, efError, efPrecStart, efLength, efType, efError, },
173 /* efWidth */ { efWidth, efWidth, efError, efPrecStart, efLength, efType, efError, },
174 /* efPrecStart */ { efPrecision, efPrecision, efError, efError, efLength, efType, efError, },
175 /* efPrecision */ { efPrecision, efPrecision, efError, efError, efLength, efType, efError, },
176 /* efLength */ { efError, efError, efError, efError, efLength, efType, efError, }
179 // Forward-declare the specialization for const wxString&, needed by the parser
180 template<> void CFormat::ProcessArgument(FormatList::iterator, const wxString&);
182 void CFormat::Init(const wxString& str)
184 m_formatString = str;
185 m_argIndex = 0;
187 // Extract format-string-like substrings from the input
189 size_t formatStart = 0;
190 eStringParserStates state = esNonFormat;
191 for (size_t pos = 0; pos < str.length(); ++pos) {
192 if (str[pos] == wxT('%')) {
193 state = stringParser[state][0];
194 } else if (isTypeChar(str[pos])) {
195 state = stringParser[state][1];
196 } else {
197 state = stringParser[state][2];
199 switch (state) {
200 case esInvalidFormat:
201 wxFAIL_MSG(wxT("Invalid format specifier: ") + str.Mid(formatStart, pos - formatStart + 1));
202 case esFormatStart:
203 formatStart = pos;
204 break;
205 case esFormatEnd:
207 FormatSpecifier fs;
208 fs.startPos = formatStart;
209 fs.endPos = pos;
210 fs.result = str.Mid(formatStart, pos - formatStart + 1);
211 m_formats.push_back(fs);
213 default:
214 break;
217 wxASSERT_MSG((state == esFormatEnd) || (state == esNonFormat), wxT("Incomplete format specifier: ") + str.Mid(formatStart));
220 // Parse the extracted format specifiers, removing invalid ones
221 unsigned formatCount = 0;
222 for (FormatList::iterator it = m_formats.begin(); it != m_formats.end();) {
223 if (it->result == wxT("%%")) {
224 it->argIndex = 0;
225 it->result = wxT("%");
226 ++it;
227 } else {
228 it->argIndex = ++formatCount;
229 it->flag = '\0';
230 it->width = 0;
231 it->precision = -1;
232 it->type = '\0';
233 unsigned num = 0;
234 wxString lengthModifier;
235 bool isPrecision = false;
236 eFormatParserStates state = efStart;
237 for (size_t pos = 1; pos < it->result.length(); ++pos) {
238 wxChar c = it->result[pos];
239 if ((c >= wxT('1')) && (c <= wxT('9'))) {
240 state = formatParser[state][0];
241 } else if (c == wxT('0')) {
242 state = formatParser[state][1];
243 } else if (isFlagChar(c)) {
244 state = formatParser[state][2];
245 } else if (c == wxT('.')) {
246 state = formatParser[state][3];
247 } else if (isLengthChar(c)) {
248 state = formatParser[state][4];
249 } else if (isTypeChar(c)) {
250 state = formatParser[state][5];
251 } else if (c == wxT('$')) {
252 state = formatParser[state][6];
253 } else {
254 state = efError;
256 if ((c >= wxT('0')) && (c <= wxT('9'))) {
257 num *= 10;
258 num += (c - wxT('0'));
260 switch (state) {
261 case efArgIndexEnd:
262 it->argIndex = num;
263 num = 0;
264 break;
265 case efFlagChar:
266 it->flag = c;
267 break;
268 case efPrecStart:
269 it->width = num;
270 num = 0;
271 isPrecision = true;
272 break;
273 case efLength:
274 if (isPrecision) {
275 it->precision = num;
276 } else if (num > 0) {
277 it->width = num;
279 num = 0;
280 lengthModifier += c;
281 if (!isValidLength(lengthModifier)) {
282 state = efError;
284 break;
285 case efType:
286 if (isPrecision) {
287 it->precision = num;
288 } else if (num > 0) {
289 it->width = num;
291 if (c == wxT('m')) {
292 it->argIndex = 0;
293 it->type = wxT('s');
294 int errnum = errno;
295 #if defined(HAVE_STRERROR) || defined(HAVE_STRERROR_R)
296 unsigned buflen = 256;
297 bool done = false;
298 do {
299 errno = 0;
300 char* buf = new char[buflen];
301 *buf = '\0';
302 int result = mule_strerror_r(errnum, buf, buflen);
303 if ((result == 0) || (buflen > 1024)) {
304 ProcessArgument<const wxString&>(it, wxString(buf, wxConvLocal));
305 } else if (errno == EINVAL) {
306 if (*buf == '\0') {
307 ProcessArgument<const wxString&>(it, wxString::Format(_("Unknown error %d"), errnum));
308 } else {
309 ProcessArgument<const wxString&>(it, wxString(buf, wxConvLocal));
311 } else if (errno != ERANGE) {
312 ProcessArgument<const wxString&>(it, wxString::Format(_("Unable to get error description for error %d"), errnum));
313 } else {
314 buflen <<= 1;
316 delete [] buf;
317 done = ((result == 0) || (errno != ERANGE));
318 } while (!done);
319 #else
320 wxFAIL_MSG(wxString::Format(wxT("Unable to get error description for error %d."), errnum));
321 ProcessArgument<const wxString&>(it, wxString::Format(_("Unable to get error description for error %d"), errnum));
322 #endif
323 } else {
324 it->type = c;
326 default:
327 break;
329 wxCHECK2_MSG(state != efError, break, wxT("Invalid format specifier: ") + it->result);
330 if (state == efType) {
331 // Needed by the '%m' conversion, which takes place immediately,
332 // overwriting it->result
333 break;
336 if (state == efError) {
337 it = m_formats.erase(it);
338 --formatCount;
339 } else {
340 ++it;
346 wxString CFormat::GetString() const
348 wxString result;
349 FormatList::const_iterator it = m_formats.begin();
350 if (it == m_formats.end()) {
351 result = m_formatString;
352 } else {
353 unsigned lastEnd = 0;
354 for (; it != m_formats.end(); ++it) {
355 result += m_formatString.Mid(lastEnd, it->startPos - lastEnd);
356 result += it->result;
357 lastEnd = it->endPos + 1;
359 result += m_formatString.Mid(lastEnd);
361 return result;
364 wxString CFormat::GetModifiers(FormatList::const_iterator it) const
366 wxString result = wxT("%");
367 if (it->flag != wxT('\0')) {
368 result += it->flag;
370 if (it->width > 0) {
371 result += wxString::Format(wxT("%u"), it->width);
373 if (it->precision >= 0) {
374 result += wxString::Format(wxT(".%u"), it->precision);
376 return result;
379 // Forward-declare the specialization for unsigned long long
380 template<> void CFormat::ProcessArgument(FormatList::iterator, unsigned long long);
382 // Processing a double-precision floating-point argument
383 template<>
384 void CFormat::ProcessArgument(FormatList::iterator it, double value)
386 switch (it->type) {
387 case wxT('a'):
388 case wxT('A'):
389 case wxT('e'):
390 case wxT('E'):
391 case wxT('f'):
392 case wxT('F'):
393 case wxT('g'):
394 case wxT('G'):
395 break;
396 case wxT('s'):
397 it->type = wxT('g');
398 break;
399 default:
400 wxFAIL_MSG(wxT("Floating-point value passed for non-floating-point format field: ") + it->result);
401 return;
403 it->result = wxString::Format(GetModifiers(it) + it->type, value);
406 // Processing a wxChar argument
407 template<>
408 void CFormat::ProcessArgument(FormatList::iterator it, wxChar value)
410 switch (it->type) {
411 case wxT('c'):
412 break;
413 case wxT('s'):
414 it->type = wxT('c');
415 break;
416 case wxT('u'):
417 case wxT('d'):
418 case wxT('i'):
419 case wxT('o'):
420 case wxT('x'):
421 case wxT('X'):
422 ProcessArgument(it, (unsigned long long)value);
423 return;
424 case wxT('a'):
425 case wxT('A'):
426 case wxT('e'):
427 case wxT('E'):
428 case wxT('f'):
429 case wxT('F'):
430 case wxT('g'):
431 case wxT('G'):
432 ProcessArgument(it, (double)value);
433 return;
434 default:
435 wxFAIL_MSG(wxT("Character value passed to non-character format field: ") + it->result);
436 return;
438 it->result = wxString::Format(GetModifiers(it) + it->type, value);
441 // Processing a signed long long argument
442 template<>
443 void CFormat::ProcessArgument(FormatList::iterator it, signed long long value)
445 switch (it->type) {
446 case wxT('c'):
447 ProcessArgument(it, (wxChar)value);
448 return;
449 case wxT('i'):
450 break;
451 case wxT('o'):
452 case wxT('x'):
453 case wxT('X'):
454 ProcessArgument(it, (unsigned long long)value);
455 return;
456 case wxT('u'):
457 case wxT('d'):
458 case wxT('s'):
459 it->type = wxT('i');
460 break;
461 case wxT('a'):
462 case wxT('A'):
463 case wxT('e'):
464 case wxT('E'):
465 case wxT('f'):
466 case wxT('F'):
467 case wxT('g'):
468 case wxT('G'):
469 ProcessArgument(it, (double)value);
470 return;
471 default:
472 wxFAIL_MSG(wxT("Integer value passed for non-integer format field: ") + it->result);
473 return;
475 it->result = wxString::Format(GetModifiers(it) + WXLONGLONGFMTSPEC + it->type, value);
478 // Processing an unsigned long long argument
479 template<>
480 void CFormat::ProcessArgument(FormatList::iterator it, unsigned long long value)
482 switch (it->type) {
483 case wxT('c'):
484 ProcessArgument(it, (wxChar)value);
485 return;
486 case wxT('u'):
487 case wxT('o'):
488 case wxT('x'):
489 case wxT('X'):
490 break;
491 case wxT('i'):
492 case wxT('d'):
493 case wxT('s'):
494 it->type = wxT('u');
495 break;
496 case wxT('a'):
497 case wxT('A'):
498 case wxT('e'):
499 case wxT('E'):
500 case wxT('f'):
501 case wxT('F'):
502 case wxT('g'):
503 case wxT('G'):
504 ProcessArgument(it, (double)value);
505 return;
506 default:
507 wxFAIL_MSG(wxT("Integer value passed for non-integer format field: ") + it->result);
508 return;
510 it->result = wxString::Format(GetModifiers(it) + WXLONGLONGFMTSPEC + it->type, value);
513 // Processing a wxString argument
514 template<>
515 void CFormat::ProcessArgument(FormatList::iterator it, const wxString& value)
517 if (it->type != wxT('s')) {
518 wxFAIL_MSG(wxT("String value passed for non-string format field: ") + it->result);
519 } else {
520 if (it->precision >= 0) {
521 it->result = value.Left(it->precision);
522 } else {
523 it->result = value;
525 if ((it->width > 0) && (it->result.length() < it->width)) {
526 if (it->flag == wxT('-')) {
527 it->result += wxString(it->width - it->result.length(), wxT(' '));
528 } else {
529 it->result = wxString(it->width -it->result.length(), wxT(' ')) + it->result;
535 // Processing pointer arguments
536 template<>
537 void CFormat::ProcessArgument(FormatList::iterator it, void * value)
539 if ((it->type == wxT('p')) || (it->type == wxT('s'))) {
540 // Modifiers (if any) are ignored for pointer conversions
541 // built-in Format for pointer is not consistent:
542 // - Windows: uppercase, no leading 0x
543 // - Linux: leading zeros missing
544 // -> format it as hex
545 if (sizeof(void*) == 8) {
546 // 64 bit
547 it->result = wxString::Format(wxString(wxT("0x%016")) + WXLONGLONGFMTSPEC + wxT("x"), (uintptr_t)value);
548 } else {
549 // 32 bit
550 it->result = wxString::Format(wxT("0x%08x"), (uintptr_t)value);
552 } else {
553 wxFAIL_MSG(wxT("Pointer value passed for non-pointer format field: ") + it->result);
558 // Generic argument processor template
559 template<typename _Tp>
560 CFormat& CFormat::operator%(_Tp value)
562 m_argIndex++;
563 for (FormatList::iterator it = m_formats.begin(); it != m_formats.end(); ++it) {
564 if (it->argIndex == m_argIndex) {
565 if ((it->type != wxT('n')) && (it->type != wxT('C')) && (it->type != wxT('S'))) {
566 ProcessArgument<_Tp>(it, value);
567 } else {
568 wxFAIL_MSG(wxT("Not supported conversion type in format field: ") + it->result);
572 return *this;
575 // explicit instatiation for the types we handle
576 template CFormat& CFormat::operator%<double>(double);
577 template CFormat& CFormat::operator%<wxChar>(wxChar);
578 template CFormat& CFormat::operator%<signed long long>(signed long long);
579 template CFormat& CFormat::operator%<unsigned long long>(unsigned long long);
580 template CFormat& CFormat::operator%<const wxString&>(const wxString&);
581 template CFormat& CFormat::operator%<void *>(void *);
583 // File_checked_for_headers