|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2002,2003 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// (c) COPYRIGHT URI/MIT 1994-1999
|
|
Packit |
a4aae4 |
// Please read the full copyright statement in the file COPYRIGHT_URI.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// Authors:
|
|
Packit |
a4aae4 |
// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Implementation for the Error class.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <cstdio>
|
|
Packit |
a4aae4 |
#include <cassert>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Error.h"
|
|
Packit |
a4aae4 |
#include "parser.h"
|
|
Packit |
a4aae4 |
#include "InternalErr.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Glue routines declared in Error.lex
|
|
Packit |
a4aae4 |
extern void Error_switch_to_buffer(void *new_buffer);
|
|
Packit |
a4aae4 |
extern void Error_delete_buffer(void * buffer);
|
|
Packit |
a4aae4 |
extern void *Error_buffer(FILE *fp);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//extern void Errorrestart(FILE *yyin); // defined in Error.tab.c
|
|
Packit |
a4aae4 |
extern int Errorparse(libdap::parser_arg *arg);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// There are two entries for 'cannot read file' because of an error made
|
|
Packit |
a4aae4 |
// when the message was first added to this class.
|
|
Packit |
a4aae4 |
static const char *err_messages[] = {
|
|
Packit |
a4aae4 |
"Undefined error",
|
|
Packit |
a4aae4 |
"Unknown error",
|
|
Packit |
a4aae4 |
"Internal error",
|
|
Packit |
a4aae4 |
"No such file",
|
|
Packit |
a4aae4 |
"No such variable",
|
|
Packit |
a4aae4 |
"Malformed expression",
|
|
Packit |
a4aae4 |
"No authorization",
|
|
Packit |
a4aae4 |
"Cannot read file",
|
|
Packit |
a4aae4 |
"Not Implemented",
|
|
Packit |
a4aae4 |
""
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Specializations of Error should use this to set the error code and
|
|
Packit |
a4aae4 |
message. */
|
|
Packit |
a4aae4 |
Error::Error() : _error_code(undefined_error), _error_message("")
|
|
Packit |
a4aae4 |
{}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Create an instance with a specific code and message string. This ctor
|
|
Packit |
a4aae4 |
provides a way to to use any code and string you'd like. The code can be
|
|
Packit |
a4aae4 |
one of the standard codes or it may be specific to your server. Thus a
|
|
Packit |
a4aae4 |
client which can tell it's dealing with a specific type of server can use
|
|
Packit |
a4aae4 |
the code accordingly. In general, clients simply show the error message
|
|
Packit |
a4aae4 |
to users or write it to a log file.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param ec The error code
|
|
Packit |
a4aae4 |
@param msg The error message string. */
|
|
Packit |
a4aae4 |
Error::Error(ErrorCode ec, string msg)
|
|
Packit |
a4aae4 |
: _error_code(ec), _error_message(msg)
|
|
Packit |
a4aae4 |
{}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Create an instance with a specific message. The error code is set to \c
|
|
Packit |
a4aae4 |
unknown_error.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param msg The error message.
|
|
Packit |
a4aae4 |
@see ErrorCode */
|
|
Packit |
a4aae4 |
Error::Error(string msg)
|
|
Packit |
a4aae4 |
: _error_code(unknown_error), _error_message(msg)
|
|
Packit |
a4aae4 |
{}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Error::Error(const Error ©_from)
|
|
Packit |
a4aae4 |
: _error_code(copy_from._error_code),
|
|
Packit |
a4aae4 |
_error_message(copy_from._error_message)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Error::~Error()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Error &
|
|
Packit |
a4aae4 |
Error::operator=(const Error &rhs)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(OK());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (&rhs == this) // are they identical?
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
_error_code = rhs._error_code;
|
|
Packit |
a4aae4 |
_error_message = rhs._error_message;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
assert(this->OK());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return *this;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Use this function to determine whether an Error object is
|
|
Packit |
a4aae4 |
valid. To be a valid, an Error object must either be: 1)
|
|
Packit |
a4aae4 |
empty or contain a message and a code.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Is the Error object valid?
|
|
Packit |
a4aae4 |
@return TRUE if the object is valid, FALSE otherwise. */
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
Error::OK() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// The object is empty - users cannot make these, but this class can!
|
|
Packit |
a4aae4 |
bool empty = ((_error_code == undefined_error)
|
|
Packit |
a4aae4 |
&& (_error_message.empty()));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Just a message - the program part is null.
|
|
Packit |
a4aae4 |
bool message = ((_error_code != undefined_error)
|
|
Packit |
a4aae4 |
&& (!_error_message.empty()));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << "empty: " << empty << ", message: " << message << endl);
|
|
Packit |
a4aae4 |
return empty || message;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given an input stream (FILE *) <tt>fp</tt>, parse an Error object from
|
|
Packit |
a4aae4 |
stream. Values for fields of the Error object are parsed and \c this is
|
|
Packit |
a4aae4 |
set accordingly. This is how a client program receives an error object
|
|
Packit |
a4aae4 |
from a server.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Parse an Error object.
|
|
Packit |
a4aae4 |
@param fp A valid file pointer to an input stream.
|
|
Packit |
a4aae4 |
@return TRUE if no error was detected, FALSE otherwise. */
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
Error::parse(FILE *fp)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!fp)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Null input stream");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void *buffer = Error_buffer(fp);
|
|
Packit |
a4aae4 |
Error_switch_to_buffer(buffer);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser_arg arg(this);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool status;
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
status = Errorparse(&arg) == 0;
|
|
Packit |
a4aae4 |
Error_delete_buffer(buffer);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
Error_delete_buffer(buffer);
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, e.get_error_message());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// STATUS is the result of the parser function; if a recoverable error
|
|
Packit |
a4aae4 |
// was found it will be true but arg.status() will be false.
|
|
Packit |
a4aae4 |
// I'm throwing an InternalErr here since Error objects are generated by
|
|
Packit |
a4aae4 |
// the core; they should always parse! 9/21/2000 jhrg
|
|
Packit |
a4aae4 |
if (!status || !arg.status())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Error parsing error object!");
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
return OK(); // Check object consistency
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Creates a printable representation of the Error object. It is suitable
|
|
Packit |
a4aae4 |
for framing, and also for printing and sending over a network.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
The printed representation produced by this function can be parsed by the
|
|
Packit |
a4aae4 |
parse() member function. Thus parse and print form a symmetrical pair
|
|
Packit |
a4aae4 |
that can be used to send and receive an Error object over the network in
|
|
Packit |
a4aae4 |
a MIME document.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param out A pointer to the output stream on which the Error object is to
|
|
Packit |
a4aae4 |
be rendered. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Error::print(FILE *out) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(OK());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
fprintf(out, "Error {\n") ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
fprintf(out, " code = %d;\n", static_cast<int>(_error_code)) ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If the error message is wrapped in double quotes, print it, else, add
|
|
Packit |
a4aae4 |
// wrapping double quotes.
|
|
Packit |
a4aae4 |
if (*_error_message.begin() == '"' && *(_error_message.end() - 1) == '"')
|
|
Packit |
a4aae4 |
fprintf(out, " message = %s;\n", _error_message.c_str()) ;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
fprintf(out, " message = \"%s\";\n", _error_message.c_str()) ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
fprintf(out, "};\n") ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Creates a printable representation of the Error object. It is suitable
|
|
Packit |
a4aae4 |
for framing, and also for printing and sending over a network.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
The printed representation produced by this function can be parsed by the
|
|
Packit |
a4aae4 |
parse() member function. Thus parse and print form a symmetrical pair
|
|
Packit |
a4aae4 |
that can be used to send and receive an Error object over the network in
|
|
Packit |
a4aae4 |
a MIME document.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param strm A reference to the output stream on which the Error object is to
|
|
Packit |
a4aae4 |
be rendered. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Error::print(ostream &strm) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(OK());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
strm << "Error {\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
strm << " code = " << static_cast<int>(_error_code) << ";\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If the error message is wrapped in double quotes, print it, else, add
|
|
Packit |
a4aae4 |
// wrapping double quotes.
|
|
Packit |
a4aae4 |
if (*_error_message.begin() == '"' && *(_error_message.end() - 1) == '"')
|
|
Packit |
a4aae4 |
strm << " message = " << _error_message.c_str() << ";\n" ;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
strm << " message = \"" << _error_message.c_str() << "\";\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
strm << "};\n" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the ErrorCode for this instance. */
|
|
Packit |
a4aae4 |
ErrorCode
|
|
Packit |
a4aae4 |
Error::get_error_code() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(OK());
|
|
Packit |
a4aae4 |
return _error_code;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Set the ErrorCode. If the current error message has not been set, use \e
|
|
Packit |
a4aae4 |
ec to set the error message. The resulting error message string is the
|
|
Packit |
a4aae4 |
same as the ErrorCode name. If \e ec is not within the range of values
|
|
Packit |
a4aae4 |
for an OPeNDAP ErrorCode, the error message is left unchanged.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param ec The new ErrorCode value. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Error::set_error_code(ErrorCode ec)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
_error_code = ec;
|
|
Packit |
a4aae4 |
// Added check to make sure that err_messages is not accessed beyond its
|
|
Packit |
a4aae4 |
// bounds. 02/02/04 jhrg
|
|
Packit |
a4aae4 |
if (_error_message.empty()
|
|
Packit |
a4aae4 |
&& ec > undefined_error && ec <= cannot_read_file) {
|
|
Packit |
a4aae4 |
_error_message = err_messages[ec - undefined_error];
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
_error_message = err_messages[0];
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the current error message. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
Error::get_error_message() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(OK());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return string(_error_message);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Set the error message. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
Error::set_error_message(string msg)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
_error_message = msg;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|