Blame Error.cc

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 &copy_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