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
32 //! Known type-modifiers.
35 //! No modifier field.
37 //! Argument is interpreted as short int (integer types).
39 //! Argument is interpreted as long int (integer types).
41 //! Two 'long' modifieres, arguments is interpreted as long long (integer types).
43 //! Argument is interpreted as long double (floating point types). Not supported.
49 * Extracts modifiers from the argument.
51 * Note that this function will possibly return wrong results
52 * for malformed format strings.
54 Modifiers
getModifier(const wxString
& str
)
56 switch ( (wxChar
)str
[str
.Len() - 2]) {
57 case wxT('h'): // short int (integer types).
59 case wxT('l'): // long int (interger types) or double (floating point types).
60 if ( str
.Len() > 3 && str
.GetChar( str
.Len() - 3 ) == wxT('l') ) {
65 case wxT('L'): // long double (floating point types).
73 /** Returns true if the char is a format-type. */
74 bool isTypeChar(wxChar c
)
77 case wxT('s'): // String of characters
78 case wxT('u'): // Unsigned decimal integer
79 case wxT('i'): // Signed decimal integer
80 case wxT('d'): // Signed decimal integer
81 case wxT('c'): // Character
82 case wxT('f'): // Decimal floating point
83 case wxT('F'): // Decimal floating point
84 case wxT('x'): // Unsigned hexadecimal integer
85 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
86 case wxT('o'): // Unsigned octal
87 case wxT('e'): // Scientific notation (mantise/exponent) using e character
88 case wxT('E'): // Scientific notation (mantise/exponent) using E character
89 case wxT('g'): // Use shorter %e or %f
90 case wxT('G'): // Use shorter %E or %f
91 case wxT('p'): // Not supported, still needs to be caught though
92 case wxT('n'): // Not supported, still needs to be caught though
99 /** Returns true if the char is a valid flag. */
100 bool isFlagChar(wxChar c
)
103 case wxT('+'): // Include sign for integers
104 case wxT('-'): // Left-align output
105 case wxT('#'): // Alternate form, varies
106 case wxT(' '): // Pad with spaces
107 case wxT('0'): // Pad with zeros
114 /** Returns true if the char is an integer (for width + precision). */
115 bool isIntChar(wxChar c
)
117 return ((c
>= wxT('0')) && (c
<= wxT('9')));
121 /** Returns true if the char is a valid length modifier. */
122 bool isLengthChar(wxChar c
)
125 case wxT('h'): // Short ('hh') and char ('h')
126 case wxT('l'): // Long ('l') and long long ('ll')
127 case wxT('L'): // Double long
128 case wxT('z'): // size_t
129 case wxT('j'): // intmax_t
130 case wxT('t'): // ptrdiff_t
134 // Catches widths, precisons and zero-padding
135 return (c
>= wxT('0')) && (c
<= wxT('9'));
139 CFormat::CFormat(const wxChar
* str
)
146 if (m_format
.Length()) {
147 SetCurrentField(wxEmptyString
);
152 bool CFormat::IsReady() const
154 return (m_fieldStart
== m_format
.Length());
158 wxString
CFormat::GetString() const
163 wxFAIL_MSG(wxT("Called GetString() before all values were passed: ") + m_format
);
165 // Return as much as possible ...
166 return m_result
+ m_format
.Mid(m_fieldStart
);
171 void CFormat::SetCurrentField(const wxString
& value
)
173 wxCHECK_RET(m_fieldStart
< m_format
.Length(),
174 wxT("Setting field in already completed string: ") + m_format
);
176 if (value
.Length()) {
190 // Format strings are expected to follow the folllowing structure:
191 // %[Flags][Width][.Precision][Length]<Type>
192 for (size_t i
= m_fieldStart
+ m_fieldLength
; i
< m_format
.Length(); ++i
) {
193 const wxChar c
= m_format
[i
];
195 if (pos
>= PosStart
) {
198 if ((pos
<= PosFlags
) && isFlagChar(c
)) {
200 } else if ((pos
<= PosWidth
) && isIntChar(c
)) {
202 } else if ((pos
< PosPrecision
) && (c
== wxT('.'))) {
204 } else if ((pos
== PosPrecision
) && isIntChar(c
)) {
206 } else if ((pos
< PosLength
) && isLengthChar(c
)) {
208 } else if ((pos
== PosLength
) && isLengthChar(c
) && (c
== m_format
[i
- 1])) {
210 } else if ((pos
<= PosLength
) && isTypeChar(c
)) {
213 } else if ((pos
<= PosLength
) && (c
== wxT('%'))) {
214 // Append the %*% to the result
215 m_result
+= wxT("%");
219 // Field is broken ...
222 } else if (c
== wxT('%')) {
223 const size_t offset
= m_fieldStart
+ m_fieldLength
;
224 // If there was anything before this, then prepend it.
226 m_result
+= m_format
.Mid(offset
, i
- offset
);
229 // Starting a new format string
234 // Normal text, nothing to do ...
238 if (pos
== PosNone
) {
240 m_result
+= m_format
.Mid(m_fieldStart
+ m_fieldLength
);
242 m_fieldStart
= m_fieldLength
= m_format
.Length();
243 } else if (pos
!= PosEnd
) {
244 // A partial field was found ...
245 wxFAIL_MSG(wxT("Invalid field in format string: ") + m_format
);
246 wxASSERT_MSG(m_fieldStart
+ m_fieldLength
<= m_format
.Length(),
247 wxT("Invalid field-start/length in format string: ") + m_format
);
249 // Prepend the parsed part of the format-string
250 m_result
+= m_format
.Mid(m_fieldStart
, m_fieldLength
);
252 // Return an empty string the next time GetCurrentField is called
255 // Anything left to do?
257 // Find the next format string
258 SetCurrentField(wxEmptyString
);
264 wxString
CFormat::GetCurrentField()
266 wxCHECK_MSG(m_fieldStart
< m_format
.Length(), wxEmptyString
,
267 wxT("Passing argument to already completed string: ") + m_format
);
268 wxASSERT_MSG(m_fieldStart
+ m_fieldLength
<= m_format
.Length(),
269 wxT("Invalid field-start/length in format string: ") + m_format
);
272 // The current field was invalid, so we skip it.
275 return wxEmptyString
;
278 return m_format
.Mid(m_fieldStart
, m_fieldLength
);
282 wxString
CFormat::GetIntegerField(const wxChar
* fieldType
)
284 const wxString field
= GetCurrentField();
285 if (field
.IsEmpty()) {
286 // Invalid or missing field ...
290 // Drop type and length
291 wxString newField
= field
;
292 while (isalpha(newField
.Last())) {
293 newField
.RemoveLast();
296 // Set the correct integer type
297 newField
+= fieldType
;
299 switch ((wxChar
)field
.Last()) {
300 case wxT('o'): // Unsigned octal
301 case wxT('x'): // Unsigned hexadecimal integer
302 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
303 // Override the default type
304 newField
.Last() = field
.Last();
306 case wxT('d'): // Signed decimal integer
307 case wxT('i'): // Signed decimal integer
308 case wxT('u'): // Unsigned decimal integer
312 wxFAIL_MSG(wxT("Integer value passed to non-integer format string: ") + m_format
);
313 SetCurrentField(field
);
314 return wxEmptyString
;
319 CFormat
& CFormat::operator%(double value
)
321 wxString field
= GetCurrentField();
322 if (field
.IsEmpty()) {
326 switch ( (wxChar
)field
.Last() ) {
327 case wxT('e'): // Scientific notation (mantise/exponent) using e character
328 case wxT('E'): // Scientific notation (mantise/exponent) using E character
329 case wxT('f'): // Decimal floating point
330 case wxT('F'): // Decimal floating point
331 case wxT('g'): // Use shorter %e or %f
332 case wxT('G'): // Use shorter %E or %f
333 wxASSERT_MSG(getModifier(field
) == modNone
, wxT("Invalid modifier specified for floating-point format: ") + m_format
);
335 SetCurrentField(wxString::Format(field
, value
));
339 wxFAIL_MSG(wxT("Floating-point value passed to non-float format string: ") + m_format
);
340 SetCurrentField(field
);
347 CFormat
& CFormat::operator%(wxChar value
)
349 wxString field
= GetCurrentField();
351 if (field
.IsEmpty()) {
352 // We've already asserted in GetCurrentField.
353 } else if (field
.Last() != wxT('c')) {
354 wxFAIL_MSG(wxT("Char value passed to non-char format string: ") + m_format
);
355 SetCurrentField(field
);
357 SetCurrentField(wxString::Format(field
, value
));
364 CFormat
& CFormat::operator%(signed long long value
)
366 wxString field
= GetIntegerField(wxLongLongFmtSpec
wxT("i"));
367 if (!field
.IsEmpty()) {
368 SetCurrentField(wxString::Format(field
, value
));
375 CFormat
& CFormat::operator%(unsigned long long value
)
377 wxString field
= GetIntegerField(wxLongLongFmtSpec
wxT("u"));
378 if (!field
.IsEmpty()) {
379 SetCurrentField(wxString::Format(field
, value
));
386 CFormat
& CFormat::operator%(const wxString
& val
)
388 wxString field
= GetCurrentField();
390 if (field
.IsEmpty()) {
391 // We've already asserted in GetCurrentField
392 } else if (field
.Last() != wxT('s')) {
393 wxFAIL_MSG(wxT("String value passed to non-string format string:") + m_format
);
394 SetCurrentField(field
);
395 } else if (field
.GetChar(1) == wxT('.')) {
396 // A max-length is specified
397 wxString size
= field
.Mid( 2, field
.Len() - 3 );
400 // Try to convert the length-field.
401 if ((size
.IsEmpty() || size
.ToLong(&lSize
)) && (lSize
>= 0)) {
402 SetCurrentField(val
.Left(lSize
));
404 wxFAIL_MSG(wxT("Invalid value found in 'precision' field: ") + m_format
);
405 SetCurrentField(field
);
407 } else if (field
.GetChar(1) == wxT('s')) {
408 // No limit on size, just set the string
409 SetCurrentField(val
);
411 SetCurrentField(field
);
412 wxFAIL_MSG(wxT("Malformed string format field: ") + m_format
);
418 CFormat
& CFormat::operator%(void * value
)
420 wxString field
= GetCurrentField();
422 if (field
.IsEmpty()) {
423 // We've already asserted in GetCurrentField.
424 } else if (field
.Last() != wxT('p')) {
425 wxFAIL_MSG(wxT("Pointer value passed to non-pointer format string: ") + m_format
);
426 SetCurrentField(field
);
427 } else if (field
!= wxT("%p")) {
428 wxFAIL_MSG(wxT("Modifiers are not allowed for pointer format string: ") + m_format
);
429 SetCurrentField(field
);
431 // built-in Format for pointer is not optimal:
432 // - Windows: uppercase, no leading 0x
433 // - Linux: leading zeros missing
434 // -> format it as hex
435 if (sizeof (void *) == 8) { // 64 bit
436 SetCurrentField(wxString::Format(wxT("0x%016x"), (uintptr_t) value
));
438 SetCurrentField(wxString::Format(wxT("0x%08x"), (uintptr_t) value
));
445 // File_checked_for_headers