BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balxml_errorinfo.h
Go to the documentation of this file.
1/// @file balxml_errorinfo.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balxml_errorinfo.h -*-C++-*-
8#ifndef INCLUDED_BALXML_ERRORINFO
9#define INCLUDED_BALXML_ERRORINFO
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balxml_errorinfo balxml_errorinfo
15/// @brief Provide common error information for XML components.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balxml
19/// @{
20/// @addtogroup balxml_errorinfo
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balxml_errorinfo-purpose"> Purpose</a>
25/// * <a href="#balxml_errorinfo-classes"> Classes </a>
26/// * <a href="#balxml_errorinfo-description"> Description </a>
27/// * <a href="#balxml_errorinfo-usage"> Usage </a>
28/// * <a href="#balxml_errorinfo-example-1-basic-usage"> Example 1: Basic Usage </a>
29///
30/// # Purpose {#balxml_errorinfo-purpose}
31/// Provide common error information for XML components.
32///
33/// # Classes {#balxml_errorinfo-classes}
34///
35/// - balxml::ErrorInfo: details of XML parsing errors
36///
37/// @see balxml_reader
38///
39/// # Description {#balxml_errorinfo-description}
40/// This component provides an in-core value-semantic class,
41/// `balxml::ErrorInfo`, that contains the following diagnostic information:
42/// @code
43/// - severity (WARNING, ERROR, FATAL ERROR)
44/// - line number
45/// - column number
46/// - document source (name of document containing the error)
47/// - error message (error description)
48/// @endcode
49/// Parsing components in the `baexml` package make use of `balxml::ErrorInfo`
50/// as a standard way to report errors and warnings back to the caller. The
51/// information contained within a `balxml::ErrorInfo` object is sufficient to
52/// report a single diagnostic in an input document.
53///
54/// ## Usage {#balxml_errorinfo-usage}
55///
56///
57/// This section illustrates intended use of this component.
58///
59/// ### Example 1: Basic Usage {#balxml_errorinfo-example-1-basic-usage}
60///
61///
62/// In this example, we create a parser for a simple file of percentages. The
63/// file is formatted as a sequence of lines, with each line containing a
64/// decimal number in the range "0" to "100", inclusive. Leading whitespace and
65/// blank lines are ignored. When an error occurs during parsing, the error
66/// data is stored in a `balxml::ErrorInfo` object. Our parser's interface is
67/// as follows:
68/// @code
69/// #include <balxml_errorinfo.h>
70/// #include <sstream>
71/// #include <cstdlib>
72/// #include <cstring>
73/// #include <climits>
74///
75/// class PercentParser {
76/// // Parse a document stream consisting of a sequence of integral
77/// // percentages (0 to 100) in decimal text format, one per line.
78///
79/// bsl::istream *d_input; // Input document stream
80/// bsl::string d_docName; // Document name
81/// int d_line; // Current line number
82///
83/// public:
84/// PercentParser(bsl::istream *input,
85/// const bsl::string& docName = "INPUT");
86/// // Construct a parser to parse the data in the specified 'input'
87/// // stream having the (optional) specified 'docName'. A valid
88/// // 'input' stream contains a sequence of integers in the range 0
89/// // to 100, one per line, in decimal text format. Each line may
90/// // contain leading but not trailing tabs and spaces. Characters
91/// // after the 20th character on each line are ignored and will
92/// // generate a warning.
93///
94/// int parseNext(balxml::ErrorInfo *errorInfo);
95/// // Read and parse the next percentage in the input stream and
96/// // return the percentage or -1 on eof or -2 on error. Set the
97/// // value of the specified 'errorInfo' structure on error or
98/// // warning and leave it unchanged otherwise. Do nothing and
99/// // return -2 if 'errorInfo->severity()' >= 'BAEXML_ERROR'.
100/// };
101/// @endcode
102/// The constructor is straight-forward:
103/// @code
104/// PercentParser::PercentParser(bsl::istream *input,
105/// const bsl::string& docName)
106/// : d_input(input), d_docName(docName), d_line(0)
107/// {
108/// }
109/// @endcode
110/// The `parseNext` function begins by testing if a previous error occurred. By
111/// testing this condition, we can call `parseNext` several times, knowing that
112/// the first error will stop the parse operation.
113/// @code
114/// int PercentParser::parseNext(balxml::ErrorInfo *errorInfo)
115/// {
116/// static const int MAX_LINE = 20;
117///
118/// if (errorInfo->isAnyError()) {
119/// // Don't advance if errorInfo shows a previous error.
120/// return -2;
121/// }
122/// @endcode
123/// The parser skips leading whitespace and lines containing only whitespace.
124/// It loops until a non-empty line is found:
125/// @code
126/// char buffer[MAX_LINE + 1];
127/// buffer[0] = '\0';
128///
129/// // Skip empty lines empty line
130/// int len = 0;
131/// int startColumn = 0;
132/// while (startColumn == len) {
133/// ++d_line;
134/// d_input->getline(buffer, MAX_LINE + 1, '\n');
135/// len = bsl::strlen(buffer);
136/// @endcode
137/// The input stream reports that the input line is longer than `MAX_LINE` by
138/// setting the fail() condition. In this case, we set the error object to a
139/// warning state, indicating the line and column where the problem occurred.
140/// Then we clear the stream condition and discard the rest of the line.
141/// @code
142/// if (MAX_LINE == len && d_input->fail()) {
143/// // 20 characters read without encountering newline.
144/// // Warn about long line and discard rest of line.
145/// errorInfo->setError(balxml::ErrorInfo::BAEXML_WARNING,
146/// d_line, len, d_docName,
147/// "Text after 20th column was discarded");
148/// d_input->clear();
149/// d_input->ignore(INT_MAX, '\n');
150/// }
151/// @endcode
152/// If we detect an EOF condition, we just return -1. Otherwise, we skip the
153/// leading whitespace and go on.
154/// @code
155/// else if (0 == len && d_input->eof()) {
156/// // Encountered eof before any other characters.
157/// return -1;
158/// }
159///
160/// // Skip leading whitespace
161/// startColumn = bsl::strspn(buffer, " \t");
162/// }
163///
164/// @endcode
165/// Now we perform two more error checks: one or superfluous characters after
166/// the integer, the other for an out-of-range integer. If the `errorInfo`
167/// object is already in warning state, either of these errors will overwrite
168/// the existing warning with the new error condition.
169/// @code
170/// char *endp = 0;
171/// long result = bsl::strtol(buffer + startColumn, &endp, 10);
172/// int endColumn = endp - buffer;
173/// if (endColumn < len) {
174/// // Conversion did not consume rest of buffer.
175/// errorInfo->setError(balxml::ErrorInfo::BAEXML_ERROR,
176/// d_line, endColumn + 1, d_docName,
177/// "Bad input character");
178/// return -2;
179/// } else if (result < 0 || 100 < result) {
180/// // Range error.
181/// errorInfo->setError(balxml::ErrorInfo::BAEXML_ERROR,
182/// d_line, startColumn + 1, d_docName,
183/// "Value is not between 0 and 100");
184/// return -2;
185/// }
186/// @endcode
187/// If there were no errors, return the result. Note that the `errorInfo`
188/// object may contain a warning, but warnings typically do not cause a change
189/// in the error value.
190/// @code
191/// return result;
192/// }
193/// @endcode
194/// The main program uses the `PercentParser` class to parse a list of values
195/// and compute the average. Typically, the data would be stored in a file,
196/// but we'll use a literal string for demonstration purposes:
197/// @code
198/// int main()
199/// {
200/// static const char INPUTS[] =
201/// " 20\n" // OK
202/// " 30\n" // Warning ('0' truncated)
203/// " \n" // Skipped: empty line
204/// "99x\n" // Error: bad character
205/// " 101\n" // Error: out of range
206/// " 1010\n"; // Out-of-range overrides warning
207/// @endcode
208/// We convert the string into a stream and initialize the parser. We name our
209/// input stream "Inputs" for the purpose of error handling. We also
210/// initialize our working variables:
211/// @code
212/// bsl::istringstream inputstream(INPUTS);
213/// PercentParser parser(&inputstream, "Inputs");
214/// int result;
215/// int sum = 0;
216/// int numValues = 0;
217/// @endcode
218/// Any error in parsing will be stored in the `errorInfo` object. When first
219/// constructed, it has a severity of `BAEXML_NO_ERROR`.
220/// @code
221/// balxml::ErrorInfo errorInfo;
222/// assert(errorInfo.isNoError());
223/// @endcode
224/// Normally, parsing would proceed in a loop. However, to illustrate the
225/// different error-handling situations, we have unrolled the loop below.
226///
227/// The first parse succeeds, and no error is reported:
228/// @code
229/// result = parser.parseNext(&errorInfo);
230/// assert(20 == result);
231/// assert(errorInfo.isNoError());
232/// sum += result;
233/// ++numValues;
234/// @endcode
235/// The next parse also succeeds but, because the input line was very long, a
236/// warning was generated:
237/// @code
238/// result = parser.parseNext(&errorInfo);
239/// assert(3 == result); // Truncated at 20th column
240/// assert(errorInfo.isWarning());
241/// assert(2 == errorInfo.lineNumber());
242/// assert(20 == errorInfo.columnNumber());
243/// assert("Text after 20th column was discarded" == errorInfo.message());
244/// sum += result;
245/// ++numValues;
246/// @endcode
247/// After resetting the `errorInfo` object, the we call `nextParse` again. This
248/// time it fails with an error. The line, column, and source of the error are
249/// reported in the object.
250/// @code
251/// errorInfo.reset();
252/// result = parser.parseNext(&errorInfo);
253/// assert(-2 == result);
254/// assert("Inputs" == errorInfo.source());
255/// assert(errorInfo.isError());
256/// assert(4 == errorInfo.lineNumber());
257/// assert(3 == errorInfo.columnNumber());
258/// assert("Bad input character" == errorInfo.message());
259/// @endcode
260/// If the `errorInfo` object is not reset, calling `parseNext` becomes a
261/// no-op:
262/// @code
263/// result = parser.parseNext(&errorInfo);
264/// assert(-2 == result);
265/// assert(errorInfo.isError());
266/// assert(4 == errorInfo.lineNumber());
267/// assert(3 == errorInfo.columnNumber());
268/// assert("Bad input character" == errorInfo.message());
269/// @endcode
270/// After calling `reset`, the next call to `parseNext` produces a different
271/// error message:
272/// @code
273/// errorInfo.reset();
274/// result = parser.parseNext(&errorInfo);
275/// assert(-2 == result);
276/// assert(errorInfo.isError());
277/// assert(5 == errorInfo.lineNumber());
278/// assert(6 == errorInfo.columnNumber());
279/// assert("Value is not between 0 and 100" == errorInfo.message());
280/// @endcode
281/// The last line of the file contains two problems: a long line, which would
282/// produce a warning, and a range error, which would produce an error. The
283/// warning message is overwritten by the error message because the error has a
284/// higher severity. Therefore, on return from `parseNext`, only the error
285/// message is stored in `errorInfo` and the warning is lost:
286/// @code
287/// errorInfo.reset();
288/// result = parser.parseNext(&errorInfo);
289/// assert(-2 == result);
290/// assert(errorInfo.isError());
291/// assert(6 == errorInfo.lineNumber());
292/// assert(18 == errorInfo.columnNumber());
293/// assert("Value is not between 0 and 100" == errorInfo.message());
294/// @endcode
295/// Writing the `errorInfo` object to a log or file will produce a readable
296/// error message:
297/// @code
298/// bsl::cerr << errorInfo << bsl::endl;
299/// @endcode
300/// The resulting message to standard error looks as follows:
301/// @code
302/// Inputs:6.18: Error: Value is not between 0 and 100
303/// @endcode
304/// Finally, we reach the end of the input stream and can compute our average.
305/// @code
306/// errorInfo.reset();
307/// result = parser.parseNext(&errorInfo);
308/// assert(-1 == result);
309/// assert(errorInfo.isNoError());
310///
311/// int average = sum / numValues;
312/// assert(11 == average); // (20 + 3) / 2
313///
314/// return 0;
315/// }
316/// @endcode
317/// @}
318/** @} */
319/** @} */
320
321/** @addtogroup bal
322 * @{
323 */
324/** @addtogroup balxml
325 * @{
326 */
327/** @addtogroup balxml_errorinfo
328 * @{
329 */
330
331#include <balscm_version.h>
332
333#include <bslma_allocator.h>
335
337
338#include <bsl_ostream.h>
339#include <bsl_string.h>
340
341
342namespace balxml {
343
344 // ===============
345 // class ErrorInfo
346 // ===============
347
348/// This class provides detailed information for errors encountered during
349/// XML parsing. Such information is common for most parsers and contains
350/// the following data: line number, column number, severity code,
351/// identification of source document and the parser error message.
353{
354
355 public:
356 // PUBLIC TYPES
358 {
359 // Error severity level. Each severity level is considered more severe
360 // than the one before. Client software will typically continue
361 // processing on 'BAEXML_WARNING' and will stop processing on
362 // 'BAEXML_ERROR' or 'BAEXML_FATAL_ERROR'. The distinction between the
363 // latter two severities is somewhat arbitrary. A component that sets
364 // the severity of a 'ErrorInfo' object can use 'BAEXML_FATAL_ERROR' to
365 // discard a less-severe error with 'BAEXML_ERROR'. As a general
366 // guideline, 'BAEXML_ERROR' means that processing could continue,
367 // albeit with compromised results and 'BAEXML_FATAL_ERROR' means that
368 // processing could not continue. For example, a constraint error
369 // would typically have 'BAEXML_ERROR' whereas a parsing (syntax) error
370 // would have 'BAEXML_FATAL_ERROR'.
375#ifndef BDE_OMIT_INTERNAL_DEPRECATED
380#endif // BDE_OMIT_INTERNAL_DEPRECATED
381 };
382
383 private:
384 // PRIVATE DATA MEMBERS
385 Severity d_severity;
386 int d_lineNumber;
387 int d_columnNumber;
388 bsl::string d_source;
389 bsl::string d_message;
390
391 public:
392 // TRAITS
394
395 // CREATORS
396
397 /// Construct an error info object using the (optionally) specified
398 /// `basicAllocator`, or the default allocator of none is specified.
399 /// After construction, `severity()` will return `BAEXML_NO_ERROR`,
400 /// `lineNumber()` and `columnNumber()` will each return 0, and
401 /// `source()` and `message()` will each return an empty string.
402 ErrorInfo(bslma::Allocator *basicAllocator = 0);
403
404 /// Construct a copy of the specified `other` object using the
405 /// (optionally) specified `basicAllocator`, or the default allocator
406 /// of none is specified.
407 ErrorInfo(const ErrorInfo& other, bslma::Allocator *basicAllocator = 0);
408
409 /// Destroy this object.
411
412 // MANIPULATORS
413
414 /// Copy the value of the specified `rhs` object into this object and
415 /// return a modifiable reference to this object.
417
418 /// If the specified `severity` is greater than the current value of
419 /// `this->severity()`, then set this object's severity to `severity`,
420 /// line number to the specified `lineNumber`, column number to the
421 /// specified `columnNumber`, source name to the specified `source`, and
422 /// error message to the specified `errorMsg`, otherwise do nothing.
424 int lineNumber,
425 int columnNumber,
427 const bsl::string_view& errorMsg);
428
429 /// If the severity of the specified `other` object is greater than the
430 /// current value of `this->severity()`, then assign this object the
431 /// value of `other`, otherwise do nothing.
432 void setError(const ErrorInfo& other);
433
434 /// Reset this object to initial state, as if it were default
435 /// constructed.
436 void reset();
437
438 // ACCESSORS
439
440 /// Return true if the `severity() == `BAEXML_NO_ERROR' and false
441 /// otherwise.
442 bool isNoError() const;
443
444 /// Return true if the `severity() == `BAEXML_WARNING' and false
445 /// otherwise.
446 bool isWarning() const;
447
448 /// Return true if the `severity() == `BAEXML_ERROR' and false
449 /// otherwise.
450 bool isError() const;
451
452 /// Return true if the `severity() == `BAEXML_FATAL_ERROR' and false
453 /// otherwise.
454 bool isFatalError() const;
455
456 /// Return true if the `severity() >= `BAEXML_ERROR' (i.e.,
457 /// `BAEXML_ERROR` or `BAEXML_FATAL_ERROR`) and false otherwise.
458 bool isAnyError() const;
459
460 /// Return the severity level.
461 Severity severity() const;
462
463 /// Return the line number of the warning or error. By convention, the
464 /// first line is numbered 1. The constructors and `reset` functions
465 /// set the line number to 0, since there is no error line to report.
466 int lineNumber() const;
467
468 /// Return the column number. By convention, the first column is
469 /// numbered 1. The constructors and `reset` functions set the column
470 /// number to 0, since there is no error column to report.
471 int columnNumber() const;
472
473 /// Return the string that identifies the document being parsed.
474 const bsl::string& source() const;
475
476 /// Return the string describing the error or warning.
477 const bsl::string& message() const;
478};
479
480// FREE OPERATORS
481
482/// Return true if the specified `lhs` object has the same value as the
483/// specified `rhs` object. The two objects have the same value if
484/// `severity()`, `lineNumber()`, `columnNumber()`, `source()`, and
485/// `message()` return equal values for both.
486bool operator==(const ErrorInfo& lhs, const ErrorInfo& rhs);
487
488/// Return true if the specified `lhs` object does not have the same value
489/// as the specified `rhs` object. The two objects have the same value if
490/// `severity()`, `lineNumber()`, `columnNumber()`, `source()`, and
491/// `message()` return equal values for both.
492inline
493bool operator!=(const ErrorInfo& lhs, const ErrorInfo& rhs);
494
495/// Print the specified `errInfo` object to the specified `stream` in
496/// human-readable form and return a modifiable reference to `stream`. The
497/// output is one-line without a terminating newline.
498bsl::ostream& operator<<(bsl::ostream& stream, const ErrorInfo& errInfo);
499
500// ============================================================================
501// INLINE DEFINITIONS
502// ============================================================================
503
504 // ---------------
505 // class ErrorInfo
506 // ---------------
507// MANIPULATORS
508inline void
510{
511 if (other.d_severity > d_severity) {
512 *this = other;
513 }
514}
515
516// ACCESSORS
519{
520 return d_severity;
521}
522
523inline bool
525{
526 return d_severity == e_NO_ERROR;
527}
528
529inline bool
531{
532 return d_severity == e_WARNING;
533}
534
535inline bool
537{
538 return d_severity == e_ERROR;
539}
540
541inline bool
543{
544 return d_severity == e_FATAL_ERROR;
545}
546
547inline bool
549{
550 return d_severity >= e_ERROR;
551}
552
553inline int
555{
556 return d_lineNumber;
557}
558
559inline int
561{
562 return d_columnNumber;
563}
564
565inline const bsl::string &
567{
568 return d_source;
569}
570
571inline const bsl::string &
573{
574 return d_message;
575}
576
577} // close package namespace
578
579// FREE OPERATORS
580inline
581bool balxml::operator!=(const ErrorInfo& lhs, const ErrorInfo& rhs)
582{
583 return ! (lhs == rhs);
584}
585
586
587
588#endif // INCLUDED_BALXML_ERRORINFO
589
590// ----------------------------------------------------------------------------
591// Copyright 2015 Bloomberg Finance L.P.
592//
593// Licensed under the Apache License, Version 2.0 (the "License");
594// you may not use this file except in compliance with the License.
595// You may obtain a copy of the License at
596//
597// http://www.apache.org/licenses/LICENSE-2.0
598//
599// Unless required by applicable law or agreed to in writing, software
600// distributed under the License is distributed on an "AS IS" BASIS,
601// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
602// See the License for the specific language governing permissions and
603// limitations under the License.
604// ----------------------------- END-OF-FILE ----------------------------------
605
606/** @} */
607/** @} */
608/** @} */
Definition balxml_errorinfo.h:353
Severity
Definition balxml_errorinfo.h:358
@ e_FATAL_ERROR
Definition balxml_errorinfo.h:374
@ e_WARNING
Definition balxml_errorinfo.h:372
@ e_ERROR
Definition balxml_errorinfo.h:373
@ BAEXML_NO_ERROR
Definition balxml_errorinfo.h:376
@ BAEXML_FATAL_ERROR
Definition balxml_errorinfo.h:379
@ e_NO_ERROR
Definition balxml_errorinfo.h:371
@ BAEXML_WARNING
Definition balxml_errorinfo.h:377
@ BAEXML_ERROR
Definition balxml_errorinfo.h:378
BSLMF_NESTED_TRAIT_DECLARATION(ErrorInfo, bslma::UsesBslmaAllocator)
bool isNoError() const
Definition balxml_errorinfo.h:524
const bsl::string & source() const
Return the string that identifies the document being parsed.
Definition balxml_errorinfo.h:566
ErrorInfo(bslma::Allocator *basicAllocator=0)
bool isWarning() const
Definition balxml_errorinfo.h:530
void setError(Severity severity, int lineNumber, int columnNumber, const bsl::string_view &source, const bsl::string_view &errorMsg)
bool isAnyError() const
Definition balxml_errorinfo.h:548
int columnNumber() const
Definition balxml_errorinfo.h:560
ErrorInfo & operator=(const ErrorInfo &rhs)
int lineNumber() const
Definition balxml_errorinfo.h:554
~ErrorInfo()
Destroy this object.
bool isError() const
Definition balxml_errorinfo.h:536
Severity severity() const
Return the severity level.
Definition balxml_errorinfo.h:518
bool isFatalError() const
Definition balxml_errorinfo.h:542
const bsl::string & message() const
Return the string describing the error or warning.
Definition balxml_errorinfo.h:572
ErrorInfo(const ErrorInfo &other, bslma::Allocator *basicAllocator=0)
Definition bslstl_stringview.h:441
Definition bslstl_string.h:1281
Definition bslma_allocator.h:457
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balxml_base64parser.h:150
bsl::ostream & operator<<(bsl::ostream &stream, const ConfigSchema &schema)
bool operator!=(const DecoderOptions &lhs, const DecoderOptions &rhs)
Definition bslma_usesbslmaallocator.h:343