Blame das.yy

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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
/*
Packit a4aae4
   Grammar for the DAS. This grammar can be used with the bison parser
Packit a4aae4
   generator to build a parser for the DAS. It assumes that a scanner called
Packit a4aae4
   `daslex()' exists and that the objects DAS and AttrTable also exist.
Packit a4aae4
Packit a4aae4
   jhrg 7/12/94 
Packit a4aae4
*/
Packit a4aae4
Packit a4aae4
%code requires {
Packit a4aae4
Packit a4aae4
#define YYSTYPE char *
Packit a4aae4
#define ATTR_STRING_QUOTE_FIX
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
#include <string>
Packit a4aae4
Packit a4aae4
#include <vector>
Packit a4aae4
Packit a4aae4
#include "DAS.h"
Packit a4aae4
#include "Error.h"
Packit a4aae4
#include "util.h"
Packit a4aae4
#include "escaping.h"
Packit a4aae4
#include "debug.h"
Packit a4aae4
#include "parser.h"
Packit a4aae4
#include "util.h"
Packit a4aae4
// #include "das.tab.hh"
Packit a4aae4
Packit a4aae4
#ifdef TRACE_NEW
Packit a4aae4
#include "trace_new.h"
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#define yylex daslex
Packit a4aae4
#define yyerror daserror 
Packit a4aae4
Packit a4aae4
using namespace std;
Packit a4aae4
using namespace libdap ;
Packit a4aae4
Packit a4aae4
// These macros are used to access the `arguments' passed to the parser. A
Packit a4aae4
// pointer to an error object and a pointer to an integer status variable are
Packit a4aae4
// passed in to the parser within a structure (which itself is passed as a
Packit a4aae4
// pointer). Note that the ERROR macro explicitly casts OBJ to an ERROR *. 
Packit a4aae4
// The parser now throws an exception when it encounters an error. 5/23/2002
Packit a4aae4
// jhrg 
Packit a4aae4
Packit a4aae4
#define DAS_OBJ(arg) ((DAS *)((parser_arg *)(arg))->_object)
Packit a4aae4
Packit a4aae4
//#define YYPARSE_PARAM arg
Packit a4aae4
Packit a4aae4
extern int das_line_num;	/* defined in das.lex */
Packit a4aae4
Packit a4aae4
} // code requires
Packit a4aae4
Packit a4aae4
%code {
Packit a4aae4
// No global static objects. We go through this every so often, I guess I
Packit a4aae4
// should learn... 1/24/2000 jhrg
Packit a4aae4
static string *name;	/* holds name in attr_pair rule */
Packit a4aae4
static string *type;	/* holds type in attr_pair rule */
Packit a4aae4
Packit a4aae4
static vector<AttrTable *> *attr_tab_stack;
Packit a4aae4
Packit a4aae4
// I use a vector of AttrTable pointers for a stack
Packit a4aae4
Packit a4aae4
#define TOP_OF_STACK (attr_tab_stack->back())
Packit a4aae4
#define PUSH(x) (attr_tab_stack->push_back((x)))
Packit a4aae4
#define POP (attr_tab_stack->pop_back())
Packit a4aae4
#define STACK_LENGTH (attr_tab_stack->size())
Packit a4aae4
#define OUTER_TABLE_ONLY (attr_tab_stack->size() == 1)
Packit a4aae4
#define STACK_EMPTY (attr_tab_stack->empty())
Packit a4aae4
Packit a4aae4
#define TYPE_NAME_VALUE(x) *type << " " << *name << " " << (x)
Packit a4aae4
Packit a4aae4
static const char *ATTR_TUPLE_MSG = 
Packit a4aae4
"Expected an attribute type (Byte, Int16, UInt16, Int32, UInt32, Float32,\n\
Packit a4aae4
Float64, String or Url) followed by a name and value.";
Packit a4aae4
static const char *NO_DAS_MSG =
Packit a4aae4
"The attribute object returned from the dataset was null\n\
Packit a4aae4
Check that the URL is correct.";
Packit a4aae4
Packit a4aae4
typedef int checker(const char *);
Packit a4aae4
Packit a4aae4
int daslex(void);
Packit a4aae4
static void daserror(parser_arg *arg, const string &s /*char *s*/);
Packit a4aae4
static void add_attribute(const string &type, const string &name, 
Packit a4aae4
			  const string &value, checker *chk) throw (Error);
Packit a4aae4
static void add_alias(AttrTable *das, AttrTable *current, const string &name, 
Packit a4aae4
		      const string &src) throw (Error);
Packit a4aae4
static void add_bad_attribute(AttrTable *attr, const string &type,
Packit a4aae4
			      const string &name, const string &value,
Packit a4aae4
			      const string &msg;;
Packit a4aae4
Packit a4aae4
} // code
Packit a4aae4
Packit a4aae4
%require "2.4"
Packit a4aae4
Packit a4aae4
%parse-param {parser_arg *arg}
Packit a4aae4
%name-prefix "das"
Packit a4aae4
%defines
Packit a4aae4
%debug
Packit a4aae4
%verbose
Packit a4aae4
Packit a4aae4
%expect 26
Packit a4aae4
Packit a4aae4
%token SCAN_ATTR
Packit a4aae4
Packit a4aae4
%token SCAN_WORD
Packit a4aae4
Packit a4aae4
%token SCAN_ALIAS
Packit a4aae4
Packit a4aae4
%token SCAN_BYTE
Packit a4aae4
%token SCAN_INT16
Packit a4aae4
%token SCAN_UINT16
Packit a4aae4
%token SCAN_INT32
Packit a4aae4
%token SCAN_UINT32
Packit a4aae4
%token SCAN_FLOAT32
Packit a4aae4
%token SCAN_FLOAT64
Packit a4aae4
%token SCAN_STRING
Packit a4aae4
%token SCAN_URL
Packit a4aae4
%token SCAN_XML
Packit a4aae4
Packit a4aae4
%%
Packit a4aae4
Packit a4aae4
/*
Packit a4aae4
  Parser algorithm: 
Packit a4aae4
Packit a4aae4
  Look for a `variable' name (this can be any identifier, but by convention
Packit a4aae4
  it is either the name of a variable in a dataset or the name of a grouping
Packit a4aae4
  of global attributes). Create a new attribute table for this identifier and
Packit a4aae4
  push the new attribute table onto a stack. If attribute tuples
Packit a4aae4
  (type-name-value tuples) are found, intern them in the attribute table
Packit a4aae4
  found on the top of the stack. If the start of a new attribute table if
Packit a4aae4
  found (before the current table is closed), create the new table and push
Packit a4aae4
  *it* on the stack. As attribute tables are closed, pop them off the stack.
Packit a4aae4
  This algorithm ensures that we can nest attribute tables to an arbitrary
Packit a4aae4
  depth.
Packit a4aae4
Packit a4aae4
  Aliases are handled using mfuncs of both the DAS and AttrTable objects. This
Packit a4aae4
  is necessary because the first level of a DAS object can contain only
Packit a4aae4
  AttrTables, not attribute tuples. Whereas, the subsequent levels can
Packit a4aae4
  contain both. Thus the compete definition is split into two objects. In
Packit a4aae4
  part this is also a hold over from an older design which did not
Packit a4aae4
  have the recursive properties of the current design.
Packit a4aae4
Packit a4aae4
  Aliases can be made between attributes within a given lexical level, from
Packit a4aae4
  one level to the next within a sub-hierarchy or across hierarchies.
Packit a4aae4
Packit a4aae4
  Tokens:
Packit a4aae4
Packit a4aae4
  BYTE, INT32, UINT32, FLOAT64, STRING and URL are tokens for the type
Packit a4aae4
  keywords. The tokens INT, FLOAT, STR and ID are returned by the scanner to
Packit a4aae4
  indicate the type of the value represented by the string contained in the
Packit a4aae4
  global DASLVAL. These two types of tokens are used to implement type
Packit a4aae4
  checking for the attributes. See the rules `bytes', etc. Additional tokens:
Packit a4aae4
  ATTR (indicates the start of an attribute object) and ALIAS (indicates an
Packit a4aae4
  alias). */
Packit a4aae4
Packit a4aae4
/* This rule makes sure the objects needed by this parser are built. Because
Packit a4aae4
   the DODS DAP library is often used with linkers that are not C++-aware, we
Packit a4aae4
   cannot use global objects (because their constructors might never be
Packit a4aae4
   called). I had thought this was going to go away... 1/24/2000 jhrg */
Packit a4aae4
Packit a4aae4
attr_start:
Packit a4aae4
	{
Packit a4aae4
		if (!name) name = new string();
Packit a4aae4
		if (!type) type = new string();
Packit a4aae4
		if (!attr_tab_stack) attr_tab_stack = new vector<AttrTable *>;
Packit a4aae4
Packit a4aae4
		// push outermost AttrTable
Packit a4aae4
		PUSH(DAS_OBJ(arg)->get_top_level_attributes());
Packit a4aae4
	}
Packit a4aae4
    attributes
Packit a4aae4
    {
Packit a4aae4
		POP;	// pop the DAS/AttrTable before stack's dtor
Packit a4aae4
		delete name; name = 0;
Packit a4aae4
		delete type; type = 0;
Packit a4aae4
		delete attr_tab_stack; attr_tab_stack = 0;
Packit a4aae4
	}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
attributes:     attribute
Packit a4aae4
    | attributes attribute
Packit a4aae4
Packit a4aae4
;
Packit a4aae4
    	    	
Packit a4aae4
attribute:    	SCAN_ATTR '{' attr_list '}'
Packit a4aae4
        | error
Packit a4aae4
        {
Packit a4aae4
		    parse_error((parser_arg *)arg, NO_DAS_MSG, das_line_num);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
attr_list:  	/* empty */
Packit a4aae4
    	| attr_tuple
Packit a4aae4
    	| attr_list attr_tuple
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
attr_tuple:	alias
Packit a4aae4
Packit a4aae4
        | SCAN_BYTE { save_str(*type, "Byte", das_line_num); }
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		bytes ';'
Packit a4aae4
Packit a4aae4
		| SCAN_INT16 { save_str(*type, "Int16", das_line_num); } 
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		int16 ';'
Packit a4aae4
Packit a4aae4
		| SCAN_UINT16 { save_str(*type, "UInt16", das_line_num); } 
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		uint16 ';'
Packit a4aae4
Packit a4aae4
		| SCAN_INT32 { save_str(*type, "Int32", das_line_num); } 
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		int32 ';'
Packit a4aae4
Packit a4aae4
		| SCAN_UINT32 { save_str(*type, "UInt32", das_line_num); } 
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		uint32 ';'
Packit a4aae4
Packit a4aae4
		| SCAN_FLOAT32 { save_str(*type, "Float32", das_line_num); } 
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		float32 ';'
Packit a4aae4
Packit a4aae4
		| SCAN_FLOAT64 { save_str(*type, "Float64", das_line_num); } 
Packit a4aae4
                name { save_str(*name, $3, das_line_num); } 
Packit a4aae4
		float64 ';'
Packit a4aae4
Packit a4aae4
		| SCAN_STRING { *type = "String"; } 
Packit a4aae4
                name { *name = $3; } 
Packit a4aae4
		strs ';'
Packit a4aae4
Packit a4aae4
                | SCAN_URL { *type = "Url"; } 
Packit a4aae4
                name { *name = $3; } 
Packit a4aae4
                urls ';'
Packit a4aae4
Packit a4aae4
                | SCAN_XML { *type = "OtherXML"; } 
Packit a4aae4
                name { *name = $3; } 
Packit a4aae4
                xml ';'
Packit a4aae4
Packit a4aae4
		| SCAN_WORD
Packit a4aae4
                {
Packit a4aae4
		    DBG(cerr << "Processing ID: " << $1 << endl);
Packit a4aae4
		    
Packit a4aae4
		    AttrTable *at = TOP_OF_STACK->get_attr_table($1);
Packit a4aae4
		    if (!at) {
Packit a4aae4
			try {
Packit a4aae4
			    at = TOP_OF_STACK->append_container($1);
Packit a4aae4
			}
Packit a4aae4
			catch (Error &e) {
Packit a4aae4
			    // re-throw with line number info
Packit a4aae4
			    parse_error(e.get_error_message().c_str(), 
Packit a4aae4
					das_line_num);
Packit a4aae4
			}
Packit a4aae4
		    }
Packit a4aae4
		    PUSH(at);
Packit a4aae4
Packit a4aae4
		    DBG(cerr << " Pushed attr_tab: " << at << endl);
Packit a4aae4
Packit a4aae4
		}
Packit a4aae4
		'{' attr_list 
Packit a4aae4
                {
Packit a4aae4
		    /* pop top of stack; store in attr_tab */
Packit a4aae4
		    DBG(cerr << " Popped attr_tab: " << TOP_OF_STACK << endl);
Packit a4aae4
		    POP;
Packit a4aae4
		}
Packit a4aae4
		'}'
Packit a4aae4
Packit a4aae4
		| error 
Packit a4aae4
                { 
Packit a4aae4
		    parse_error(ATTR_TUPLE_MSG, das_line_num, $1);
Packit a4aae4
		} ';'
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
bytes:		SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_byte);
Packit a4aae4
		}
Packit a4aae4
		| bytes ',' SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_byte);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
int16:		SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_int16);
Packit a4aae4
		}
Packit a4aae4
		| int16 ',' SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_int16);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
uint16:		SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_uint16);
Packit a4aae4
		}
Packit a4aae4
		| uint16 ',' SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_uint16);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
int32:		SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_int32);
Packit a4aae4
		}
Packit a4aae4
		| int32 ',' SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_int32);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
uint32:		SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_uint32);
Packit a4aae4
		}
Packit a4aae4
		| uint32 ',' SCAN_WORD
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_uint32);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
float32:	float_or_int
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_float32);
Packit a4aae4
		}
Packit a4aae4
		| float32 ',' float_or_int
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_float32);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
float64:	float_or_int
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $1, &check_float64);
Packit a4aae4
		}
Packit a4aae4
		| float64 ',' float_or_int
Packit a4aae4
		{
Packit a4aae4
		    add_attribute(*type, *name, $3, &check_float64);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
strs:		str_or_id
Packit a4aae4
		{
Packit a4aae4
		    string attr = remove_quotes($1);
Packit a4aae4
		    add_attribute(*type, *name, attr, 0);
Packit a4aae4
		}
Packit a4aae4
		| strs ',' str_or_id
Packit a4aae4
		{
Packit a4aae4
		    string attr = remove_quotes($3);
Packit a4aae4
		    add_attribute(*type, *name, attr, 0);
Packit a4aae4
		}
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
urls:           url
Packit a4aae4
                {
Packit a4aae4
                    add_attribute(*type, *name, $1, &check_url);
Packit a4aae4
                }
Packit a4aae4
                | urls ',' url
Packit a4aae4
                {
Packit a4aae4
                    add_attribute(*type, *name, $3, &check_url);
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
xml:            SCAN_WORD
Packit a4aae4
                {
Packit a4aae4
                    // XML must be quoted in the DAS but the quotes are an
Packit a4aae4
                    // artifact of the DAS syntax so they are not part of the
Packit a4aae4
                    // value.
Packit a4aae4
                    string xml = unescape_double_quotes($1);
Packit a4aae4
                    
Packit a4aae4
                    if (is_quoted(xml))
Packit a4aae4
                        add_attribute(*type, *name, remove_quotes(xml), 0);
Packit a4aae4
                    else
Packit a4aae4
                        add_attribute(*type, *name, xml, 0);
Packit a4aae4
                }
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
url:		SCAN_WORD
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
str_or_id:	SCAN_WORD
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
float_or_int:   SCAN_WORD
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
name:           SCAN_WORD | SCAN_ATTR | SCAN_ALIAS | SCAN_BYTE | SCAN_INT16 
Packit a4aae4
                | SCAN_UINT16 | SCAN_INT32 | SCAN_UINT32 | SCAN_FLOAT32 
Packit a4aae4
                | SCAN_FLOAT64 | SCAN_STRING | SCAN_URL | SCAN_XML
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
alias:          SCAN_ALIAS SCAN_WORD
Packit a4aae4
                { 
Packit a4aae4
		    *name = $2;
Packit a4aae4
		} 
Packit a4aae4
                SCAN_WORD
Packit a4aae4
                {
Packit a4aae4
		    add_alias( DAS_OBJ(arg)->get_top_level_attributes(),
Packit a4aae4
		               TOP_OF_STACK, *name, string($4) ) ;
Packit a4aae4
                }
Packit a4aae4
                ';'
Packit a4aae4
;
Packit a4aae4
Packit a4aae4
%%
Packit a4aae4
Packit a4aae4
// This function is required for linking, but DODS uses its own error
Packit a4aae4
// reporting mechanism.
Packit a4aae4
Packit a4aae4
static void
Packit a4aae4
daserror(parser_arg *, const string &)
Packit a4aae4
{
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static string
Packit a4aae4
a_or_an(const string &subject)
Packit a4aae4
{
Packit a4aae4
    string first_char(1, subject[0]);
Packit a4aae4
    string::size_type pos = first_char.find_first_of("aeiouAEIOUyY");
Packit a4aae4
    
Packit a4aae4
    if (pos == string::npos)
Packit a4aae4
		return "a";
Packit a4aae4
    else
Packit a4aae4
		return "an";
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// This code used to throw an exception when a bad attribute value came
Packit a4aae4
// along; now it dumps the errant value(s) into a sub container called *_DODS
Packit a4aae4
// and stores the parser's error message in a string attribute named
Packit a4aae4
// `explanation.' 
Packit a4aae4
static void
Packit a4aae4
add_attribute(const string &type, const string &name, const string &value,
Packit a4aae4
	      checker *chk) throw (Error)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Adding: " << type << " " << name << " " << value \
Packit a4aae4
	<< " to Attrtable: " << TOP_OF_STACK << endl);
Packit a4aae4
Packit a4aae4
    if (chk && !(*chk)(value.c_str())) {
Packit a4aae4
		string msg = "`";
Packit a4aae4
		msg += value + "' is not " + a_or_an(type) + " " + type + " value.";
Packit a4aae4
		add_bad_attribute(TOP_OF_STACK, type, name, value, msg);
Packit a4aae4
		return;
Packit a4aae4
    }
Packit a4aae4
    
Packit a4aae4
    if (STACK_EMPTY) {
Packit a4aae4
		string msg = "Whoa! Attribute table stack empty when adding `" ;
Packit a4aae4
		msg += name + ".' ";
Packit a4aae4
		parse_error(msg, das_line_num);
Packit a4aae4
    }
Packit a4aae4
    
Packit a4aae4
    try {
Packit a4aae4
#if 0
Packit a4aae4
        // Special treatment for XML: remove the double quotes that were 
Packit a4aae4
        // included in the value by this parser.
Packit a4aae4
        if (type == OtherXML && is_quoted(value))
Packit a4aae4
            TOP_OF_STACK->append_attr(name, type, value.substr(1, value.size()-2));
Packit a4aae4
        else    
Packit a4aae4
#endif
Packit a4aae4
	    TOP_OF_STACK->append_attr(name, type, value);
Packit a4aae4
    }
Packit a4aae4
    catch (Error &e) {
Packit a4aae4
	 	// re-throw with line number
Packit a4aae4
		parse_error(e.get_error_message().c_str(), das_line_num);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static void
Packit a4aae4
add_alias(AttrTable *das, AttrTable *current, const string &name, 
Packit a4aae4
	  const string &src) throw (Error)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Adding an alias: " << name << ": " << src << endl);
Packit a4aae4
Packit a4aae4
    AttrTable *table = das->get_attr_table(src);
Packit a4aae4
    if (table) {
Packit a4aae4
	try {
Packit a4aae4
	    current->add_container_alias(name, table);
Packit a4aae4
	}
Packit a4aae4
	catch (Error &e) {
Packit a4aae4
	    parse_error(e.get_error_message().c_str(), das_line_num);
Packit a4aae4
	}
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
	try {
Packit a4aae4
	    current->add_value_alias(das, name, src);
Packit a4aae4
	}
Packit a4aae4
	catch (Error &e) {
Packit a4aae4
	    parse_error(e.get_error_message().c_str(), das_line_num);
Packit a4aae4
	}
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static void
Packit a4aae4
add_bad_attribute(AttrTable *attr, const string &type, const string &name,
Packit a4aae4
		  const string &value, const string &msg)
Packit a4aae4
{
Packit a4aae4
    // First, if this bad value is already in a *_dods_errors container,
Packit a4aae4
    // then just add it. This can happen when the server side processes a DAS
Packit a4aae4
    // and then hands it off to a client which does the same.
Packit a4aae4
    // Make a new container. Call it <attr's name>_errors. If that container
Packit a4aae4
    // already exists, use it.
Packit a4aae4
    // Add the attribute.
Packit a4aae4
    // Add the error string to an attribute in the container called
Packit a4aae4
    // `
Packit a4aae4
    
Packit a4aae4
    if (attr->get_name().find("_dods_errors") != string::npos) {
Packit a4aae4
	attr->append_attr(name, type, value);
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
	string error_cont_name = attr->get_name() + "_dods_errors";
Packit a4aae4
	AttrTable *error_cont = attr->get_attr_table(error_cont_name);
Packit a4aae4
	if (!error_cont)
Packit a4aae4
	    error_cont = attr->append_container(error_cont_name);
Packit a4aae4
Packit a4aae4
	error_cont->append_attr(name, type, value);
Packit a4aae4
#ifndef ATTR_STRING_QUOTE_FIX
Packit a4aae4
    error_cont->append_attr(name + "_explanation", "String",
Packit a4aae4
                "\"" + msg + "\"");
Packit a4aae4
#else
Packit a4aae4
       error_cont->append_attr(name + "_explanation", "String", msg);
Packit a4aae4
#endif
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4