Blame DAS.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
// Methods for the class DAS - a class used to parse the dataset attribute
Packit a4aae4
// structure.
Packit a4aae4
//
Packit a4aae4
// jhrg 7/25/94
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
#include <cstdio>
Packit a4aae4
Packit a4aae4
#ifdef HAVE_UNISTD_H
Packit a4aae4
#include <unistd.h>
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#ifdef WIN32
Packit a4aae4
#include <io.h>
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#include <iostream>
Packit a4aae4
#include <string>
Packit a4aae4
Packit a4aae4
#include "DAS.h"
Packit a4aae4
#include "AttrTable.h"
Packit a4aae4
#include "Error.h"
Packit a4aae4
#include "InternalErr.h"
Packit a4aae4
#include "parser.h"
Packit a4aae4
#include "escaping.h"
Packit a4aae4
#include "debug.h"
Packit a4aae4
Packit a4aae4
using std::cerr;
Packit a4aae4
using std::endl;
Packit a4aae4
Packit a4aae4
// Glue routines declared in das.lex
Packit a4aae4
extern void das_switch_to_buffer(void *new_buffer);
Packit a4aae4
extern void das_delete_buffer(void * buffer);
Packit a4aae4
extern void *das_buffer(FILE *fp);
Packit a4aae4
Packit a4aae4
//extern void dasrestart(FILE *yyin);
Packit a4aae4
//extern int dasparse(void *arg); // defined in das.tab.c
Packit a4aae4
extern int dasparse(libdap::parser_arg *arg); // defined in das.tab.c
Packit a4aae4
Packit a4aae4
namespace libdap {
Packit a4aae4
Packit a4aae4
void DAS::duplicate(const DAS &src)
Packit a4aae4
{
Packit a4aae4
    // If the container field is set, perform a deep copy
Packit a4aae4
    if (src.d_container)
Packit a4aae4
        d_container  = new AttrTable(*src.d_container);
Packit a4aae4
    else
Packit a4aae4
        d_container = 0;
Packit a4aae4
Packit a4aae4
    d_container_name = src.d_container_name;
Packit a4aae4
    d_attrs = src.d_attrs;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
DAS &DAS::operator=(const DAS &rhs)
Packit a4aae4
{
Packit a4aae4
    if (this == &rhs)
Packit a4aae4
        return *this;
Packit a4aae4
Packit a4aae4
    duplicate(rhs);
Packit a4aae4
Packit a4aae4
    return *this;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Sets the name of the current attribute container when multiple
Packit a4aae4
 * files used to build this DAS.
Packit a4aae4
 *
Packit a4aae4
 * @param cn container name
Packit a4aae4
 */
Packit a4aae4
void DAS::container_name(const string &cn)
Packit a4aae4
{
Packit a4aae4
    // We want to find a top level attribute table with the given name. So
Packit a4aae4
    // set d_container to null first so that we aren't searching some
Packit a4aae4
    // previous container
Packit a4aae4
    if (cn != d_container_name) {
Packit a4aae4
        d_container = 0;
Packit a4aae4
        if (!cn.empty()) {
Packit a4aae4
            d_container = get_table(cn);
Packit a4aae4
            if (!d_container) {
Packit a4aae4
                d_container = add_table(cn, new AttrTable);
Packit a4aae4
            }
Packit a4aae4
        }
Packit a4aae4
        d_container_name = cn;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Returns the number of attributes in the current attribute table
Packit a4aae4
 *
Packit a4aae4
 * If the there is a container set, then return the number of variable
Packit a4aae4
 * attribute tables for the current container. If not set then return the
Packit a4aae4
 * number of current attribute tables in the outermost attribute table.
Packit a4aae4
 */
Packit a4aae4
unsigned int DAS::get_size() const
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        return d_container->get_size();
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.get_size();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief erase all attributes in this DAS
Packit a4aae4
 */
Packit a4aae4
void DAS::erase()
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        d_container->erase();
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        d_attrs.erase();
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Returns a reference to the attribute table for the first variable.
Packit a4aae4
 */
Packit a4aae4
AttrTable::Attr_iter DAS::var_begin()
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        return d_container->attr_begin();
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.attr_begin();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Returns a reference to the end of the attribute table. Does not
Packit a4aae4
 *  point to an attribute table.
Packit a4aae4
 */
Packit a4aae4
AttrTable::Attr_iter DAS::var_end()
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        return d_container->attr_end();
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.attr_end();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Returns the name of the referenced variable attribute table.
Packit a4aae4
 */
Packit a4aae4
string DAS::get_name(AttrTable::Attr_iter &i)
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        return d_container->get_name(i);
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.get_name(i);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Returns the referenced variable attribute table.
Packit a4aae4
 */
Packit a4aae4
AttrTable *
Packit a4aae4
DAS::get_table(AttrTable::Attr_iter &i)
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        return d_container->get_attr_table(i);
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.get_attr_table(i);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Returns the variable attribute table with the given name.
Packit a4aae4
 */
Packit a4aae4
AttrTable *
Packit a4aae4
DAS::get_table(const string &name)
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        return d_container->get_attr_table(name);
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.get_attr_table(name);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/** @brief Adds an attribute table to the DAS.
Packit a4aae4
    @name add_table()
Packit a4aae4
*/
Packit a4aae4
//@{
Packit a4aae4
Packit a4aae4
/** @brief Adds a variable attribute table to the DAS or the current
Packit a4aae4
 * dataset container attribute table.
Packit a4aae4
 */
Packit a4aae4
AttrTable *
Packit a4aae4
DAS::add_table( const string &name, AttrTable *at )
Packit a4aae4
{
Packit a4aae4
    if (d_container) {
Packit a4aae4
        at->set_is_global_attribute(false);
Packit a4aae4
        return d_container->append_container(at, name);
Packit a4aae4
    }
Packit a4aae4
    return d_attrs.append_container( at, name ) ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/** @brief Reads a DAS in from an external source.
Packit a4aae4
Packit a4aae4
    @name parse()
Packit a4aae4
*/
Packit a4aae4
//@{
Packit a4aae4
Packit a4aae4
Packit a4aae4
/** @brief Reads a DAS from the named file.
Packit a4aae4
Packit a4aae4
    Read attributes from a file. Returns false if unable to open
Packit a4aae4
    the file, otherwise returns the result of the mfunc parse. */
Packit a4aae4
void
Packit a4aae4
DAS::parse(string fname)
Packit a4aae4
{
Packit a4aae4
    FILE *in = fopen(fname.c_str(), "r");
Packit a4aae4
Packit a4aae4
    if (!in) {
Packit a4aae4
        throw Error(cannot_read_file, "Could not open: " + fname);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    parse(in);
Packit a4aae4
Packit a4aae4
    int res = fclose(in);
Packit a4aae4
    if (res) {
Packit a4aae4
        DBG(cerr << "DAS::parse - Failed to close file " << (void *)in << endl ;) ;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Read attributes from a file descriptor.
Packit a4aae4
Packit a4aae4
    If the file descriptor cannot be fdopen'd, return false, otherwise
Packit a4aae4
    return the status of the mfunc parse.
Packit a4aae4
Packit a4aae4
    \note Added call to dup() within fdopen so that once the FILE * is
Packit a4aae4
    closed the decriptor fd will not also be closed (instead the
Packit a4aae4
    duplicate descriptor will be closed). Thus further information can
Packit a4aae4
    be read from the descriptor fd.
Packit a4aae4
*/
Packit a4aae4
void
Packit a4aae4
DAS::parse(int fd)
Packit a4aae4
{
Packit a4aae4
#ifdef WIN32
Packit a4aae4
    int new_fd = _dup(fd);
Packit a4aae4
#else
Packit a4aae4
    int new_fd = dup(fd);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    if (new_fd < 0)
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not access file.");
Packit a4aae4
    FILE *in = fdopen(new_fd, "r");
Packit a4aae4
Packit a4aae4
    if (!in) {
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not access file.");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    parse(in);
Packit a4aae4
Packit a4aae4
    int res = fclose(in);
Packit a4aae4
    if (res) {
Packit a4aae4
        DBG(cerr << "DAS::parse(fd) - Failed to close " << (void *)in << endl ;) ;
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
Packit a4aae4
Packit a4aae4
/** @brief Reads a DAS from an open file descriptor.
Packit a4aae4
Packit a4aae4
    Read attributes from in (which defaults to stdin). If
Packit a4aae4
    dasrestart() fails, return false, otherwise return the status
Packit a4aae4
    of dasparse().
Packit a4aae4
*/
Packit a4aae4
void
Packit a4aae4
DAS::parse(FILE *in)
Packit a4aae4
{
Packit a4aae4
    if (!in) {
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Null input stream.");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    void *buffer = das_buffer(in);
Packit a4aae4
    das_switch_to_buffer(buffer);
Packit a4aae4
Packit a4aae4
    parser_arg arg(this);
Packit a4aae4
Packit a4aae4
    //bool status = dasparse((void *) & arg) == 0;
Packit a4aae4
    bool status = dasparse(&arg) == 0;
Packit a4aae4
Packit a4aae4
    das_delete_buffer(buffer);
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
    if (!status || !arg.status()) {// Check parse result
Packit a4aae4
        if (arg.error())
Packit a4aae4
            throw *arg.error();
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
//@}
Packit a4aae4
Packit a4aae4
/** Creates an ASCII representation of a DAS on the given output
Packit a4aae4
    stream.
Packit a4aae4
Packit a4aae4
    When an identifier contains a character that contains
Packit a4aae4
    characters that cannot be present in a URL (e.g., a space)
Packit a4aae4
    AttrTable::print replaces those characters with WWW
Packit a4aae4
    escape codes. 7/13/2001 jhrg
Packit a4aae4
Packit a4aae4
    @param out output FILE on which to print the DAS
Packit a4aae4
    @param dereference If true, follow aliases. Default is false.
Packit a4aae4
*/
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DAS::print(FILE *out, bool dereference)
Packit a4aae4
{
Packit a4aae4
    fprintf(out, "Attributes {\n") ;
Packit a4aae4
Packit a4aae4
    d_attrs.print(out, "    ", dereference);
Packit a4aae4
Packit a4aae4
    fprintf(out, "}\n") ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Creates an ASCII representation of a DAS on the given output
Packit a4aae4
    stream.
Packit a4aae4
Packit a4aae4
    When an identifier contains a character that contains
Packit a4aae4
    characters that cannot be present in a URL (e.g., a space)
Packit a4aae4
    AttrTable::print replaces those characters with WWW
Packit a4aae4
    escape codes. 7/13/2001 jhrg
Packit a4aae4
Packit a4aae4
    @param out output ostream on which to print the DAS
Packit a4aae4
    @param dereference If true, follow aliases. Default is false.
Packit a4aae4
*/
Packit a4aae4
Packit a4aae4
void
Packit a4aae4
DAS::print(ostream &out, bool dereference)
Packit a4aae4
{
Packit a4aae4
    out << "Attributes {\n" ;
Packit a4aae4
Packit a4aae4
    d_attrs.print(out, "    ", dereference);
Packit a4aae4
Packit a4aae4
    out << "}\n" ;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief dumps information about this object
Packit a4aae4
 *
Packit a4aae4
 * Displays the pointer value of this instance and then calls parent dump
Packit a4aae4
 *
Packit a4aae4
 * @param strm C++ i/o stream to dump the information to
Packit a4aae4
 * @return void
Packit a4aae4
 */
Packit a4aae4
void DAS::dump(ostream &strm) const
Packit a4aae4
{
Packit a4aae4
    strm << DapIndent::LMarg << "DAS::dump - (" << (void *) this << ")" << endl;
Packit a4aae4
    DapIndent::Indent();
Packit a4aae4
    if (d_container) {
Packit a4aae4
        strm << DapIndent::LMarg << "current container: " << d_container_name << endl;
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        strm << DapIndent::LMarg << "current container: NONE" << endl;
Packit a4aae4
    }
Packit a4aae4
    d_attrs.dump(strm);
Packit a4aae4
    DapIndent::UnIndent();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
} // namespace libdap
Packit a4aae4