// // This file is part of the aMule Project. // // Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #ifndef FORMAT_H #define FORMAT_H #include #include "MuleDebug.h" /** * This class offers a typesafe alternative to wxString::Format. * * %CFormat has been implemented against the description of printf found * in the "man 3 printf" manual page. * * %CFormat lacks the following capabilities: * - The @c "*" width-modifier, because only one argument is fed at a time. * - The @c "n" type, just unsafe and won't be implemented. * - The @c "C" and @c "S" types, which are considered obsolete. * - The Long Double type, which is extremly slow and shouldn't be used. * * Support for the C99 @c a, @c A conversions and the non-standard @c ', @c I * flags depend on the underlying C library. Do not use them. * * Supports the glibc-specific @c m conversion on all platforms, where there's * a way to get the error description. If the underlying C library has a * thread-safe way to get the error description, then this conversion is * thread-safe, too. * * Deviations from printf(3): * * %CFormat tries hard to format the passed POD-type according to the * conversion type. Basic type conversions may take place to accomplish this * goal. This results in formats accepting a variety of types, namely: * - @c c, @c i, @c d, @c u, @c o, @c x, @c X accept @c wxChar and all integer * types, * - @c a, @c A, @c e, @c E, @c f, @c F, @c g, @c G accept @c wxChar, integer * and floating-point types, * - @c p accepts only pointers, * - @c s accepts all the above mentioned types in addition to @c wxString and * @c wxChar* types. * * The only exception from this rule is integer (@c d, @c i, @c u) conversion. * It will always use the correct conversion (@c i or @c u) depending on the * signedness of the passed argument. * * @c 's' conversions are inspired by the "we're converting to string, * anyway" mood. Thus they use a 'default' conversion for each accepted * type: @c 'c' for @c wxChar, @c 'i' and @c 'u' for signed and unsigned * integers, respectively, @c 'g' for floating-point numbers and @c 'p' for * pointers. * * Other relaxations / differences from printf(3): * - Length modifiers are read and validated, but always ignored. * - As a consequence, invalid combinations of length modifiers and conversion * types are silently ignored (i.e. for example the invalid @c '%%qs' * format-specifier is silently treated as @c '%%s'). * - @c 'p' conversion ignores all modifiers except the argument index reference. * - You can mix positional and indexed argument references. (You actually can't, * because msgfmt will treat this as an error.) * - With indexed argument references we allow to leave gaps in the indices. */ class CFormat { private: /** * Structure to hold a format specifier. */ struct FormatSpecifier { unsigned argIndex; //!< Argument index. (Position, unless specified otherwise.) wxChar flag; //!< The optional flag character. unsigned width; //!< The optional field width. signed precision; //!< The optional precision value. // length is not stored wxChar type; //!< The conversion type. size_t startPos; //!< Position of the first character of the format-specifier in the format-string. size_t endPos; //!< Position of the last character of the format-specifier in the format-string. wxString result; //!< Result of the conversion. Initialized to the format-specifier. }; public: /** * Constructor. * * @param str The format-string to be used. */ CFormat(const wxChar* str) { Init(str); } /** * Constructor. * * This form is required to construct from a plain char * * with wx 2.9 * * @param str The format-string to be used. */ CFormat(const wxString& str) { Init(str); } /** * Feeds a value into the format-string. * * Passing a type that isn't compatible with the current format * field results in the field being skipped, and an exception raised. * * Passing any type to a CFormat with no free fields results in the * argument being ignored. * * Specialize this member template to teach CFormat how to handle * other types. */ template CFormat& operator%(_Tp value); // Overload hack to map all pointer types to void* template CFormat& operator%(_Tp* value) { return this->operator%(value); } // explicit overloads to avoid pass-by-value even in debug builds. CFormat& operator%(const wxString& value) { return this->operator%(value); } CFormat& operator%(const CFormat& value) { return this->operator%(value); } /** * Returns the resulting string. */ wxString GetString() const; /** * Implicit conversion to wxString. */ operator wxString() const { return GetString(); }; private: /** * Initialize internal structures. * * Initializes member variables and parses the given format string. */ void Init(const wxString& str); //! Type holding format specifiers. typedef std::list FormatList; //! Retrieve the modifiers for the given format specifier. wxString GetModifiers(FormatList::const_iterator it) const; //! Do one argument conversion. template void ProcessArgument(FormatList::iterator it, _Tp value); //! List of the valid format-specifiers found in the format string. FormatList m_formats; //! Number of the previous argument. unsigned m_argIndex; //! The format-string fed to the parser. wxString m_formatString; }; // type mappings template<> inline CFormat& CFormat::operator%(char value) { return *this % (wxChar)value; } template<> inline CFormat& CFormat::operator%(signed char value) { return *this % (wxChar)value; } template<> inline CFormat& CFormat::operator%(unsigned char value) { return *this % (wxChar)value; } template<> inline CFormat& CFormat::operator%(bool value) { return *this % (signed long long)value; } template<> inline CFormat& CFormat::operator%(signed short value) { return *this % (signed long long)value; } template<> inline CFormat& CFormat::operator%(unsigned short value) { return *this % (unsigned long long)value; } template<> inline CFormat& CFormat::operator%(signed int value) { return *this % (signed long long)value; } template<> inline CFormat& CFormat::operator%(unsigned int value) { return *this % (unsigned long long)value; } template<> inline CFormat& CFormat::operator%(signed long value) { return *this % (signed long long)value; } template<> inline CFormat& CFormat::operator%(unsigned long value) { return *this % (unsigned long long)value; } template<> inline CFormat& CFormat::operator%(float value) { return *this % (double)value; } template<> inline CFormat& CFormat::operator%(const wxChar* value) { return this->operator%(wxString(value)); } #if wxCHECK_VERSION(2, 9, 0) #define WXLONGLONGFMTSPEC wxT(wxLongLongFmtSpec) #else #define WXLONGLONGFMTSPEC wxLongLongFmtSpec #endif #endif // File_checked_for_headers