Lumiera  0.pre.03
»edit your freedom«
format-string.cpp
Go to the documentation of this file.
1 /*
2  FormatString - string template formatting based on boost::format
3 
4  Copyright (C) Lumiera.org
5  2011, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
50 #include "lib/error.hpp"
51 #include "lib/format-util.hpp"
52 #include "lib/format-string.hpp"
53 
54 #include <boost/static_assert.hpp>
55 #include <boost/format.hpp>
56 #include <iostream>
57 #include <cstddef>
58 #include <new>
59 
60 
61 
62 
63 
64 namespace util {
65 
66  using boost::format;
67 
68 
69  namespace { // implementation details...
70 
71  inline boost::format&
72  accessImpl (std::byte* buffer)
73  {
74  return * std::launder (reinterpret_cast<boost::format*> (buffer));
75  }
76 
77 
78  inline void
79  destroyImpl (std::byte* buffer)
80  {
81  accessImpl(buffer).~format();
82  }
83 
84 
87  void
88  pushFailsafeReplacement (std::byte* formatter, const char* errorMsg =NULL)
89  try {
90  string placeholder("<Error");
91  if (errorMsg){
92  placeholder += ": ";
93  placeholder += errorMsg;
94  }
95  placeholder += ">";
96 
97  accessImpl(formatter) % placeholder;
98  }
99  ERROR_LOG_AND_IGNORE (progress, "Supplying placeholder for problematic format parameter")
100 
101 
102  inline void
103  suppressInsufficientArgumentErrors (std::byte* formatter)
104  {
105  using namespace boost::io;
106  accessImpl(formatter).exceptions (all_error_bits ^ too_few_args_bit);
107  }
108 
109 
110  }//(End) implementation details
111 
112 
113 
114 
115 
123  _Fmt::_Fmt (string formatString)
124  try {
125  static_assert (sizeof(boost::format) <= FORMATTER_SIZE,
126  "opaque working buffer insufficient "
127  "to hold a boost::format instance. "
128  "Maybe boost implementation change. "
129  "Please verify lib/meta/size-trait.hpp");
130 
131  new(formatter_) boost::format(formatString);
132  suppressInsufficientArgumentErrors (formatter_);
133  }
134  catch (boost::io::bad_format_string& syntaxError)
135  {
136  throw lumiera::error::Fatal (syntaxError
137  , _Fmt("Format string '%s' is broken") % formatString
138  , LUMIERA_ERROR_FORMAT_SYNTAX);
139  }
140 
141 
142  _Fmt::~_Fmt ()
143  {
144  destroyImpl (formatter_);
145  }
146 
147 
161  template<typename VAL>
162  void
163  _Fmt::format (const VAL val, Implementation& formatter)
164  try {
165  accessImpl(formatter) % val;
166  }
167 
168  catch (boost::io::too_many_args& argErr)
169  {
170  WARN (progress, "Format: excess argument '%s' of type «%s» ignored."
171  , cStr(toString(val))
172  , cStr(typeStr(val)));
173  }
174  catch (std::exception& failure)
175  {
176  _clear_errorflag();
177  WARN (progress, "Format: Parameter '%s' causes problems: %s"
178  , cStr(toString(val))
179  , failure.what());
180  pushFailsafeReplacement (formatter, failure.what());
181  }
182  catch (...)
183  {
184  _clear_errorflag();
185  WARN (progress, "Format: Unexpected problems accepting format parameter '%s'", cStr(toString(val)));
186  pushFailsafeReplacement (formatter);
187  }
188 
189 
190 
191 
192  /* ===== explicitly supported =================== */
193 
194  template void _Fmt::format (const char, Implementation&);
195  template void _Fmt::format (const uchar, Implementation&);
196  template void _Fmt::format (const int16_t, Implementation&);
197  template void _Fmt::format (const uint16_t,Implementation&);
198  template void _Fmt::format (const int32_t, Implementation&);
199  template void _Fmt::format (const uint32_t,Implementation&);
200  template void _Fmt::format (const int64_t, Implementation&);
201  template void _Fmt::format (const uint64_t,Implementation&);
202  template void _Fmt::format (const float, Implementation&);
203  template void _Fmt::format (const double, Implementation&);
204  template void _Fmt::format (const string, Implementation&);
205  template void _Fmt::format (const void *, Implementation&);
206  template void _Fmt::format (const char *, Implementation&);
207 #ifndef __x86_64__
208  template void _Fmt::format (const long, Implementation&);
209  template void _Fmt::format (const ulong, Implementation&);
210 #endif
211 
212 
213 
214 
222  _Fmt::operator string() const
223  try {
224  return accessImpl(formatter_).str();
225  }
226 
227  catch (std::exception& failure)
228  {
229  _clear_errorflag();
230  WARN (progress, "Format: Failure to receive formatted result: %s", failure.what());
231  return "<formatting failure>";
232  }
233  catch (...)
234  {
235  _clear_errorflag();
236  WARN (progress, "Format: Unexpected problems while formatting output.");
237  return "<unexpected problems>";
238  }
239 
240 
241 
247  std::ostream&
248  operator<< (std::ostream& os, _Fmt const& fmt)
249  try {
250  return os << accessImpl(fmt.formatter_);
251  }
252 
253  catch(std::exception& failure)
254  {
255  _clear_errorflag();
256  WARN (progress, "Format: Failure when outputting formatted result: %s", failure.what());
257  return os << "<formatting failure>";
258  }
259  catch(...)
260  {
261  _clear_errorflag();
262  WARN (progress, "Format: Unexpected problems while producing formatted output.");
263  return os << "<unexpected problems>";
264  }
265 
266 
267  LUMIERA_ERROR_DEFINE (FORMAT_SYNTAX, "Syntax error in format string for boost::format");
268 
269 
270 
271 } // namespace util
static void format(const VAL, Implementation &)
call into the opaque implementation
Implementation formatter_
_Fmt(string formatString)
Build a formatter object based on the given format string.
CStr cStr(std::string const &rendered)
convenience shortcut: forced conversion to c-String via string.
Definition: symbol.hpp:68
void pushFailsafeReplacement(std::byte *formatter, const char *errorMsg=NULL)
in case the formatting of a (primitive) value fails, we try to supply an error indicator instead ...
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
Definition: error.hpp:275
Front-end for printf-style string template interpolation.
A front-end for using printf-style formatting.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
std::string toString(TY const &val) noexcept
get some string representation of any object, reliably.
Definition: format-obj.hpp:200
Lumiera error handling (C++ interface).
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
#define LUMIERA_ERROR_DEFINE(err, msg)
Definition and initialisation of an error constant.
Definition: error.h:80