/* FormatString - string template formatting based on boost::format Copyright (C) Lumiera.org 2011, Hermann Vosseler 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************/ /** @file format-string.cpp ** Implementation for printf-style formatting, based on boost::format. ** This file holds the generic implementation of our format frontend, ** which actually just invokes boost::format. The corresponding header ** format-string.hpp provides some template functions and classes, ** either invoking a custom string conversion, or passing primitive ** values down unaltered. ** ** Here, we define explicit specialisations for the frontend to invoke, ** which in turn just pass on the given argument value to the embedded ** boost::format object, which in turn dumps the formatted result ** into an embedded string stream. ** ** To avoid exposing boost::format in the frontend header, we use an ** opaque buffer of appropriate size to piggyback the formatter object. ** @warning unfortunately this requires a hard coded buffer size constant ** in the front-end, which we define there manually, based on ** the current implementation layout found in the boost libraries. ** If Boost eventually changes the implementation, the assertion ** in our constructor will trigger. ** ** @see FormatString_test ** */ #include "lib/error.hpp" #include "lib/format-util.hpp" #include "lib/format-string.hpp" #include #include #include namespace util { using boost::format; namespace { // implementation details... inline boost::format& accessImpl (char* buffer) { return reinterpret_cast (*buffer); } inline void destroyImpl (char* buffer) { accessImpl(buffer).~format(); } /** in case the formatting of a (primitive) value fails, * we try to supply an error indicator instead */ void pushFailsafeReplacement (char* formatter, const char* errorMsg =NULL) try { string placeholder(" void _Fmt::format (const VAL val, Implementation& formatter) try { accessImpl(formatter) % val; } catch (boost::io::too_many_args& argErr) { WARN (progress, "Format: excess argument '%s' of type %s ignored." , cStr(str(val)) , cStr(tyStr(val))); } catch (std::exception& failure) { _clear_errorflag(); WARN (progress, "Format: Parameter '%s' causes problems: %s" , cStr(str(val)) , failure.what()); pushFailsafeReplacement (formatter, failure.what()); } catch (...) { _clear_errorflag(); WARN (progress, "Format: Unexpected problems accepting format parameter '%s'", cStr(str(val))); pushFailsafeReplacement (formatter); } /* ===== explicitly supported =================== */ template void _Fmt::format (const char, Implementation&); template void _Fmt::format (const uchar, Implementation&); template void _Fmt::format (const int16_t, Implementation&); template void _Fmt::format (const uint16_t,Implementation&); template void _Fmt::format (const int32_t, Implementation&); template void _Fmt::format (const uint32_t,Implementation&); template void _Fmt::format (const int64_t, Implementation&); template void _Fmt::format (const uint64_t,Implementation&); template void _Fmt::format (const float, Implementation&); template void _Fmt::format (const double, Implementation&); template void _Fmt::format (const string, Implementation&); template void _Fmt::format (const void *, Implementation&); template void _Fmt::format (const char *, Implementation&); #ifndef __x86_64__ template void _Fmt::format (const long, Implementation&); template void _Fmt::format (const ulong, Implementation&); #endif /** @remarks usually the _Fmt helper is used inline * at places where a string is expected. The '%' operator * used to fed parameters has a higher precedence than the * assignment or comparison operators, ensuring that all parameters * are evaluated and formatted prior to receiving the formatted result * @note EX_FREE */ _Fmt::operator string() const try { return accessImpl(formatter_).str(); } catch (std::exception& failure) { _clear_errorflag(); WARN (progress, "Format: Failure to receive formatted result: %s", failure.what()); return ""; } catch (...) { _clear_errorflag(); WARN (progress, "Format: Unexpected problems while formatting output."); return ""; } /** send the formatted buffer directly to the output stream. * @note this is more efficient than creating a string and outputting that, * because boost::format internally uses a string-stream to generate * the formatted representation, relying on the C++ output framework */ std::ostream& operator<< (std::ostream& os, _Fmt const& fmt) try { return os << accessImpl(fmt.formatter_); } catch(std::exception& failure) { _clear_errorflag(); WARN (progress, "Format: Failure when outputting formatted result: %s", failure.what()); return os << ""; } catch(...) { _clear_errorflag(); WARN (progress, "Format: Unexpected problems while producing formatted output."); return os << ""; } LUMIERA_ERROR_DEFINE (FORMAT_SYNTAX, "Syntax error in format string for boost::format"); } // namespace util