Merge lp:~zorba-coders/zorba/zorba-error_printer_in_api into lp:zorba

Proposed by David Graf
Status: Merged
Approved by: Paul J. Lucas
Approved revision: 11148
Merged at revision: 11222
Proposed branch: lp:~zorba-coders/zorba/zorba-error_printer_in_api
Merge into: lp:zorba
Diff against target: 1148 lines (+475/-273)
14 files modified
ChangeLog (+2/-0)
bin/CMakeLists.txt (+3/-5)
bin/error_printer.cpp (+0/-132)
bin/error_printer.h (+0/-40)
bin/zorbacmd.cpp (+23/-12)
doc/cxx/examples/errors.cpp (+31/-0)
include/zorba/xquery_exception.h (+55/-1)
include/zorba/xquery_stack_trace.h (+3/-3)
include/zorba/zorba_exception.h (+50/-2)
src/diagnostics/xquery_exception.cpp (+171/-30)
src/diagnostics/zorba_exception.cpp (+86/-24)
src/runtime/json/common.h (+2/-23)
src/util/fs_util.h (+1/-1)
src/util/omanip.h (+48/-0)
To merge this branch: bzr merge lp:~zorba-coders/zorba/zorba-error_printer_in_api
Reviewer Review Type Date Requested Status
Paul J. Lucas Approve
Matthias Brantner Approve
William Candillon Approve
Review via email: mp+134405@code.launchpad.net

Commit message

Moving the error printer from zorbacmd into the api.

Description of the change

Moving the error printer from zorbacmd into the api.

To post a comment you must log in.
Revision history for this message
David Graf (davidagraf) wrote :

It would be good to use this error printer for the warning reporter too. But I didn't figure out how that should work yet? Can you guys help?

Revision history for this message
William Candillon (wcandillon) :
review: Approve
Revision history for this message
Matthias Brantner (matthias-brantner) wrote :

I approve but I want to make sure the same or similar functionality (maybe without XML printing) is not already available in the API. Hence, I added Paul.

review: Approve
Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

It's a stupid API. There's no reason to have a class with a single static member function. If you're going to make it public, it needs to be better. Two things come to mind:

1. (Trivial) Simply make it a global function -- no need for a class.

2. (Less trivial) Create a (real) ErrorPrinter class that holds the configuration parameters; then using operator<<, you can write an XQueryException to it.

3. Regardless, the indentation parameter should be an unsigned int (not a bool): it will specify a multiplier for the amount of indentation (where 0 = none).

BTW: It should take a ZorbaException, not an XQueryException.

review: Disapprove
Revision history for this message
David Graf (davidagraf) wrote :

Cool, now I can fix what someone else did wrong :-(.

Anyway, Paul, can you help me on one thing please? Can you tell me how I can use this ErrorPrinter for warnings too?

> It's a stupid API. There's no reason to have a class with a single static
> member function. If you're going to make it public, it needs to be better.
> Two things come to mind:
>
> 1. (Trivial) Simply make it a global function -- no need for a class.
>
> 2. (Less trivial) Create a (real) ErrorPrinter class that holds the
> configuration parameters; then using operator<<, you can write an
> XQueryException to it.
>
> 3. Regardless, the indentation parameter should be an unsigned int (not a
> bool): it will specify a multiplier for the amount of indentation (where 0 =
> none).
>
> BTW: It should take a ZorbaException, not an XQueryException.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

> Anyway, Paul, can you help me on one thing please? Can you tell me how I can
> use this ErrorPrinter for warnings too?

An XQueryWarning is just a typedef for XQueryException, so it should just work as-is.

That aside: generally, I don't like to decide for the user how errors should be printed. By putting an error-printer in the public API, you're essentially making that decision for them. If you're going to do that, you could just define operator<<(ostream&,ZorbaException const&) and then << would just work.

If you want to set parameters (like XML or indentation), then the nice way to do it is via stream manipulators, e.g.:

    // ...
    }
    catch ( XQueryException const &e ) {
      cout << XQueryException::as_xml << XQueryException::indent( 2 ) << e;
    }

You can look at src/util/indent.h for how to do this kind of thing. The above manipulators, however, should be "one-shot" and auto-reset (which is trivial to do).

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

I just checked: ZorbaException already has a global operator<<(ostream&,ZorbaException const&) function defined for it.

So why do you need to do anything at all?

Revision history for this message
David Graf (davidagraf) wrote :

> I just checked: ZorbaException already has a global
> operator<<(ostream&,ZorbaException const&) function defined for it.
>
> So why do you need to do anything at all?
Hi Paul, sorry for not following up for a long time. We just need it to get the errors in xml format. I guess this is not supported in operator<<(ostream&,ZorbaException const&). I will investigate in the stream manipulators. Hopefully, I understand how it works!

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

I've done a lot of clean-up. You have the basic implementation correct. I've moved several functions inline. I've moved the printing of the stack trace constants to XQueryException since only XQueryException has stack traces. I've added doxygen comments that you didn't.

Why don't you include the "raised at" in the XML format?

Why don't you include the "applied at" in the XML format? (Not knowing what it is is not an acceptable reason.)

Why does ErrorPrinter need to exist at all? It seems redundant.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

The error code was printed in XML as:

  <code>err:XPST0003</code>

I think it's better to print it as:

  <code>http://www.w3.org/2005/xqt-errors#XPST0003</code>

(as suggested in <http://www.w3.org/TR/xquery-30/#id-identifying-errors>).
But is it better still to print it as:

  <code ns="http://www.w3.org/2005/xqt-errors" prefix="err" localname="XPST0003"/>

?

Revision history for this message
Matthias Brantner (matthias-brantner) wrote :

> The error code was printed in XML as:
>
> <code>err:XPST0003</code>
>
> I think it's better to print it as:
>
> <code>http://www.w3.org/2005/xqt-errors#XPST0003</code>
>
> (as suggested in <http://www.w3.org/TR/xquery-30/#id-identifying-errors>).
> But is it better still to print it as:
>
> <code ns="http://www.w3.org/2005/xqt-errors" prefix="err"
> localname="XPST0003"/>
>
> ?
It would make sense to me but the problem is that the change is not backwards compatible. I know that 28msec relies on it.
on the current way the error is reported.

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

> It would make sense to me but the problem is that the change is not backwards compatible.
> I know that 28msec relies on it.
> on the current way the error is reported.

There were other mistakes that whoever coded the original XML made. For example, not including a xmlns="..." attribute on the <exception> element; omitting the <raised-at ...> information; using localized strings for the <code> value (this is one case where the string should NOT be localized).

Will those changes break 28msec as well?
Can't we just update the 28msec code?

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

Actually, in the short term, I'd like to revert the way the error code is printed to:

    <code>err:XPST0003</code>

and merge the branch into the trunk immediately because this branch actually makes testing the branch for bug 1111786 much easier. I'll file a separate bug to change the form to:

    <code namespace="http://www.w3.org/2005/xqt-errors" local-name="XPST0003"/>

for 3.0.

OK?

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

Also, does the 28msec code rely on the <kind> being like:

  <kind>static error</kind>

or will:

  <kind>static</kind>

still work?

Revision history for this message
Paul J. Lucas (paul-lucas) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

The attempt to merge lp:~zorba-coders/zorba/zorba-error_printer_in_api into lp:zorba failed. Below is the output from the failed tests.

CMake Error at /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake:275 (message):
  Validation queue job zorba-error_printer_in_api-2013-02-07T00-11-30.914Z is
  finished. The final status was:

  2 tests did not succeed - changes not commited.

Error in read script: /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake

11148. By Paul J. Lucas

Fully reverted to old format.

Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job zorba-error_printer_in_api-2013-02-07T01-32-31.231Z is finished. The final status was:

All tests succeeded!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2013-01-31 19:52:13 +0000
3+++ ChangeLog 2013-02-07 01:30:37 +0000
4@@ -5,6 +5,7 @@
5 New Features:
6 * Typeswitch expression extended to allow union of types in each case clause,
7 as specified by XQuery v3.0
8+ * In C++ API, added optional XML formatting of exceptions.
9 * Extended sequence types to include unions, as specified by XQuery v3.0
10 * Added millis-to-dateTime() function in datetime module.
11
12@@ -184,6 +185,7 @@
13 http://www.zorba-xquery.com/modules/store/data-structures/unordered-map module.
14 * Added support for fragments to fn:path
15 * Positional pagination support for collections
16+ * Pagination by reference support for collections
17 * http://www.zorba-xquery.com/modules/archive module for creating,
18 reading, and updating various (compressed) archives (e.g. zip, tar.gz,
19 or tar.bz2)
20
21=== modified file 'bin/CMakeLists.txt'
22--- bin/CMakeLists.txt 2013-01-21 09:00:53 +0000
23+++ bin/CMakeLists.txt 2013-02-07 01:30:37 +0000
24@@ -46,14 +46,12 @@
25 SET(SRCS
26 zorbacmd.cpp
27 zorbacmdproperties.cpp
28- error_printer.cpp
29 util.cpp
30 path_util.cpp
31 )
32
33 ZORBA_GENERATE_EXE("zorbacmd" "${SRCS}" "" "zorba" "bin")
34
35-
36 IF(UNIX)
37 ADD_CUSTOM_TARGET(zorbacmd_man help2man -N -s1 -n Zorba -S "FLWOR Foundation" ./zorba > "${PROJECT_BINARY_DIR}/doc/zorba.1")
38 ADD_DEPENDENCIES(zorbacmd_man zorbacmd)
39@@ -80,12 +78,12 @@
40 ZORBA_SET_TEST_PROPERTY(bin/zorba_compilechk1 PASS_REGULAR_EXPRESSION ".*mymod.xq>:22,8:.*:XPST0008.*")
41
42 ZORBA_ADD_TEST(bin/zorba_compilechk2 zorbacmd -q "${CMAKE_CURRENT_SOURCE_DIR}/test/mymod.xq" -f -l -x)
43-ZORBA_SET_TEST_PROPERTY(bin/zorba_compilechk2 PASS_REGULAR_EXPRESSION ".*XPST0008.*mymod.xq' lineStart='22' columnStart='8' lineEnd='22' columnEnd='10'.*")
44+ZORBA_SET_TEST_PROPERTY(bin/zorba_compilechk2 PASS_REGULAR_EXPRESSION ".*XPST0008.*mymod.xq.*lineStart=['\"]22['\"] columnStart=['\"]8['\"] lineEnd=['\"]22['\"] columnEnd=['\"]10['\"].*")
45
46 # test compile checking to work with library modules that have an invalid target namespace uri
47 # test for bug #2934414
48 ZORBA_ADD_TEST(bin/zorba_compilechk3 zorbacmd -q "${CMAKE_CURRENT_SOURCE_DIR}/test/mymod2.xq" -f -l -x)
49-ZORBA_SET_TEST_PROPERTY(bin/zorba_compilechk3 PASS_REGULAR_EXPRESSION ".*XQST0046.*mymod2.xq' lineStart='17' columnStart='1' lineEnd='17' columnEnd='26'.*")
50+ZORBA_SET_TEST_PROPERTY(bin/zorba_compilechk3 PASS_REGULAR_EXPRESSION ".*XQST0046.*mymod2.xq.*lineStart=['\"]17['\"] columnStart=['\"]1['\"] lineEnd=['\"]17['\"] columnEnd=['\"]26['\"].*")
51
52 # test the --option option to set an option in the static context
53 ZORBA_ADD_TEST(bin/zorba_option zorbacmd -q "${CMAKE_CURRENT_SOURCE_DIR}/test/option.xq" -f --option "{http://www.zorba-xquery.com}option=value")
54@@ -138,4 +136,4 @@
55 ZORBA_ADD_TEST(bin/zorba_compilechk4 zorbacmd
56 -q "${CMAKE_CURRENT_SOURCE_DIR}/../test/zperf/src/start.xq" -f --compile-only)
57 ZORBA_SET_TEST_PROPERTY(bin/zorba_compilechk4
58- PASS_REGULAR_EXPRESSION "[]|[XQST0059]")
59\ No newline at end of file
60+ PASS_REGULAR_EXPRESSION "[]|[XQST0059]")
61
62=== removed file 'bin/error_printer.cpp'
63--- bin/error_printer.cpp 2012-09-19 21:16:15 +0000
64+++ bin/error_printer.cpp 1970-01-01 00:00:00 +0000
65@@ -1,132 +0,0 @@
66-/*
67- * Copyright 2006-2008 The FLWOR Foundation.
68- *
69- * Licensed under the Apache License, Version 2.0 (the "License");
70- * you may not use this file except in compliance with the License.
71- * You may obtain a copy of the License at
72- *
73- * http://www.apache.org/licenses/LICENSE-2.0
74- *
75- * Unless required by applicable law or agreed to in writing, software
76- * distributed under the License is distributed on an "AS IS" BASIS,
77- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
78- * See the License for the specific language governing permissions and
79- * limitations under the License.
80- */
81-
82-#include <ostream>
83-#include <sstream>
84-
85-#include <zorba/xquery_exception.h>
86-#include <zorba/xquery_functions.h>
87-#include <zorba/xquery_stack_trace.h>
88-#include <zorba/zorba_string.h>
89-
90-#include "zorba/util/uri.h"
91-#include "error_printer.h"
92-
93-namespace zorba {
94-
95- std::ostream&
96- print_stack_trace(
97- const XQueryException& aException,
98- std::ostream& aOut,
99- bool aAsXml,
100- bool aIndent)
101- {
102- XQueryStackTrace const& lTrace = aException.query_trace();
103- if (!lTrace.empty()) {
104- XQueryStackTrace::const_iterator it = lTrace.begin();
105- if (aAsXml) {
106- if (aIndent) aOut << " ";
107- aOut << "<stack>";
108- }
109- for (; it != lTrace.end(); ++it) {
110- XQueryStackTrace::fn_name_type const& lName = it->getFnName();
111- XQueryStackTrace::fn_arity_type lArity = it->getFnArity();
112- char const *const lPrefix = lName.prefix();
113- String lFileName = it->getFileName();
114- if (fn::starts_with(lFileName,"file:")) {
115- lFileName = URIHelper::decodeFileURI(lFileName);
116- while (fn::starts_with(lFileName,"//")) {
117- lFileName = lFileName.substr(1);
118- }
119- }
120- if (aAsXml) {
121- if (aIndent) aOut << std::endl << " ";
122- aOut << "<call ";
123- if (lPrefix && *lPrefix) {
124- aOut << "prefix=\"" << lPrefix << "\" ";
125- }
126- aOut << "arity=\"" << lArity << "\" ";
127- aOut << "ns=\"" << lName.ns() << "\" ";
128- aOut << "localName=\"" << lName.localname() << "\">";
129- if (aIndent) aOut << std::endl << " ";
130- aOut << "<location ";
131- aOut << "fileName=\"" << lFileName << "\" ";
132- aOut << "lineStart=\"" << it->getLine() << "\" "
133- << "columnStart=\"" << it->getColumn() << "\" ";
134- if (it->getLineEnd())
135- aOut << "lineEnd=\"" << it->getLineEnd() << "\" ";
136- if (it->getColumnEnd())
137- aOut << "lineEnd=\"" << it->getColumnEnd() << "\" ";
138- aOut << "/>";
139- if (aIndent) aOut << std::endl << " ";
140- aOut << "</call>";
141- } else {
142- std::ostringstream oss;
143- oss << lName;
144- String lFName = oss.str();
145- aOut << "=================================================" << std::endl;
146- aOut << lFName << "#" << lArity << " <" << lName.ns() << "> " << std::endl;
147- aOut << lFileName << " at line " << it->getLine() << " column " << it->getColumn() << std::endl;
148- }
149- }
150- if (aAsXml) {
151- if (aIndent) aOut << std::endl << " ";
152- aOut << "</stack>";
153- }
154- }
155- return aOut;
156- }
157-
158- std::ostream&
159- ErrorPrinter::print(
160- const XQueryException& aException,
161- std::ostream& aOut,
162- bool aAsXml,
163- bool aIndent)
164- {
165- if (!aAsXml) {
166- aOut << aException << " ";
167- aOut << std::endl;
168- print_stack_trace(aException, aOut, aAsXml, aIndent);
169- } else {
170- aOut << "<errors>";
171- if (aIndent) aOut << std::endl << " ";
172- //code
173- aOut << "<error code='" << aException.diagnostic().qname() << "'>";
174- if (aIndent) aOut << std::endl << " ";
175- //location
176- aOut << "<location module='" << aException.source_uri();
177- aOut << "' lineStart='" << aException.source_line();
178- aOut << "' columnStart='" << aException.source_column() << "'";
179- if (aException.source_line_end())
180- aOut << " lineEnd='" << aException.source_line_end() << "'";
181- if (aException.source_column_end())
182- aOut << " columnEnd='" << aException.source_column_end() << "'";
183- aOut << "/>";
184- if (aIndent) aOut << std::endl << " ";
185- //description
186- aOut << "<description>" << aException.what() << "</description>";
187- if( aIndent ) aOut << std::endl << " ";
188- print_stack_trace(aException, aOut, aAsXml, aIndent);
189- if (aIndent) aOut << std::endl << " ";
190- aOut << "</error>";
191- if (aIndent) aOut << std::endl;
192- aOut << "</errors>";
193- }
194- return aOut;
195- }
196-
197-} // namespace zorba
198
199=== removed file 'bin/error_printer.h'
200--- bin/error_printer.h 2012-09-19 21:16:15 +0000
201+++ bin/error_printer.h 1970-01-01 00:00:00 +0000
202@@ -1,40 +0,0 @@
203-/*
204- * Copyright 2006-2008 The FLWOR Foundation.
205- *
206- * Licensed under the Apache License, Version 2.0 (the "License");
207- * you may not use this file except in compliance with the License.
208- * You may obtain a copy of the License at
209- *
210- * http://www.apache.org/licenses/LICENSE-2.0
211- *
212- * Unless required by applicable law or agreed to in writing, software
213- * distributed under the License is distributed on an "AS IS" BASIS,
214- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
215- * See the License for the specific language governing permissions and
216- * limitations under the License.
217- */
218-#ifndef ZORBA_ERROR_PRINTER_H
219-#define ZORBA_ERROR_PRINTER_H
220-
221-#include <ostream>
222-
223-namespace zorba {
224-
225-class XQueryException;
226-
227-class ErrorPrinter {
228-
229- public:
230-
231- static std::ostream&
232- print(
233- const XQueryException& lException,
234- std::ostream& lOut,
235- bool aAsXml,
236- bool aIndent);
237-
238-}; /* class ErrorPrinter */
239-
240-} /* namespace zorba */
241-
242-#endif //ZORBA_ERROR_PRINTER_H
243
244=== modified file 'bin/zorbacmd.cpp'
245--- bin/zorbacmd.cpp 2013-01-24 02:27:45 +0000
246+++ bin/zorbacmd.cpp 2013-02-07 01:30:37 +0000
247@@ -51,7 +51,6 @@
248 #include <zorba/audit_scoped.h>
249 #endif
250
251-#include "error_printer.h"
252 #include "util.h"
253 #include "path_util.h"
254
255@@ -103,6 +102,23 @@
256
257 URIMapperSerializationCallback theSerializationCallback;
258
259+/*******************************************************************************
260+
261+********************************************************************************/
262+static void print_exception( ZorbaException const &e,
263+ ZorbaCMDProperties const &props ) {
264+ using namespace std;
265+
266+ if ( props.printErrorsAsXml() )
267+ if ( props.indent() )
268+ cerr << ZorbaException::format_xml_indented;
269+ else
270+ cerr << ZorbaException::format_xml;
271+ else
272+ cerr << ZorbaException::format_text;
273+
274+ cerr << e << endl;
275+}
276
277 /*******************************************************************************
278
279@@ -779,7 +795,7 @@
280 }
281 catch (zorba::XQueryException const& qe)
282 {
283- ErrorPrinter::print(qe, std::cerr, properties.printErrorsAsXml(), lIndent);
284+ print_exception( qe, properties );
285 return 11;
286 }
287 catch (zorba::ZorbaException const& ze)
288@@ -830,7 +846,7 @@
289 }
290 catch (zorba::XQueryException const& qe)
291 {
292- ErrorPrinter::print(qe, std::cerr, properties.printErrorsAsXml(), lIndent);
293+ print_exception( qe, properties );
294 return 22;
295 }
296 catch (zorba::ZorbaException const& ze)
297@@ -872,7 +888,7 @@
298 }
299 catch (zorba::XQueryException const& qe)
300 {
301- ErrorPrinter::print(qe, std::cerr, properties.printErrorsAsXml(), lIndent);
302+ print_exception( qe, properties );
303 return 31;
304 }
305 catch (zorba::ZorbaException const& ze)
306@@ -1169,10 +1185,7 @@
307 }
308 catch (zorba::XQueryException const& qe)
309 {
310- ErrorPrinter::print(qe,
311- std::cerr,
312- properties.printErrorsAsXml(),
313- properties.indent());
314+ print_exception( qe, properties );
315 return 6;
316 }
317 }
318@@ -1258,10 +1271,7 @@
319 }
320 catch (zorba::XQueryException const& qe)
321 {
322- ErrorPrinter::print(qe,
323- std::cerr,
324- properties.printErrorsAsXml(),
325- properties.indent());
326+ print_exception( qe, properties );
327 return 5;
328 }
329 catch (zorba::ZorbaException const& ze)
330@@ -1303,3 +1313,4 @@
331 }
332 return 0;
333 }
334+/* vim:set et sw=2 ts=2: */
335
336=== modified file 'doc/cxx/examples/errors.cpp'
337--- doc/cxx/examples/errors.cpp 2012-09-19 21:16:15 +0000
338+++ doc/cxx/examples/errors.cpp 2013-02-07 01:30:37 +0000
339@@ -157,6 +157,32 @@
340 return false;
341 }
342
343+bool
344+error_example_7(Zorba* aZorba)
345+{
346+ try {
347+ std::ostringstream s;
348+ s << "declare function local:test() { fn:error() };" << std::endl
349+ << "local:test()" << std::endl;
350+ XQuery_t lQuery = aZorba->compileQuery(s.str());
351+
352+ std::cout << lQuery << std::endl;
353+ } catch (ZorbaException const& ze) {
354+ std::cerr << "=== Error XML + Stacktrace ===" << std::endl;
355+ std::cerr << XQueryException::trace
356+ << ZorbaException::format_xml
357+ << ze
358+ << std::endl;
359+ std::cerr << "=== Error Text + Stacktrace ===" << std::endl;
360+ std::cerr << XQueryException::trace
361+ << ZorbaException::format_text
362+ << ze
363+ << std::endl;
364+ return true;
365+ }
366+ return false;
367+}
368+
369 int
370 errors(int argc, char* argv[])
371 {
372@@ -194,6 +220,11 @@
373 if (!res) return 1;
374 std::cout << std::endl;
375
376+ std::cout << "executing example 7" << std::endl;
377+ res = error_example_7(lZorba);
378+ if (!res) return 1;
379+ std::cout << std::endl;
380+
381 lZorba->shutdown();
382 zorba::StoreManager::shutdownStore(lStore);
383 return 0;
384
385=== modified file 'include/zorba/xquery_exception.h'
386--- include/zorba/xquery_exception.h 2012-12-01 00:06:15 +0000
387+++ include/zorba/xquery_exception.h 2013-02-07 01:30:37 +0000
388@@ -39,6 +39,15 @@
389 typedef internal::diagnostic::location::column_type column_type;
390
391 /**
392+ * Whether to include the XQuery stack trace for the XQueryException that's
393+ * printed to an ostream.
394+ */
395+ enum print_trace {
396+ trace,
397+ no_trace
398+ };
399+
400+ /**
401 * Copy-constructs an %XQueryException.
402 *
403 * @param from The %XQueryException to copy from.
404@@ -208,6 +217,17 @@
405 ////////// XQuery stack trace ///////////////////////////////////////////////
406
407 /**
408+ * Gets whether XQuery stack traces will be included when XQueryExceptions
409+ * are printed to the given ostream.
410+ *
411+ * @param o The ostream.
412+ * @return Returns \a true only if stack traces will be included.
413+ */
414+ static bool get_print_trace( std::ostream &o ) {
415+ return static_cast<print_trace>( o.iword( get_ios_trace_index() ) );
416+ }
417+
418+ /**
419 * Gets the XQuery stack trace, if any.
420 *
421 * @return Returns said stack trace.
422@@ -225,13 +245,29 @@
423 return query_trace_;
424 }
425
426+ /**
427+ * Sets whether XQuery stack traces will be included when XQueryExceptions
428+ * are printed to the given ostream.
429+ *
430+ * @param o The ostream to affect.
431+ * @param print If \a true, stack traces will be included.
432+ */
433+ static void set_print_trace( std::ostream &o, bool print ) {
434+ o.iword( get_ios_trace_index() ) = print;
435+ }
436+
437+ /////////////////////////////////////////////////////////////////////////////
438+
439 // inherited
440 void polymorphic_throw() const;
441
442 protected:
443+ std::ostream& print_stack_trace( std::ostream& ) const;
444+ static bool print_uri( std::ostream&, char const *uri );
445+
446 // inherited
447 std::unique_ptr<ZorbaException> clone() const;
448- std::ostream& print( std::ostream &o ) const;
449+ std::ostream& print_impl( std::ostream& ) const;
450
451 private:
452 typedef internal::diagnostic::location location;
453@@ -254,6 +290,8 @@
454 location applied_loc_;
455 XQueryStackTrace query_trace_;
456
457+ static int get_ios_trace_index();
458+
459 friend XQueryException make_xquery_exception(
460 char const*, ZorbaException::line_type, Diagnostic const&,
461 parameters const&, location const&
462@@ -281,6 +319,22 @@
463
464 ///////////////////////////////////////////////////////////////////////////////
465
466+/**
467+ * Sets whether to include the XQuery stack trace for the next XQueryException
468+ * that's printed.
469+ *
470+ * @param o The ostream to affect.
471+ * @param t The print_trace value.
472+ * @return Returns \a o.
473+ */
474+inline std::ostream& operator<<( std::ostream &o,
475+ XQueryException::print_trace t ) {
476+ XQueryException::set_print_trace( o, t );
477+ return o;
478+}
479+
480+///////////////////////////////////////////////////////////////////////////////
481+
482 } // namespace zorba
483 #endif /* ZORBA_XQUERY_EXCEPTION_API_H */
484 /* vim:set et sw=2 ts=2: */
485
486=== modified file 'include/zorba/xquery_stack_trace.h'
487--- include/zorba/xquery_stack_trace.h 2012-09-19 21:16:15 +0000
488+++ include/zorba/xquery_stack_trace.h 2013-02-07 01:30:37 +0000
489@@ -44,13 +44,13 @@
490 public:
491 Entry( fn_name_type const &fn_name, fn_arity_type fn_arity,
492 char const *file_name, line_type line, column_type column,
493- line_type line_end, column_type column_end);
494+ line_type line_end, column_type column_end );
495
496 fn_name_type const& getFnName() const {
497 return fn_name_;
498 }
499
500- fn_arity_type const& getFnArity() const {
501+ fn_arity_type getFnArity() const {
502 return fn_arity_;
503 }
504
505@@ -74,7 +74,7 @@
506 return col_end_;
507 }
508
509- fn_name_type& getFnNameRef() {
510+ fn_name_type& getFnNameRef() {
511 return fn_name_;
512 }
513
514
515=== modified file 'include/zorba/zorba_exception.h'
516--- include/zorba/zorba_exception.h 2012-09-19 21:16:15 +0000
517+++ include/zorba/zorba_exception.h 2013-02-07 01:30:37 +0000
518@@ -44,6 +44,15 @@
519 typedef internal::diagnostic::location::line_type line_type;
520
521 /**
522+ * The format to print exceptions as to an ostream.
523+ */
524+ enum print_format {
525+ format_text = 0, ///< plain text
526+ format_xml = 1, ///< XML without unnecessary whitespace
527+ format_xml_indented = 3 ///< XML with newlines and indentation
528+ };
529+
530+ /**
531 * Copy-constructs a %ZorbaException.
532 *
533 * @param from The %ZorbaException to copy from.
534@@ -73,6 +82,16 @@
535 }
536
537 /**
538+ * Gets the current print_format associated with the given ostream.
539+ *
540+ * @param o The ostream to get the print_format of.
541+ * @return Returns said print_format.
542+ */
543+ static print_format get_print_format( std::ostream &o ) {
544+ return static_cast<print_format>( o.iword( get_ios_format_index() ) );
545+ }
546+
547+ /**
548 * Throws itself polymorphically; see
549 * http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.16
550 */
551@@ -105,6 +124,16 @@
552 return raise_line_;
553 }
554
555+ /**
556+ * Sets the print_format of the given ostream.
557+ *
558+ * @param o The ostream to set the print_format of.
559+ * @param f The print_format value.
560+ */
561+ static void set_print_format( std::ostream &o, print_format f ) {
562+ o.iword( get_ios_format_index() ) = static_cast<long>( f );
563+ }
564+
565 // inherited
566 char const* what() const throw();
567
568@@ -135,9 +164,9 @@
569 * @param o The ostream to print to.
570 * @return Returns \a o.
571 */
572- virtual std::ostream& print( std::ostream &o ) const;
573+ std::ostream& print( std::ostream& ) const;
574
575- friend std::ostream& operator<<( std::ostream&, ZorbaException const& );
576+ virtual std::ostream& print_impl( std::ostream &o ) const;
577
578 private:
579 Diagnostic const *diagnostic_;
580@@ -145,6 +174,8 @@
581 line_type raise_line_;
582 std::string message_;
583
584+ static int get_ios_format_index();
585+
586 friend std::unique_ptr<ZorbaException> clone( ZorbaException const& );
587
588 friend ZorbaException make_zorba_exception(
589@@ -157,6 +188,8 @@
590 internal::diagnostic::parameters const&
591 );
592
593+ friend std::ostream& operator<<( std::ostream&, ZorbaException const& );
594+
595 protected:
596 // for plan serialization
597 ZorbaException( serialization::Archiver& );
598@@ -164,6 +197,8 @@
599 ZorbaException*& );
600 };
601
602+///////////////////////////////////////////////////////////////////////////////
603+
604 /**
605 * Emits the given ZorbaException to the given ostream.
606 *
607@@ -175,6 +210,19 @@
608 return e.print( o );
609 }
610
611+/**
612+ * Sets the format for the next ZorbaException that's printed.
613+ *
614+ * @param o The ostream to affect.
615+ * @param f The print_format to use.
616+ * @return Returns \a o.
617+ */
618+inline std::ostream& operator<<( std::ostream &o,
619+ ZorbaException::print_format f ) {
620+ ZorbaException::set_print_format( o, f );
621+ return o;
622+}
623+
624 ///////////////////////////////////////////////////////////////////////////////
625
626 } // namespace zorba
627
628=== modified file 'src/diagnostics/xquery_exception.cpp'
629--- src/diagnostics/xquery_exception.cpp 2012-12-02 17:24:18 +0000
630+++ src/diagnostics/xquery_exception.cpp 2013-02-07 01:30:37 +0000
631@@ -19,14 +19,29 @@
632 // standard
633 #include <cstring>
634
635+// API
636+#include <zorba/xquery_stack_trace.h>
637+#include <zorba/util/uri.h>
638+#include <zorba/xquery_functions.h>
639+
640 // Zorba
641+#include "util/ascii_util.h"
642 #include "util/fs_util.h"
643+#include "util/indent.h"
644+#include "util/omanip.h"
645 #include "util/uri_util.h"
646+#include "zorbatypes/URI.h"
647
648 // local
649 #include "dict.h"
650 #include "xquery_exception.h"
651
652+#define if_inc_indent if_do( do_indent, inc_indent )
653+#define if_dec_indent if_do( do_indent, dec_indent )
654+
655+#undef if_nl
656+#define if_nl if_emit( do_indent, '\n' )
657+
658 using namespace std;
659
660 namespace zorba {
661@@ -77,6 +92,11 @@
662 return unique_ptr<ZorbaException>( new XQueryException( *this ) );
663 }
664
665+int XQueryException::get_ios_trace_index() {
666+ static int const index = ios_base::xalloc();
667+ return index;
668+}
669+
670 void XQueryException::set_applied( char const *uri,
671 line_type line,
672 column_type col,
673@@ -99,13 +119,159 @@
674 throw *this;
675 }
676
677-static bool print_uri( ostream &o, char const *uri ) {
678+ostream& XQueryException::print_impl( ostream &o ) const {
679+ print_format const format = get_print_format( o );
680+ bool const as_xml = format != format_text;
681+ bool const do_indent = format == format_xml_indented;
682+
683+ if ( as_xml ) {
684+ ZorbaException::print_impl( o );
685+ if ( has_source() ) {
686+ o << indent << "<location";
687+ print_uri( o, source_uri() );
688+#if 0
689+ o << " line-begin=\"" << source_line() << '"';
690+ if ( source_line_end() )
691+ o << " line-end=\"" << source_line_end() << '"';
692+ if ( source_column() )
693+ o << " column-begin=\"" << source_column() << '"';
694+ if ( source_column_end() )
695+ o << " column-end=\"" << source_column_end() << '"';
696+#else
697+ o << " lineStart=\"" << source_line() << '"';
698+ if ( source_column() )
699+ o << " columnStart=\"" << source_column() << '"';
700+ if ( source_line_end() )
701+ o << " lineEnd=\"" << source_line_end() << '"';
702+ if ( source_column_end() )
703+ o << " columnEnd=\"" << source_column_end() << '"';
704+#endif
705+ o << "/>" << if_nl; // <location ...
706+
707+ if ( has_applied() ) {
708+ o << indent << "<applied-at";
709+ if ( applied_uri() && ::strcmp( applied_uri(), source_uri() ) != 0 )
710+ print_uri( o, applied_uri() );
711+ o << " line=\"" << applied_line() << '"';
712+ if ( applied_column() )
713+ o << " column=\"" << applied_column() << '"';
714+ o << "/>" << if_nl; // <applied-at ...
715+ }
716+
717+ if ( get_print_trace( o ) )
718+ print_stack_trace( o );
719+ }
720+ return o;
721+ } else {
722+ if ( has_source() ) {
723+ if ( !print_uri( o, source_uri() ) )
724+ o << "(" << diagnostic::dict::lookup( ZED( NoSourceURI ) ) << ")";
725+ o << ":" << source_line();
726+ if ( source_column() )
727+ o << "," << source_column();
728+
729+ if ( has_applied() ) {
730+ o << " (" << diagnostic::dict::lookup( ZED( AppliedAt ) ) << ' ';
731+ if ( applied_uri() && ::strcmp( applied_uri(), source_uri() ) != 0 ) {
732+ if ( print_uri( o, applied_uri() ) )
733+ o << ':';
734+ }
735+ o << applied_line();
736+ if ( applied_column() )
737+ o << ',' << applied_column();
738+ o << ')';
739+ }
740+
741+ o << ": ";
742+ }
743+ return ZorbaException::print_impl( o );
744+ }
745+}
746+
747+ostream& XQueryException::print_stack_trace( ostream &o ) const {
748+ XQueryStackTrace const &trace = query_trace();
749+ if ( !trace.empty() ) {
750+ print_format const format = get_print_format( o );
751+ bool const as_xml = format != format_text;
752+ bool const do_indent = format == format_xml_indented;
753+
754+ if ( as_xml )
755+ o << indent << "<stack>" << if_nl << if_inc_indent;
756+ FOR_EACH( XQueryStackTrace, it, trace ) {
757+ XQueryStackTrace::fn_name_type const &fn_name = it->getFnName();
758+ char const *const fn_prefix = fn_name.prefix();
759+ XQueryStackTrace::fn_arity_type fn_arity = it->getFnArity();
760+
761+ zstring filename( it->getFileName() );
762+ if ( ascii::begins_with( filename, "file:" ) ) {
763+ URI::decode_file_URI( filename, filename );
764+ while ( ascii::begins_with( filename, "//" ) )
765+ filename = filename.substr(1);
766+ }
767+
768+ if ( as_xml ) {
769+ o << indent << "<call";
770+ if ( fn_prefix && *fn_prefix )
771+ o << " prefix=\"" << fn_prefix << '"';
772+
773+#if 0
774+ o << " namespace=\"" << fn_name.ns() << '"'
775+ << " local-name=\"" << fn_name.localname()
776+ << " arity=\"" << fn_arity << '"'
777+ << "\">" << if_nl; // <call ...
778+
779+ o << if_inc_indent << indent << "<location uri=\"" << filename << '"';
780+
781+ o << " line-begin=\"" << it->getLine() << '"';
782+ if ( it->getLineEnd() )
783+ o << " line-end=\"" << it->getLineEnd() << '"';
784+
785+ o << " column-begin=\"" << it->getColumn() << '"';
786+ if ( it->getColumnEnd() )
787+ o << " column-end=\"" << it->getColumnEnd() << '"';
788+#else
789+ o << " ns=\"" << fn_name.ns() << '"'
790+ << " localName=\"" << fn_name.localname()
791+ << " arity=\"" << fn_arity << '"'
792+ << "\">" << if_nl; // <call ...
793+
794+ o << if_inc_indent << indent << "<location fileName=\"" << filename << '"';
795+
796+ o << " lineStart=\"" << it->getLine() << '"';
797+ o << " columnStart=\"" << it->getColumn() << '"';
798+
799+ if ( it->getLineEnd() )
800+ o << " lineEnd=\"" << it->getLineEnd() << '"';
801+ if ( it->getColumnEnd() )
802+ o << " columnEnd=\"" << it->getColumnEnd() << '"';
803+#endif
804+
805+ o << "/>" << if_nl // <location ...
806+ << if_dec_indent << "</call>" << if_nl;
807+ } else {
808+ o << fn_name << '#' << fn_arity
809+ << " <" << fn_name.ns() << "> "
810+ << '"' << filename << "\":"
811+ << it->getLine() << ',' << it->getColumn()
812+ << '\n';
813+ }
814+ } // FOR_EACH
815+ if ( as_xml )
816+ o << indent << "</stack>" << if_nl << if_dec_indent;
817+ }
818+ return o;
819+}
820+
821+bool XQueryException::print_uri( ostream &o, char const *uri ) {
822 if ( uri && *uri ) {
823+ bool const as_xml = get_print_format( o ) != format_text;
824 switch ( uri::get_scheme( uri ) ) {
825 case uri::none:
826 case uri::file:
827 try {
828- o << '<' << fs::get_normalized_path( uri ) << '>';
829+ o << (as_xml ? " uri=\"" : "<")
830+ << fs::get_normalized_path( uri )
831+ << (as_xml ? '"' : '>');
832 break;
833 }
834 catch ( ... ) {
835@@ -113,38 +279,13 @@
836 }
837 // no break;
838 default:
839- o << '<' << uri << '>';
840- }
841+ o << (as_xml ? " uri=\"" : "<" ) << uri << (as_xml ? '"' : '>');
842+ } // switch
843 return true;
844- }
845+ } // if
846 return false;
847 }
848
849-ostream& XQueryException::print( ostream &o ) const {
850- if ( has_source() ) {
851- if ( !print_uri( o, source_uri() ) )
852- o << '(' << diagnostic::dict::lookup( ZED( NoSourceURI ) ) << ')';
853- o << ':' << source_line();
854- if ( source_column() )
855- o << ',' << source_column();
856-
857- if ( has_applied() ) {
858- o << " (" << diagnostic::dict::lookup( ZED( AppliedAt ) ) << ' ';
859- if ( applied_uri() && ::strcmp( applied_uri(), source_uri() ) != 0 ) {
860- if ( print_uri( o, applied_uri() ) )
861- o << ':';
862- }
863- o << applied_line();
864- if ( applied_column() )
865- o << ',' << applied_column();
866- o << ')';
867- }
868-
869- o << ": ";
870- }
871- return ZorbaException::print( o );
872-}
873-
874 ///////////////////////////////////////////////////////////////////////////////
875
876 XQueryException
877
878=== modified file 'src/diagnostics/zorba_exception.cpp'
879--- src/diagnostics/zorba_exception.cpp 2012-09-19 21:16:15 +0000
880+++ src/diagnostics/zorba_exception.cpp 2013-02-07 01:30:37 +0000
881@@ -20,6 +20,10 @@
882 #include <zorba/zorba_exception.h>
883 #include <zorba/xquery_warning.h>
884
885+#include "util/indent.h"
886+#include "util/omanip.h"
887+#include "zorbamisc/ns_consts.h"
888+
889 #include "dict.h"
890
891 #ifndef NDEBUG
892@@ -27,12 +31,24 @@
893 ZORBA_DLL_PUBLIC bool g_abort_on_error;
894 #endif /* NDEBUG */
895
896+#define if_inc_indent if_do( do_indent, inc_indent )
897+#define if_dec_indent if_do( do_indent, dec_indent )
898+
899+#undef if_nl
900+#define if_nl if_emit( do_indent, '\n' )
901+
902 using namespace std;
903
904 namespace zorba {
905
906 ///////////////////////////////////////////////////////////////////////////////
907
908+inline bool is_warning( Diagnostic const &d ) {
909+ return !!dynamic_cast<ZorbaWarningCode const*>( &d );
910+}
911+
912+///////////////////////////////////////////////////////////////////////////////
913+
914 ZorbaException::ZorbaException( Diagnostic const &diagnostic,
915 char const *raise_file, line_type raise_line,
916 char const *message ) :
917@@ -56,7 +72,7 @@
918 {
919 }
920
921-ZorbaException::ZorbaException( serialization::Archiver &ar )
922+ZorbaException::ZorbaException( serialization::Archiver& )
923 {
924 }
925
926@@ -80,40 +96,86 @@
927 return unique_ptr<ZorbaException>( new ZorbaException( *this ) );
928 }
929
930+int ZorbaException::get_ios_format_index() {
931+ static int const index = ios_base::xalloc();
932+ return index;
933+}
934+
935 void ZorbaException::polymorphic_throw() const {
936 throw *this;
937 }
938
939-ostream& ZorbaException::print( ostream &o ) const {
940- //
941- // We need to create an error phrase (e.g., "static error") and look that up
942- // as a unit rather than looking up the error kind word and "error"
943- // separately because many languages have the word order reversed (e.g.,
944- // "static error" becomes "erreur statique" in French).
945- //
946- ostringstream oss;
947- oss << ZED_PREFIX;
948+ostream& ZorbaException::print( ostream& o ) const {
949+ print_format const format = get_print_format( o );
950+ bool const as_xml = format != format_text;
951+ bool const do_indent = format == format_xml_indented;
952+ if ( as_xml ) {
953+ o << "<exception xmlns=\""
954+ << (is_warning( diagnostic() ) ? ZORBA_WARN_NS : ZORBA_ERR_NS)
955+ << "\">" << if_nl << if_inc_indent;
956+ }
957+ print_impl( o );
958+ if ( as_xml )
959+ o << if_dec_indent << "</exception>";
960+ return o;
961+}
962
963- streampos pos = oss.tellp();
964+ostream& ZorbaException::print_impl( ostream &o ) const {
965 Diagnostic const &d = diagnostic();
966- oss << d.category();
967- if ( oss.tellp() != pos ) // emit ' ' only if non-empty category
968- oss << ' ';
969-
970- if ( diagnostic::kind const k = d.kind() )
971- oss << k << ' ';
972-
973- oss << (dynamic_cast<ZorbaWarningCode const*>( &d ) ? "warning" : "error");
974-
975- o << diagnostic::dict::lookup( oss.str() ) << " [" << d.qname() << ']';
976+ print_format const format = get_print_format( o );
977+ bool const as_xml = format != format_text;
978+ bool const do_indent = format == format_xml_indented;
979+
980+ if ( as_xml ) {
981+ diagnostic::QName const &q = d.qname();
982+#if 0
983+ o << indent << "<kind>" << d.kind() << "</kind>" << if_nl
984+ << indent << "<code namespace=\"" << q.ns()
985+ << "\" local-name=\"" << q.localname() << "\"/>"
986+#else
987+ o << indent << "<kind>" << d.kind() << ' '
988+ << (is_warning( d ) ? "warning" : "error") << "</kind>" << if_nl
989+ << indent << "<code>" << q << "</code>"
990+#endif
991+ << if_nl;
992+ } else {
993+ //
994+ // We need to create an error phrase (e.g., "static error") and look that
995+ // up as a unit rather than looking up the error kind word and "error"
996+ // separately because many languages have the word order reversed (e.g.,
997+ // "static error" becomes "erreur statique" in French).
998+ //
999+ ostringstream oss;
1000+ oss << ZED_PREFIX;
1001+
1002+ streampos pos = oss.tellp();
1003+ oss << d.category();
1004+ if ( oss.tellp() != pos ) // emit ' ' only if non-empty category
1005+ oss << ' ';
1006+
1007+ if ( diagnostic::kind const k = d.kind() )
1008+ oss << k << ' ';
1009+
1010+ oss << (is_warning( d ) ? "warning" : "error");
1011+ o << diagnostic::dict::lookup( oss.str() ) << " [" << d.qname() << ']';
1012+ }
1013
1014 if ( char const *const w = what() )
1015- if ( *w )
1016- o << ": " << w;
1017+ if ( *w ) {
1018+ if ( as_xml )
1019+ o << indent << "<message>" << w << "</message>" << if_nl;
1020+ else
1021+ o << ": " << w;
1022+ }
1023
1024 #ifndef NDEBUG
1025- o << "; raised at " << raise_file() << ':' << raise_line();
1026+ if ( as_xml )
1027+ o << indent << "<raised-at file=\"" << raise_file()
1028+ << "\" line=\"" << raise_line() << "\"/>" << if_nl;
1029+ else
1030+ o << "; raised at " << raise_file() << ':' << raise_line();
1031 #endif
1032+
1033 return o;
1034 }
1035
1036
1037=== modified file 'src/runtime/json/common.h'
1038--- src/runtime/json/common.h 2012-09-19 21:16:15 +0000
1039+++ src/runtime/json/common.h 2013-02-07 01:30:37 +0000
1040@@ -49,34 +49,13 @@
1041 };
1042 }
1043
1044+#define if_indent(WS,FN) if_do( (WS) == whitespace::indent, FN )
1045+
1046 ///////////////////////////////////////////////////////////////////////////////
1047
1048 bool get_attribute_value( store::Item_t const &element, char const *att_name,
1049 zstring *att_value );
1050
1051-typedef std::ostream& (*std_omanip_type)(std::ostream&);
1052-
1053-inline std::ostream& if_do_impl( std::ostream &o, bool expr,
1054- std_omanip_type fn ) {
1055- if ( expr )
1056- o << fn;
1057- return o;
1058-}
1059-DEF_OMANIP2( if_do_impl, bool, std_omanip_type )
1060-// A macro with a !! is used to suppress a warning from MSVC++.
1061-#define if_do(EXPR,FN) if_do_impl( !!(EXPR), (FN) )
1062-
1063-#define if_indent(WS,FN) if_do( (WS) == whitespace::indent, FN )
1064-
1065-inline std::ostream& if_emit_impl( std::ostream &o, bool expr, char c ) {
1066- if ( expr )
1067- o << c;
1068- return o;
1069-}
1070-DEF_OMANIP2( if_emit_impl, bool, char )
1071-// A macro with a !! is used to suppress a warning from MSVC++.
1072-#define if_emit(EXPR,C) if_emit_impl( !!(EXPR), (C) )
1073-
1074 ///////////////////////////////////////////////////////////////////////////////
1075
1076 #define IN_STATE(S) ztd::top_stack_equals( state_stack, (S) )
1077
1078=== modified file 'src/util/fs_util.h'
1079--- src/util/fs_util.h 2013-01-24 02:27:45 +0000
1080+++ src/util/fs_util.h 2013-02-07 01:30:37 +0000
1081@@ -648,7 +648,7 @@
1082 char const* (PathStringType::*)() const>::value,
1083 zstring>::type
1084 get_normalized_path( PathStringType const &path,
1085- PathStringType const &base = "" ) {
1086+ PathStringType const &base = "" ) {
1087 return get_normalized_path( path.c_str(), base.c_str() );
1088 }
1089
1090
1091=== modified file 'src/util/omanip.h'
1092--- src/util/omanip.h 2012-09-19 21:16:15 +0000
1093+++ src/util/omanip.h 2013-02-07 01:30:37 +0000
1094@@ -298,6 +298,54 @@
1095
1096 ///////////////////////////////////////////////////////////////////////////////
1097
1098+/**
1099+ * A type for the standard, no-argument ostream manipulator.
1100+ */
1101+typedef std::ostream& (*std_omanip_type)(std::ostream&);
1102+
1103+/**
1104+ * Emits \a c to the given ostream only if \a expr is \c true.
1105+ *
1106+ * @param o The ostream to emit to.
1107+ * @param expr The boolean expression.
1108+ * @param c The character to emit only if \a expr is \c true.
1109+ * @return Returns \a o.
1110+ */
1111+inline std::ostream& if_emit_impl( std::ostream &o, bool expr, char c ) {
1112+ if ( expr )
1113+ o << c;
1114+ return o;
1115+}
1116+DEF_OMANIP2( if_emit_impl, bool, char )
1117+// A macro with a !! is used to suppress a warning from MSVC++.
1118+#define if_emit(EXPR,C) if_emit_impl( !!(EXPR), (C) )
1119+
1120+/**
1121+ * Emits a newline only if the given expression is \c true.
1122+ */
1123+#define if_nl(EXPR) if_emit( EXPR, '\n' )
1124+
1125+/**
1126+ * Calls the given manipulator function \a fn on the given ostream only if \a
1127+ * expr is \c true.
1128+ *
1129+ * @param o The ostream to emit to.
1130+ * @param expr The boolean expression.
1131+ * @param fn The manipulator function to call only if \a expr is \c true.
1132+ * @return Returns \a o.
1133+ */
1134+inline std::ostream& if_do_impl( std::ostream &o, bool expr,
1135+ std_omanip_type fn ) {
1136+ if ( expr )
1137+ o << fn;
1138+ return o;
1139+}
1140+DEF_OMANIP2( if_do_impl, bool, std_omanip_type )
1141+// A macro with a !! is used to suppress a warning from MSVC++.
1142+#define if_do(EXPR,FN) if_do_impl( !!(EXPR), (FN) )
1143+
1144+///////////////////////////////////////////////////////////////////////////////
1145+
1146 } // namespace zorba
1147
1148 #endif /* ZORBA_OMANIP_H */

Subscribers

People subscribed via source and target branches