2 // This file is part of the aMule Project.
4 // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org )
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
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
29 #if defined HAVE_STDINT_H
31 #elif defined HAVE_INTTYPES_H
32 # include <inttypes.h>
35 #include <wx/intl.h> // Needed for _()
37 #include <errno.h> // Needed for errno and EINVAL
38 #include "strerror_r.h" // Needed for mule_strerror_r()
40 /** Returns true if the char is a format-type. */
41 inline bool isTypeChar(wxChar c
)
44 case wxT('s'): // String of characters
45 case wxT('u'): // Unsigned decimal integer
46 case wxT('i'): // Signed decimal integer
47 case wxT('d'): // Signed decimal integer
48 case wxT('c'): // Character
49 case wxT('f'): // Decimal floating point
50 case wxT('F'): // Decimal floating point
51 case wxT('x'): // Unsigned hexadecimal integer
52 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
53 case wxT('o'): // Unsigned octal
54 case wxT('e'): // Scientific notation (mantise/exponent) using e character
55 case wxT('E'): // Scientific notation (mantise/exponent) using E character
56 case wxT('g'): // Use shorter %e or %f
57 case wxT('G'): // Use shorter %E or %F
58 case wxT('p'): // Pointer
59 case wxT('n'): // Not supported, still needs to be caught though
60 case wxT('a'): // (C99; not in SUSv2) Double in hexadecimal notation.
61 case wxT('A'): // (C99; not in SUSv2) Double in hexadecimal notation (capital letters).
62 case wxT('C'): // (Not in C99, but in SUSv2.) Synonym for lc. Don't use. Not supported.
63 case wxT('S'): // (Not in C99, but in SUSv2.) Synonym for ls. Don't use. Not supported.
64 case wxT('m'): // (Glibc extension.) Print output of strerror(errno). No argument is required.
65 // case wxT('%'): // A `%' is written. No argument is converted. The complete conversion specification is `%%'.
72 /** Returns true if the char is a valid flag. */
73 inline bool isFlagChar(wxChar c
)
77 case wxT('+'): // Include sign for integers
78 case wxT('-'): // Left-align output
79 case wxT('#'): // Alternate form, varies
80 case wxT(' '): // Pad with spaces
81 case wxT('0'): // Pad with zeros
83 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.
85 case wxT('I'): // For decimal integer conversion (i, d, u) the output uses the locale's alternative output digits, if any.
92 /** Returns true if the char is a valid length modifier. */
93 inline bool isLengthChar(wxChar c
)
96 case wxT('h'): // Short ('hh') and char ('h')
97 case wxT('l'): // Long ('l') and long long ('ll')
98 case wxT('L'): // Double long
99 case wxT('z'): // size_t
100 case wxT('j'): // intmax_t
101 case wxT('t'): // ptrdiff_t
102 case wxT('q'): // quad. Synonym for 'll'. Don't use.
109 /** Returns true if the argument is a valid length modifier */
110 inline bool isValidLength(const wxString
& str
)
112 return ((str
== wxT("hh")) || (str
== wxT("h")) ||
113 (str
== wxT("l")) || (str
== wxT("ll")) ||
114 (str
== wxT("L")) || (str
== wxT("z")) ||
115 (str
== wxT("j")) || (str
== wxT("t")) ||
120 enum eStringParserStates
{
121 esNonFormat
= 0, // Not in a format string
122 esFormatStart
, // Start of a format string
123 esFormat
, // Inside a format string
124 esFormatEnd
, // Finished reading a format string
125 esInvalidFormat
// Invalid (incomplete) format specifier
129 * State machine to extract format specifiers from the string
131 * All format strings will be extracted, regardless whether they are valid or
132 * not. Also '%%' is considered to be special format string which requires no
133 * arguments, thus it will be extracted too (that is because it has to be
136 static eStringParserStates stringParser
[][3] = {
137 /* %-sign, type-char, other */
138 /* esNonFormat */ { esFormatStart
, esNonFormat
, esNonFormat
},
139 /* esFormatStart */ { esFormatEnd
, esFormatEnd
, esFormat
},
140 /* esFormat */ { esInvalidFormat
, esFormatEnd
, esFormat
},
141 /* esFormatEnd */ { esFormatStart
, esNonFormat
, esNonFormat
},
142 /* esInvalidFormat */ { esFormatEnd
, esFormatEnd
, esFormat
}
145 enum eFormatParserStates
{
146 efStart
= 0, // Format string start
147 efArgIndex
, // Argument index
148 efArgIndexEnd
, // End of the argument index ('$' sign)
149 efFlagChar
, // Flag character
150 efWidth
, // Width field
151 efPrecStart
, // Precision field start ('.' character)
152 efPrecision
, // Precision field
153 efLength
, // Length field
154 // The following two are terminal states, they terminate processing
155 efType
, // Type character
156 efError
// Invalid format specifier
160 * State machine to parse format specifiers
162 * Format specifiers are expected to follow the following structure:
163 * %[argIndex$][Flags][Width][.Precision][Length]<Type>
165 static eFormatParserStates formatParser
[][7] = {
166 /* [1-9], '0', flagChar, '.', lengthChar, typeChar, '$' */
167 /* efStart */ { efArgIndex
, efFlagChar
, efFlagChar
, efPrecStart
, efLength
, efType
, efError
, },
168 /* efArgIndex */ { efArgIndex
, efArgIndex
, efError
, efPrecStart
, efLength
, efType
, efArgIndexEnd
, },
169 /* efArgIndexEnd */ { efWidth
, efFlagChar
, efFlagChar
, efPrecStart
, efLength
, efType
, efError
, },
170 /* efFlagChar */ { efWidth
, efError
, efError
, efPrecStart
, efLength
, efType
, efError
, },
171 /* efWidth */ { efWidth
, efWidth
, efError
, efPrecStart
, efLength
, efType
, efError
, },
172 /* efPrecStart */ { efPrecision
, efPrecision
, efError
, efError
, efLength
, efType
, efError
, },
173 /* efPrecision */ { efPrecision
, efPrecision
, efError
, efError
, efLength
, efType
, efError
, },
174 /* efLength */ { efError
, efError
, efError
, efError
, efLength
, efType
, efError
, }
177 // Forward-declare the specialization for const wxString&, needed by the parser
178 template<> void CFormat::ProcessArgument(FormatList::iterator
, const wxString
&);
180 void CFormat::Init(const wxString
& str
)
182 m_formatString
= str
;
185 // Extract format-string-like substrings from the input
187 size_t formatStart
= 0;
188 eStringParserStates state
= esNonFormat
;
189 for (size_t pos
= 0; pos
< str
.length(); ++pos
) {
190 if (str
[pos
] == wxT('%')) {
191 state
= stringParser
[state
][0];
192 } else if (isTypeChar(str
[pos
])) {
193 state
= stringParser
[state
][1];
195 state
= stringParser
[state
][2];
198 case esInvalidFormat
:
199 wxFAIL_MSG(wxT("Invalid format specifier: ") + str
.Mid(formatStart
, pos
- formatStart
+ 1));
207 fs
.startPos
= formatStart
;
209 fs
.result
= str
.Mid(formatStart
, pos
- formatStart
+ 1);
210 m_formats
.push_back(fs
);
216 wxASSERT_MSG((state
== esFormatEnd
) || (state
== esNonFormat
), wxT("Incomplete format specifier: ") + str
.Mid(formatStart
));
219 // Parse the extracted format specifiers, removing invalid ones
220 unsigned formatCount
= 0;
221 for (FormatList::iterator it
= m_formats
.begin(); it
!= m_formats
.end();) {
222 if (it
->result
== wxT("%%")) {
224 it
->result
= wxT("%");
227 it
->argIndex
= ++formatCount
;
233 wxString lengthModifier
;
234 bool isPrecision
= false;
235 eFormatParserStates state
= efStart
;
236 for (size_t pos
= 1; pos
< it
->result
.length(); ++pos
) {
237 wxChar c
= it
->result
[pos
];
238 if ((c
>= wxT('1')) && (c
<= wxT('9'))) {
239 state
= formatParser
[state
][0];
240 } else if (c
== wxT('0')) {
241 state
= formatParser
[state
][1];
242 } else if (isFlagChar(c
)) {
243 state
= formatParser
[state
][2];
244 } else if (c
== wxT('.')) {
245 state
= formatParser
[state
][3];
246 } else if (isLengthChar(c
)) {
247 state
= formatParser
[state
][4];
248 } else if (isTypeChar(c
)) {
249 state
= formatParser
[state
][5];
250 } else if (c
== wxT('$')) {
251 state
= formatParser
[state
][6];
255 if ((c
>= wxT('0')) && (c
<= wxT('9'))) {
257 num
+= (c
- wxT('0'));
275 } else if (num
> 0) {
280 if (!isValidLength(lengthModifier
)) {
287 } else if (num
> 0) {
294 #if defined(HAVE_STRERROR) || defined(HAVE_STRERROR_R)
295 unsigned buflen
= 256;
299 char* buf
= new char[buflen
];
301 int result
= mule_strerror_r(errnum
, buf
, buflen
);
302 if ((result
== 0) || (buflen
> 1024)) {
303 ProcessArgument
<const wxString
&>(it
, wxString(buf
, wxConvLocal
));
304 } else if (errno
== EINVAL
) {
306 ProcessArgument
<const wxString
&>(it
, wxString::Format(_("Unknown error %d"), errnum
));
308 ProcessArgument
<const wxString
&>(it
, wxString(buf
, wxConvLocal
));
310 } else if (errno
!= ERANGE
) {
311 ProcessArgument
<const wxString
&>(it
, wxString::Format(_("Unable to get error description for error %d"), errnum
));
316 done
= ((result
== 0) || (errno
!= ERANGE
));
319 wxFAIL_MSG(wxString::Format(wxT("Unable to get error description for error %d."), errnum
));
320 ProcessArgument
<const wxString
&>(it
, wxString::Format(_("Unable to get error description for error %d"), errnum
));
328 wxCHECK2_MSG(state
!= efError
, break, wxT("Invalid format specifier: ") + it
->result
);
329 if (state
== efType
) {
330 // Needed by the '%m' conversion, which takes place immediately,
331 // overwriting it->result
335 if (state
== efError
) {
336 it
= m_formats
.erase(it
);
345 wxString
CFormat::GetString() const
348 FormatList::const_iterator it
= m_formats
.begin();
349 if (it
== m_formats
.end()) {
350 result
= m_formatString
;
352 unsigned lastEnd
= 0;
353 for (; it
!= m_formats
.end(); ++it
) {
354 result
+= m_formatString
.Mid(lastEnd
, it
->startPos
- lastEnd
);
355 result
+= it
->result
;
356 lastEnd
= it
->endPos
+ 1;
358 result
+= m_formatString
.Mid(lastEnd
);
363 wxString
CFormat::GetModifiers(FormatList::const_iterator it
) const
365 wxString result
= wxT("%");
366 if (it
->flag
!= wxT('\0')) {
370 result
+= wxString::Format(wxT("%u"), it
->width
);
372 if (it
->precision
>= 0) {
373 result
+= wxString::Format(wxT(".%u"), it
->precision
);
378 // Forward-declare the specialization for unsigned long long
379 template<> void CFormat::ProcessArgument(FormatList::iterator
, unsigned long long);
381 // Processing a double-precision floating-point argument
383 void CFormat::ProcessArgument(FormatList::iterator it
, double value
)
399 wxFAIL_MSG(wxT("Floating-point value passed for non-floating-point format field: ") + it
->result
);
402 it
->result
= wxString::Format(GetModifiers(it
) + it
->type
, value
);
405 // Processing a wxChar argument
407 void CFormat::ProcessArgument(FormatList::iterator it
, wxChar value
)
421 ProcessArgument(it
, (unsigned long long)value
);
431 ProcessArgument(it
, (double)value
);
434 wxFAIL_MSG(wxT("Character value passed to non-character format field: ") + it
->result
);
437 it
->result
= wxString::Format(GetModifiers(it
) + it
->type
, value
);
440 // Processing a signed long long argument
442 void CFormat::ProcessArgument(FormatList::iterator it
, signed long long value
)
446 ProcessArgument(it
, (wxChar
)value
);
453 ProcessArgument(it
, (unsigned long long)value
);
468 ProcessArgument(it
, (double)value
);
471 wxFAIL_MSG(wxT("Integer value passed for non-integer format field: ") + it
->result
);
474 it
->result
= wxString::Format(GetModifiers(it
) + WXLONGLONGFMTSPEC
+ it
->type
, value
);
477 // Processing an unsigned long long argument
479 void CFormat::ProcessArgument(FormatList::iterator it
, unsigned long long value
)
483 ProcessArgument(it
, (wxChar
)value
);
503 ProcessArgument(it
, (double)value
);
506 wxFAIL_MSG(wxT("Integer value passed for non-integer format field: ") + it
->result
);
509 it
->result
= wxString::Format(GetModifiers(it
) + WXLONGLONGFMTSPEC
+ it
->type
, value
);
512 // Processing a wxString argument
514 void CFormat::ProcessArgument(FormatList::iterator it
, const wxString
& value
)
516 if (it
->type
!= wxT('s')) {
517 wxFAIL_MSG(wxT("String value passed for non-string format field: ") + it
->result
);
519 if (it
->precision
>= 0) {
520 it
->result
= value
.Left(it
->precision
);
524 if ((it
->width
> 0) && (it
->result
.length() < it
->width
)) {
525 if (it
->flag
== wxT('-')) {
526 it
->result
+= wxString(it
->width
- it
->result
.length(), wxT(' '));
528 it
->result
= wxString(it
->width
-it
->result
.length(), wxT(' ')) + it
->result
;
534 // Processing pointer arguments
536 void CFormat::ProcessArgument(FormatList::iterator it
, void * value
)
538 if ((it
->type
== wxT('p')) || (it
->type
== wxT('s'))) {
539 // Modifiers (if any) are ignored for pointer conversions
540 // built-in Format for pointer is not consistent:
541 // - Windows: uppercase, no leading 0x
542 // - Linux: leading zeros missing
543 // -> format it as hex
544 if (sizeof(void*) == 8) {
546 it
->result
= wxString::Format(wxString(wxT("0x%016")) + WXLONGLONGFMTSPEC
+ wxT("x"), (uintptr_t)value
);
549 it
->result
= wxString::Format(wxT("0x%08x"), (uintptr_t)value
);
552 wxFAIL_MSG(wxT("Pointer value passed for non-pointer format field: ") + it
->result
);
557 // Generic argument processor template
558 template<typename _Tp
>
559 CFormat
& CFormat::operator%(_Tp value
)
562 for (FormatList::iterator it
= m_formats
.begin(); it
!= m_formats
.end(); ++it
) {
563 if (it
->argIndex
== m_argIndex
) {
564 if ((it
->type
!= wxT('n')) && (it
->type
!= wxT('C')) && (it
->type
!= wxT('S'))) {
565 ProcessArgument
<_Tp
>(it
, value
);
567 wxFAIL_MSG(wxT("Not supported conversion type in format field: ") + it
->result
);
574 // explicit instatiation for the types we handle
575 template CFormat
& CFormat::operator%<double>(double);
576 template CFormat
& CFormat::operator%<wxChar
>(wxChar
);
577 template CFormat
& CFormat::operator%<signed long long>(signed long long);
578 template CFormat
& CFormat::operator%<unsigned long long>(unsigned long long);
579 template CFormat
& CFormat::operator%<const wxString
&>(const wxString
&);
580 template CFormat
& CFormat::operator%<void *>(void *);
582 // File_checked_for_headers