--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/format.h Wed Dec 10 19:17:00 2014 +0200 @@ -0,0 +1,216 @@ +/* + Copyright 2014 Teemu Piippo + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "mystring.h" +#include "basics.h" +#include "geometry.h" + +#define FORMAT_OVERLOAD(T) \ + inline FUNCTION make_format_argument (T a) -> String + +// +// ------------------------------------------------------------------------------------------------- +// + +FORMAT_OVERLOAD (String) { return a; } +FORMAT_OVERLOAD (char) { return String (a); } +FORMAT_OVERLOAD (int) { return String::from_number (a); } +FORMAT_OVERLOAD (long int) { return String::from_number (a); } +FORMAT_OVERLOAD (double) { return String::from_number (a); } +FORMAT_OVERLOAD (size_t) { return String::from_number (a); } +FORMAT_OVERLOAD (const char*) { return a; } +FORMAT_OVERLOAD (std::nullptr_t) { (void) a; return "<null pointer>"; } +FORMAT_OVERLOAD (bool) { return a ? "true" : "false"; } + +FORMAT_OVERLOAD (const void*) +{ + String result; + result.sprintf ("%p", a); + return result; +} + +template<typename T> +FORMAT_OVERLOAD (const List<T>&) +{ + String result; + + if (a.is_empty()) + return "{}"; + + result = "{"; + + for (auto it = a.begin(); it != a.end(); ++it) + { + if (it != a.begin()) + result += ", "; + + result += make_format_argument (*it); + } + + result += "}"; + return result; +} + +FORMAT_OVERLOAD (Color) +{ + static const char* colorstrings[] = + { + "BLACK", "RED", "GREEN", "YELLOW", + "BLUE", "MAGENTA", "CYAN", "WHITE", "DEFAULT" + }; + + static_assert (sizeof colorstrings / sizeof *colorstrings == NUM_COLORS, + "colostrings[] has an incorrect amount of elements"); + + if (int (a) >= 0 and int (a) < NUM_COLORS) + return colorstrings[int (a)]; + + return "???"; +} + +FORMAT_OVERLOAD (Position) { return String ("(") + a.x + ", " + a.y + ")"; } +FORMAT_OVERLOAD (Size) { return String ("(") + a.width + "x" + a.height + ")"; } + +FORMAT_OVERLOAD (Rectangle) +{ + String result; + result.sprintf ("{(%d, %d), (%dx%d)}", a.x, a.y, a.width, a.height); + return result; +} + +// +// ------------------------------------------------------------------------------------------------- +// +// Formats the given string with the given args. +// +auto format_args (const String& fmtstr, const Vector<String>& args) -> String; + +// +// ------------------------------------------------------------------------------------------------- +// +// Expands the given arguments into a vector of strings. +// +template<typename T, typename... RestTypes> +auto expand_format_arguments (Vector<String>& data, const T& arg, const RestTypes& ... rest) -> void +{ + data.append (make_format_argument (arg).text()); + expand_format_arguments (data, rest...); +} + +static void expand_format_arguments (Vector<String>&) __attribute__( (unused)); +static void expand_format_arguments (Vector<String>&) {} + +// +// ------------------------------------------------------------------------------------------------- +// +// Formats the given formatter string and args and returns the string. +// This is essentially a modernized sprintf. +// +// Args in the format string take the form %n where n is a digit. The argument +// will be expanded to the nth argument passed. This is essentially Qt's +// QString::arg() syntax. Note: %0 is invalid. +// +// Arguments can be passed a modifier which takes the form of a character +// just before the digit. Currently supported modifiers are s, d and x. +// +// - s: The argument will expand into "s" if it would've not expanded into "1" +// otherwise. If it would have expanded into "1" it will expand into an +// empty string. +// +// - d: The argument expands into the numeric form of the first character of +// its previous expansion. Use this to get numeric forms of @c char +// arguments. +// +// - x: The numeric argument will be represented in hexadecimal notation. This +// will work if the argument is a string representing a number. If the +// argument did not expand into a number in the first place, 0 is used +// and 0x0 is printed. +// +template<typename... argtypes> +String format (const String& fmtstr, const argtypes&... raw_args) +{ + Vector<String> args; + expand_format_arguments (args, raw_args...); + return format_args (fmtstr, args); +} + +// +// ------------------------------------------------------------------------------------------------- +// +// This is an overload of format() where no arguments are supplied. +// It returns the formatter string as-is. +// +static String format (const String& fmtstr) __attribute__ ((unused)); +static String format (const String& fmtstr) +{ + return fmtstr; +} + +// +// ------------------------------------------------------------------------------------------------- +// + +template<typename... Args> +void print_to (FILE* fp, const String& fmtstr, Args const& ...args) +{ + std::fprintf (fp, "%s", format (fmtstr, args...).chars()); +} + +// +// ------------------------------------------------------------------------------------------------- +// + +template<typename... argtypes> +void print_to (const String& filename, const String& fmtstr, const argtypes&... args) +{ + FILE* handle; + + if ((handle = fopen (filename, "w+"))) + { + print_to (handle, fmtstr, args...); + fclose (handle); + } +} + +// +// ------------------------------------------------------------------------------------------------- +// + +template<typename... argtypes> +void print (const String& fmtstr, const argtypes&... args) +{ + print_to (stdout, fmtstr, args...); +} + +#define PRINT_TO_LOG(...) \ +{ \ + print_to (LOGFILE, "%1:%2: ", __PRETTY_FUNCTION__, __LINE__); \ + print_to (LOGFILE, __VA_ARGS__); \ +}