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
28 //! Known type-modifiers.
31 //! No modifier field.
33 //! Argument is interpreted as short int (integer types).
35 //! Argument is interpreted as long int (interger types).
37 //! Two 'long' modifieres, arguments is interpreted as long long (integer types).
39 //! Argument is interpreted as long double (floating point types). Not supported.
45 * Extracts modifiers from the argument.
47 * Note that this function will possibly return wrong results
48 * for malformed format strings.
50 Modifiers
getModifier(const wxString
& str
)
52 switch ( (wxChar
)str
[str
.Len() - 2]) {
53 case wxT('h'): // short int (integer types).
55 case wxT('l'): // long int (interger types) or double (floating point types).
56 if ( str
.Len() > 3 && str
.GetChar( str
.Len() - 3 ) == wxT('l') ) {
61 case wxT('L'): // long double (floating point types).
69 /** Returns true if the char is a format-type. */
70 bool isTypeChar(wxChar c
)
73 case wxT('s'): // String of characters
74 case wxT('u'): // Unsigned decimal integer
75 case wxT('i'): // Signed decimal integer
76 case wxT('d'): // Signed decimal integer
77 case wxT('c'): // Character
78 case wxT('f'): // Decimal floating point
79 case wxT('F'): // Decimal floating point
80 case wxT('x'): // Unsigned hexadecimal integer
81 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
82 case wxT('o'): // Unsigned octal
83 case wxT('e'): // Scientific notation (mantise/exponent) using e character
84 case wxT('E'): // Scientific notation (mantise/exponent) using E character
85 case wxT('g'): // Use shorter %e or %f
86 case wxT('G'): // Use shorter %E or %f
87 case wxT('p'): // Not supported, still needs to be caught though
88 case wxT('n'): // Not supported, still needs to be caught though
95 /** Returns true if the char is a valid flag. */
96 bool isFlagChar(wxChar c
)
99 case wxT('+'): // Include sign for integers
100 case wxT('-'): // Left-align output
101 case wxT('#'): // Alternate form, varies
102 case wxT(' '): // Pad with spaces
103 case wxT('0'): // Pad with zeros
110 /** Returns true if the char is an integer (for width + precision). */
111 bool isIntChar(wxChar c
)
113 return ((c
>= wxT('0')) && (c
<= wxT('9')));
117 /** Returns true if the cahr is a valid length modifier. */
118 bool isLengthChar(wxChar c
)
121 case wxT('h'): // Short ('hh') and char ('h')
122 case wxT('l'): // Long ('l') and long long ('ll')
123 case wxT('L'): // Double long
124 case wxT('z'): // size_t
125 case wxT('j'): // intmax_t
126 case wxT('t'): // ptrdiff_t
130 // Catches widths, precisons and zero-padding
131 return (c
>= wxT('0')) && (c
<= wxT('9'));
135 CFormat::CFormat(const wxChar
* str
)
142 if (m_format
.Length()) {
143 SetCurrentField(wxEmptyString
);
148 bool CFormat::IsReady() const
150 return (m_fieldStart
== m_format
.Length());
154 wxString
CFormat::GetString() const
159 wxFAIL_MSG(wxT("Called GetString() before all values were passed: ") + m_format
);
161 // Return as much as possible ...
162 return m_result
+ m_format
.Mid(m_fieldStart
);
167 void CFormat::SetCurrentField(const wxString
& value
)
169 wxCHECK_RET(m_fieldStart
< m_format
.Length(),
170 wxT("Setting field in already completed string: ") + m_format
);
172 if (value
.Length()) {
186 // Format strings are expected to follow the folllowing structure:
187 // %[Flags][Width][.Precision][Length]<Type>
188 for (size_t i
= m_fieldStart
+ m_fieldLength
; i
< m_format
.Length(); ++i
) {
189 const wxChar c
= m_format
[i
];
191 if (pos
>= PosStart
) {
194 if ((pos
<= PosFlags
) && isFlagChar(c
)) {
196 } else if ((pos
<= PosWidth
) && isIntChar(c
)) {
198 } else if ((pos
< PosPrecision
) && (c
== wxT('.'))) {
200 } else if ((pos
== PosPrecision
) && isIntChar(c
)) {
202 } else if ((pos
< PosLength
) && isLengthChar(c
)) {
204 } else if ((pos
== PosLength
) && isLengthChar(c
) && (c
== m_format
[i
- 1])) {
206 } else if ((pos
<= PosLength
) && isTypeChar(c
)) {
209 } else if ((pos
<= PosLength
) && (c
== wxT('%'))) {
210 // Append the %*% to the result
211 m_result
+= wxT("%");
215 // Field is broken ...
218 } else if (c
== wxT('%')) {
219 const size_t offset
= m_fieldStart
+ m_fieldLength
;
220 // If there was anything before this, then prepend it.
222 m_result
+= m_format
.Mid(offset
, i
- offset
);
225 // Starting a new format string
230 // Normal text, nothing to do ...
234 if (pos
== PosNone
) {
236 m_result
+= m_format
.Mid(m_fieldStart
+ m_fieldLength
);
238 m_fieldStart
= m_fieldLength
= m_format
.Length();
239 } else if (pos
!= PosEnd
) {
240 // A partial field was found ...
241 wxFAIL_MSG(wxT("Invalid field in format string: ") + m_format
);
242 wxASSERT_MSG(m_fieldStart
+ m_fieldLength
<= m_format
.Length(),
243 wxT("Invalid field-start/length in format string: ") + m_format
);
245 // Prepend the parsed part of the format-string
246 m_result
+= m_format
.Mid(m_fieldStart
, m_fieldLength
);
248 // Return an empty string the next time GetCurrentField is called
251 // Anything left to do?
253 // Find the next format string
254 SetCurrentField(wxEmptyString
);
260 wxString
CFormat::GetCurrentField()
262 wxCHECK_MSG(m_fieldStart
< m_format
.Length(), wxEmptyString
,
263 wxT("Passing argument to already completed string: ") + m_format
);
264 wxASSERT_MSG(m_fieldStart
+ m_fieldLength
<= m_format
.Length(),
265 wxT("Invalid field-start/length in format string: ") + m_format
);
268 // The current field was invalid, so we skip it.
271 return wxEmptyString
;
274 return m_format
.Mid(m_fieldStart
, m_fieldLength
);
278 wxString
CFormat::GetIntegerField(const wxChar
* fieldType
)
280 const wxString field
= GetCurrentField();
281 if (field
.IsEmpty()) {
282 // Invalid or missing field ...
286 // Drop type and length
287 wxString newField
= field
;
288 while (isalpha(newField
.Last())) {
289 newField
.RemoveLast();
292 // Set the correct integer type
293 newField
+= fieldType
;
295 switch ((wxChar
)field
.Last()) {
296 case wxT('o'): // Unsigned octal
297 case wxT('x'): // Unsigned hexadecimal integer
298 case wxT('X'): // Unsigned hexadecimal integer (capital letters)
299 // Override the default type
300 newField
.Last() = field
.Last();
302 case wxT('d'): // Signed decimal integer
303 case wxT('i'): // Signed decimal integer
304 case wxT('u'): // Unsigned decimal integer
308 wxFAIL_MSG(wxT("Integer value passed to non-integer format string: ") + m_format
);
309 SetCurrentField(field
);
310 return wxEmptyString
;
315 CFormat
& CFormat::operator%(double value
)
317 wxString field
= GetCurrentField();
318 if (field
.IsEmpty()) {
322 switch ( (wxChar
)field
.Last() ) {
323 case wxT('e'): // Scientific notation (mantise/exponent) using e character
324 case wxT('E'): // Scientific notation (mantise/exponent) using E character
325 case wxT('f'): // Decimal floating point
326 case wxT('F'): // Decimal floating point
327 case wxT('g'): // Use shorter %e or %f
328 case wxT('G'): // Use shorter %E or %f
329 wxASSERT_MSG(getModifier(field
) == modNone
, wxT("Invalid modifier specified for floating-point format: ") + m_format
);
331 SetCurrentField(wxString::Format(field
, value
));
335 wxFAIL_MSG(wxT("Floating-point value passed to non-float format string: ") + m_format
);
336 SetCurrentField(field
);
343 CFormat
& CFormat::operator%(wxChar value
)
345 wxString field
= GetCurrentField();
347 if (field
.IsEmpty()) {
348 // We've already asserted in GetCurrentField.
349 } else if (field
.Last() != wxT('c')) {
350 wxFAIL_MSG(wxT("Char value passed to non-char format string: ") + m_format
);
351 SetCurrentField(field
);
353 SetCurrentField(wxString::Format(field
, value
));
360 CFormat
& CFormat::operator%(signed long long value
)
362 wxString field
= GetIntegerField(wxLongLongFmtSpec
wxT("i"));
363 if (!field
.IsEmpty()) {
364 SetCurrentField(wxString::Format(field
, value
));
371 CFormat
& CFormat::operator%(unsigned long long value
)
373 wxString field
= GetIntegerField(wxLongLongFmtSpec
wxT("u"));
374 if (!field
.IsEmpty()) {
375 SetCurrentField(wxString::Format(field
, value
));
382 CFormat
& CFormat::operator%(const wxString
& val
)
384 wxString field
= GetCurrentField();
386 if (field
.IsEmpty()) {
387 // We've already asserted in GetCurrentField
388 } else if (field
.Last() != wxT('s')) {
389 wxFAIL_MSG(wxT("String value passed to non-string format string:") + m_format
);
390 SetCurrentField(field
);
391 } else if (field
.GetChar(1) == wxT('.')) {
392 // A max-length is specified
393 wxString size
= field
.Mid( 2, field
.Len() - 3 );
396 // Try to convert the length-field.
397 if ((size
.IsEmpty() || size
.ToLong(&lSize
)) && (lSize
>= 0)) {
398 SetCurrentField(val
.Left(lSize
));
400 wxFAIL_MSG(wxT("Invalid value found in 'precision' field: ") + m_format
);
401 SetCurrentField(field
);
403 } else if (field
.GetChar(1) == wxT('s')) {
404 // No limit on size, just set the string
405 SetCurrentField(val
);
407 SetCurrentField(field
);
408 wxFAIL_MSG(wxT("Malformed string format field: ") + m_format
);
414 // File_checked_for_headers