2 // This file is part of the aMule Project.
4 // Copyright (c) 2005-2008 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
33 #if defined HAVE_STDINT_H
35 #elif defined HAVE_INTTYPES_H
36 # include <inttypes.h>
40 //! Known type-modifiers.
43 //! No modifier field.
45 //! Argument is interpreted as short int (integer types).
47 //! Argument is interpreted as long int (integer types).
49 //! Two 'long' modifieres, arguments is interpreted as long long (integer types).
51 //! Argument is interpreted as long double (floating point types). Not supported.
57 * Extracts modifiers from the argument.
59 * Note that this function will possibly return wrong results
60 * for malformed format strings.
62 Modifiers
getModifier(const wxString
& str
)
64 switch ( (wxChar
)str
[str
.Len() - 2]) {
65 case wxT('h'): // short int (integer types).
67 case wxT('l'): // long int (interger types) or double (floating point types).
68 if ( str
.Len() > 3 && str
.GetChar( str
.Len() - 3 ) == wxT('l') ) {
73 case wxT('L'): // long double (floating point types).
81 /** Returns true if the char is a format-type. */
82 bool isTypeChar(wxChar c
)
85 case wxT('s'): // String of characters
86 case wxT('u'): // Unsigned decimal integer
87 case wxT('i'): // Signed decimal integer
88 case wxT('d'): // Signed decimal integer
89 case wxT('c'): // Character
90 case wxT('f'): // Decimal floating point
91 case wxT('F'): // Decimal floating point
92 case wxT('x'): // Unsigned hexadecimal integer
93 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
94 case wxT('o'): // Unsigned octal
95 case wxT('e'): // Scientific notation (mantise/exponent) using e character
96 case wxT('E'): // Scientific notation (mantise/exponent) using E character
97 case wxT('g'): // Use shorter %e or %f
98 case wxT('G'): // Use shorter %E or %f
99 case wxT('p'): // Not supported, still needs to be caught though
100 case wxT('n'): // Not supported, still needs to be caught though
107 /** Returns true if the char is a valid flag. */
108 bool isFlagChar(wxChar c
)
111 case wxT('+'): // Include sign for integers
112 case wxT('-'): // Left-align output
113 case wxT('#'): // Alternate form, varies
114 case wxT(' '): // Pad with spaces
115 case wxT('0'): // Pad with zeros
122 /** Returns true if the char is an integer (for width + precision). */
123 bool isIntChar(wxChar c
)
125 return ((c
>= wxT('0')) && (c
<= wxT('9')));
129 /** Returns true if the char is a valid length modifier. */
130 bool isLengthChar(wxChar c
)
133 case wxT('h'): // Short ('hh') and char ('h')
134 case wxT('l'): // Long ('l') and long long ('ll')
135 case wxT('L'): // Double long
136 case wxT('z'): // size_t
137 case wxT('j'): // intmax_t
138 case wxT('t'): // ptrdiff_t
142 // Catches widths, precisons and zero-padding
143 return (c
>= wxT('0')) && (c
<= wxT('9'));
147 CFormat::CFormat(const wxChar
* str
)
154 if (m_format
.Length()) {
155 SetCurrentField(wxEmptyString
);
160 CFormat::CFormat(const wxString
& str
)
167 if (m_format
.Length()) {
168 SetCurrentField(wxEmptyString
);
173 bool CFormat::IsReady() const
175 return (m_fieldStart
== m_format
.Length());
179 wxString
CFormat::GetString() const
184 wxFAIL_MSG(wxT("Called GetString() before all values were passed: ") + m_format
);
186 // Return as much as possible ...
187 return m_result
+ m_format
.Mid(m_fieldStart
);
192 void CFormat::SetCurrentField(const wxString
& value
)
194 wxCHECK_RET(m_fieldStart
< m_format
.Length(),
195 wxT("Setting field in already completed string: ") + m_format
);
197 if (value
.Length()) {
211 // Format strings are expected to follow the folllowing structure:
212 // %[Flags][Width][.Precision][Length]<Type>
213 for (size_t i
= m_fieldStart
+ m_fieldLength
; i
< m_format
.Length(); ++i
) {
214 const wxChar c
= m_format
[i
];
216 if (pos
>= PosStart
) {
219 if ((pos
<= PosFlags
) && isFlagChar(c
)) {
221 } else if ((pos
<= PosWidth
) && isIntChar(c
)) {
223 } else if ((pos
< PosPrecision
) && (c
== wxT('.'))) {
225 } else if ((pos
== PosPrecision
) && isIntChar(c
)) {
227 } else if ((pos
< PosLength
) && isLengthChar(c
)) {
229 } else if ((pos
== PosLength
) && isLengthChar(c
) && (c
== m_format
[i
- 1])) {
231 } else if ((pos
<= PosLength
) && isTypeChar(c
)) {
234 } else if ((pos
<= PosLength
) && (c
== wxT('%'))) {
235 // Append the %*% to the result
236 m_result
+= wxT("%");
240 // Field is broken ...
243 } else if (c
== wxT('%')) {
244 const size_t offset
= m_fieldStart
+ m_fieldLength
;
245 // If there was anything before this, then prepend it.
247 m_result
+= m_format
.Mid(offset
, i
- offset
);
250 // Starting a new format string
255 // Normal text, nothing to do ...
259 if (pos
== PosNone
) {
261 m_result
+= m_format
.Mid(m_fieldStart
+ m_fieldLength
);
263 m_fieldStart
= m_fieldLength
= m_format
.Length();
264 } else if (pos
!= PosEnd
) {
265 // A partial field was found ...
266 wxFAIL_MSG(wxT("Invalid field in format string: ") + m_format
);
267 wxASSERT_MSG(m_fieldStart
+ m_fieldLength
<= m_format
.Length(),
268 wxT("Invalid field-start/length in format string: ") + m_format
);
270 // Prepend the parsed part of the format-string
271 m_result
+= m_format
.Mid(m_fieldStart
, m_fieldLength
);
273 // Return an empty string the next time GetCurrentField is called
276 // Anything left to do?
278 // Find the next format string
279 SetCurrentField(wxEmptyString
);
285 wxString
CFormat::GetCurrentField()
287 wxCHECK_MSG(m_fieldStart
< m_format
.Length(), wxEmptyString
,
288 wxT("Passing argument to already completed string: ") + m_format
);
289 wxASSERT_MSG(m_fieldStart
+ m_fieldLength
<= m_format
.Length(),
290 wxT("Invalid field-start/length in format string: ") + m_format
);
293 // The current field was invalid, so we skip it.
296 return wxEmptyString
;
299 return m_format
.Mid(m_fieldStart
, m_fieldLength
);
303 wxString
CFormat::GetIntegerField(const wxChar
* fieldType
)
305 const wxString field
= GetCurrentField();
306 if (field
.IsEmpty()) {
307 // Invalid or missing field ...
311 // Drop type and length
312 wxString newField
= field
;
313 while (isalpha(newField
.Last())) {
314 newField
.RemoveLast();
317 // Set the correct integer type
318 newField
+= fieldType
;
320 switch ((wxChar
)field
.Last()) {
321 case wxT('o'): // Unsigned octal
322 case wxT('x'): // Unsigned hexadecimal integer
323 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
324 // Override the default type
325 newField
.Last() = field
.Last();
327 case wxT('d'): // Signed decimal integer
328 case wxT('i'): // Signed decimal integer
329 case wxT('u'): // Unsigned decimal integer
333 wxFAIL_MSG(wxT("Integer value passed to non-integer format string: ") + m_format
);
334 SetCurrentField(field
);
335 return wxEmptyString
;
340 CFormat
& CFormat::operator%(double value
)
342 wxString field
= GetCurrentField();
343 if (field
.IsEmpty()) {
347 switch ( (wxChar
)field
.Last() ) {
348 case wxT('e'): // Scientific notation (mantise/exponent) using e character
349 case wxT('E'): // Scientific notation (mantise/exponent) using E character
350 case wxT('f'): // Decimal floating point
351 case wxT('F'): // Decimal floating point
352 case wxT('g'): // Use shorter %e or %f
353 case wxT('G'): // Use shorter %E or %f
354 wxASSERT_MSG(getModifier(field
) == modNone
, wxT("Invalid modifier specified for floating-point format: ") + m_format
);
356 SetCurrentField(wxString::Format(field
, value
));
360 wxFAIL_MSG(wxT("Floating-point value passed to non-float format string: ") + m_format
);
361 SetCurrentField(field
);
368 CFormat
& CFormat::operator%(wxChar value
)
370 wxString field
= GetCurrentField();
372 if (field
.IsEmpty()) {
373 // We've already asserted in GetCurrentField.
374 } else if (field
.Last() != wxT('c')) {
375 wxFAIL_MSG(wxT("Char value passed to non-char format string: ") + m_format
);
376 SetCurrentField(field
);
378 SetCurrentField(wxString::Format(field
, value
));
385 CFormat
& CFormat::operator%(signed long long value
)
387 wxString field
= GetIntegerField(WXLONGLONGFMTSPEC
wxT("i"));
388 if (!field
.IsEmpty()) {
389 SetCurrentField(wxString::Format(field
, value
));
396 CFormat
& CFormat::operator%(unsigned long long value
)
398 wxString field
= GetIntegerField(WXLONGLONGFMTSPEC
wxT("u"));
399 if (!field
.IsEmpty()) {
400 SetCurrentField(wxString::Format(field
, value
));
407 CFormat
& CFormat::operator%(const wxString
& val
)
409 wxString field
= GetCurrentField();
411 if (field
.IsEmpty()) {
412 // We've already asserted in GetCurrentField
413 } else if (field
.Last() != wxT('s')) {
414 wxFAIL_MSG(wxT("String value passed to non-string format string:") + m_format
);
415 SetCurrentField(field
);
416 } else if (field
.GetChar(1) == wxT('.')) {
417 // A max-length is specified
418 wxString size
= field
.Mid( 2, field
.Len() - 3 );
421 // Try to convert the length-field.
422 if ((size
.IsEmpty() || size
.ToLong(&lSize
)) && (lSize
>= 0)) {
423 SetCurrentField(val
.Left(lSize
));
425 wxFAIL_MSG(wxT("Invalid value found in 'precision' field: ") + m_format
);
426 SetCurrentField(field
);
428 } else if (field
.GetChar(1) == wxT('s')) {
429 // No limit on size, just set the string
430 SetCurrentField(val
);
432 SetCurrentField(field
);
433 wxFAIL_MSG(wxT("Malformed string format field: ") + m_format
);
439 CFormat
& CFormat::operator%(void * value
)
441 wxString field
= GetCurrentField();
443 if (field
.IsEmpty()) {
444 // We've already asserted in GetCurrentField.
445 } else if (field
.Last() != wxT('p')) {
446 wxFAIL_MSG(wxT("Pointer value passed to non-pointer format string: ") + m_format
);
447 SetCurrentField(field
);
448 } else if (field
!= wxT("%p")) {
449 wxFAIL_MSG(wxT("Modifiers are not allowed for pointer format string: ") + m_format
);
450 SetCurrentField(field
);
452 // built-in Format for pointer is not optimal:
453 // - Windows: uppercase, no leading 0x
454 // - Linux: leading zeros missing
455 // -> format it as hex
456 if (sizeof (void *) == 8) { // 64 bit
457 SetCurrentField(wxString::Format(wxT("0x%016x"), (uintptr_t) value
));
459 SetCurrentField(wxString::Format(wxT("0x%08x"), (uintptr_t) value
));
466 // File_checked_for_headers