|
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 |
// Utility functions used by the api.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// jhrg 9/21/94
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <fstream>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <cassert>
|
|
Packit |
a4aae4 |
#include <cstring>
|
|
Packit |
a4aae4 |
#include <climits>
|
|
Packit |
a4aae4 |
#include <cstdlib>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <ctype.h>
|
|
Packit |
a4aae4 |
#ifndef TM_IN_SYS_TIME
|
|
Packit |
a4aae4 |
#include <time.h>
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
#include <sys/time.h>
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
#include <unistd.h> // for stat
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
#include <io.h>
|
|
Packit |
a4aae4 |
#include <fcntl.h>
|
|
Packit |
a4aae4 |
#include <process.h>
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <sys/types.h>
|
|
Packit |
a4aae4 |
#include <sys/stat.h>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <string>
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
#include <vector>
|
|
Packit |
a4aae4 |
#include <algorithm>
|
|
Packit |
a4aae4 |
#include <stdexcept>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "BaseType.h"
|
|
Packit |
a4aae4 |
#include "Byte.h"
|
|
Packit |
a4aae4 |
#include "Int16.h"
|
|
Packit |
a4aae4 |
#include "Int32.h"
|
|
Packit |
a4aae4 |
#include "UInt16.h"
|
|
Packit |
a4aae4 |
#include "UInt32.h"
|
|
Packit |
a4aae4 |
#include "Float32.h"
|
|
Packit |
a4aae4 |
#include "Float64.h"
|
|
Packit |
a4aae4 |
#include "Str.h"
|
|
Packit |
a4aae4 |
#include "Array.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Int64.h"
|
|
Packit |
a4aae4 |
#include "UInt64.h"
|
|
Packit |
a4aae4 |
#include "Int8.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Error.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "GNURegex.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Does this host use big-endian byte order? */
|
|
Packit |
a4aae4 |
bool is_host_big_endian()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#ifdef COMPUTE_ENDIAN_AT_RUNTIME
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dods_int16 i = 0x0100;
|
|
Packit |
a4aae4 |
char *c = reinterpret_cast<char*>(&i);
|
|
Packit |
a4aae4 |
return *c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if WORDS_BIGENDIAN
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given a BaseType pointer, extract the string value it contains
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param arg The BaseType pointer
|
|
Packit |
a4aae4 |
@return A C++ string
|
|
Packit |
a4aae4 |
@exception Error thrown if the referenced BaseType object does not contain
|
|
Packit |
a4aae4 |
a DAP String. */
|
|
Packit |
a4aae4 |
string extract_string_argument(BaseType *arg)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(arg);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (arg->type() != dods_str_c) throw Error(malformed_expr, "The function requires a string argument.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!arg->read_p())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The CE Evaluator built an argument list where some constants held no values.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return static_cast<Str*>(arg)->value();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
template<class T> static void set_array_using_double_helper(Array *a, double *src, int src_len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(a);
|
|
Packit |
a4aae4 |
assert(src);
|
|
Packit |
a4aae4 |
assert(src_len > 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
vector<T> values(src_len);
|
|
Packit |
a4aae4 |
for (int i = 0; i < src_len; ++i)
|
|
Packit |
a4aae4 |
values[i] = (T) src[i];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This copies the values
|
|
Packit |
a4aae4 |
a->set_value(values, src_len);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given an array that holds some sort of numeric data, load it with values
|
|
Packit |
a4aae4 |
using an array of doubles. This function makes several assumptions. First,
|
|
Packit |
a4aae4 |
it assumes the caller really wants to put the doubles into whatever types
|
|
Packit |
a4aae4 |
the array holds! Caveat emptor. Second, it assumes that if the size of
|
|
Packit |
a4aae4 |
source (\e src) array is different than the destination (\e dest) the
|
|
Packit |
a4aae4 |
caller has made a mistake. In that case it will throw an Error object.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
After setting the values, this method sets the \c read_p property for
|
|
Packit |
a4aae4 |
\e dest. Setting \e read_p tells the serialization methods in libdap
|
|
Packit |
a4aae4 |
that this variable already holds data values and, given that, the
|
|
Packit |
a4aae4 |
serialization code will not try to read the values.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note Support for DAP4 added.
|
|
Packit |
a4aae4 |
@param dest An Array. The values are written to this array, reusing
|
|
Packit |
a4aae4 |
its storage. Existing values are lost.
|
|
Packit |
a4aae4 |
@param src The source data.
|
|
Packit |
a4aae4 |
@param src_len The number of elements in the \e src array.
|
|
Packit |
a4aae4 |
@exception Error Thrown if \e dest is not a numeric-type array (Byte, ...,
|
|
Packit |
a4aae4 |
Float64) or if the number of elements in \e src does not match the number
|
|
Packit |
a4aae4 |
is \e dest. */
|
|
Packit |
a4aae4 |
void set_array_using_double(Array *dest, double *src, int src_len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(dest);
|
|
Packit |
a4aae4 |
assert(src);
|
|
Packit |
a4aae4 |
assert(src_len > 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Simple types are Byte, ..., Float64, String and Url.
|
|
Packit |
a4aae4 |
if ((dest->type() == dods_array_c && !dest->var()->is_simple_type()) || dest->var()->type() == dods_str_c
|
|
Packit |
a4aae4 |
|| dest->var()->type() == dods_url_c)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "The function requires a numeric-type array argument.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Test sizes. Note that Array::length() takes any constraint into account
|
|
Packit |
a4aae4 |
// when it returns the length. Even if this was removed, the 'helper'
|
|
Packit |
a4aae4 |
// function this uses calls Vector::val2buf() which uses Vector::width()
|
|
Packit |
a4aae4 |
// which in turn uses length().
|
|
Packit |
a4aae4 |
if (dest->length() != src_len)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The source and destination array sizes don't match (" + long_to_string(src_len) + " versus "
|
|
Packit |
a4aae4 |
+ long_to_string(dest->length()) + ").");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The types of arguments that the CE Parser will build for numeric
|
|
Packit |
a4aae4 |
// constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
|
|
Packit |
a4aae4 |
// Expanded to work for any numeric type so it can be used for more than
|
|
Packit |
a4aae4 |
// just arguments.
|
|
Packit |
a4aae4 |
switch (dest->var()->type()) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_byte>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_uint16>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_int16>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_uint32>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_int32>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_float32>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_float64>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// DAP4 support
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_byte>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_int8>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_uint64>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
set_array_using_double_helper<dods_int64>(dest, src, src_len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The argument list built by the CE parser contained an unsupported numeric type.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Set the read_p property.
|
|
Packit |
a4aae4 |
dest->set_read_p(true);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
template<class T> static double *extract_double_array_helper(Array * a)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(a);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int length = a->length();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
vector<T> b(length);
|
|
Packit |
a4aae4 |
a->value(&b[0]); // Extract the values of 'a' to 'b'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
double *dest = new double[length];
|
|
Packit |
a4aae4 |
for (int i = 0; i < length; ++i)
|
|
Packit |
a4aae4 |
dest[i] = (double) b[i];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return dest;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Given a pointer to an Array which holds a numeric type, extract the
|
|
Packit |
a4aae4 |
* values and return in an array of doubles. This function allocates the
|
|
Packit |
a4aae4 |
* array using 'new double[n]' so delete[] MUST be used when you are done
|
|
Packit |
a4aae4 |
* the data.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note Support added for DAP4.
|
|
Packit |
a4aae4 |
* @param a Extract value from this Array.
|
|
Packit |
a4aae4 |
* @return A C++/C array of doubles.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
double *extract_double_array(Array * a)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(a);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Simple types are Byte, ..., Float64, String and Url.
|
|
Packit |
a4aae4 |
if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
|
|
Packit |
a4aae4 |
|| a->var()->type() == dods_url_c)
|
|
Packit |
a4aae4 |
throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!a->read_p())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "'does not contain values.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The types of arguments that the CE Parser will build for numeric
|
|
Packit |
a4aae4 |
// constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
|
|
Packit |
a4aae4 |
// Expanded to work for any numeric type so it can be used for more than
|
|
Packit |
a4aae4 |
// just arguments.
|
|
Packit |
a4aae4 |
switch (a->var()->type()) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_byte>(a);
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_uint16>(a);
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int16>(a);
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_uint32>(a);
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int32>(a);
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_float32>(a);
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
// Should not be copying these values, just read them,
|
|
Packit |
a4aae4 |
// but older code may depend on the return of this function
|
|
Packit |
a4aae4 |
// being something that should be deleted, so leave this
|
|
Packit |
a4aae4 |
// alone. jhrg 2/24/15
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_float64>(a);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Support for DAP4
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_byte>(a);
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int8>(a);
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_uint64>(a);
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int64>(a);
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The argument list built by the CE parser contained an unsupported numeric type.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This helper function assumes 'dest' is the correct size. This should not
|
|
Packit |
a4aae4 |
// be called when the Array 'a' is a Float64, since the values are already
|
|
Packit |
a4aae4 |
// in a double array!
|
|
Packit |
a4aae4 |
template<class T> static void extract_double_array_helper(Array * a, vector<double> &dest)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(a);
|
|
Packit |
a4aae4 |
assert(dest.size() == (unsigned long )a->length());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int length = a->length();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
vector<T> b(length);
|
|
Packit |
a4aae4 |
a->value(&b[0]); // Extract the values of 'a' to 'b'
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (int i = 0; i < length; ++i)
|
|
Packit |
a4aae4 |
dest[i] = (double) b[i];
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Given a pointer to an Array which holds a numeric type, extract the
|
|
Packit |
a4aae4 |
* values and return in an array of doubles. This function allocates the
|
|
Packit |
a4aae4 |
* array using 'new double[n]' so delete[] MUST be used when you are done
|
|
Packit |
a4aae4 |
* the data.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note Before you call this function, you must call read on the array,
|
|
Packit |
a4aae4 |
* or load the array with values and set the read_p property.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note Support added for DAP4.
|
|
Packit |
a4aae4 |
* @param a Extract value from this Array.
|
|
Packit |
a4aae4 |
* @param dest Put the values in this vector. A value-result parameter.
|
|
Packit |
a4aae4 |
* @return A C++/C array of doubles.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void extract_double_array(Array *a, vector<double> &dest)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(a);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Simple types are Byte, ..., Float64, String and Url.
|
|
Packit |
a4aae4 |
if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
|
|
Packit |
a4aae4 |
|| a->var()->type() == dods_url_c)
|
|
Packit |
a4aae4 |
throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!a->read_p())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "' does not contain values.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dest.resize(a->length());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The types of arguments that the CE Parser will build for numeric
|
|
Packit |
a4aae4 |
// constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
|
|
Packit |
a4aae4 |
// Expanded to work for any numeric type so it can be used for more than
|
|
Packit |
a4aae4 |
// just arguments.
|
|
Packit |
a4aae4 |
switch (a->var()->type()) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_byte>(a, dest);
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_uint16>(a, dest);
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int16>(a, dest);
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_uint32>(a, dest);
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int32>(a, dest);
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_float32>(a, dest);
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
return a->value(&dest[0]); // no need to copy the values
|
|
Packit |
a4aae4 |
// return extract_double_array_helper<dods_float64>(a, dest);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Support for DAP4
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_byte>(a, dest);
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int8>(a, dest);
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_uint64>(a, dest);
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
return extract_double_array_helper<dods_int64>(a, dest);
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The argument list built by the CE parser contained an unsupported numeric type.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given a BaseType pointer, extract the numeric value it contains and return
|
|
Packit |
a4aae4 |
it in a C++ double.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note Support for DAP4 types added.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param arg The BaseType pointer
|
|
Packit |
a4aae4 |
@return A C++ double
|
|
Packit |
a4aae4 |
@exception Error thrown if the referenced BaseType object does not contain
|
|
Packit |
a4aae4 |
a DAP numeric value. */
|
|
Packit |
a4aae4 |
double extract_double_value(BaseType *arg)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
assert(arg);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Simple types are Byte, ..., Float64, String and Url.
|
|
Packit |
a4aae4 |
if (!arg->is_simple_type() || arg->type() == dods_str_c || arg->type() == dods_url_c)
|
|
Packit |
a4aae4 |
throw Error(malformed_expr, "The function requires a numeric-type argument.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!arg->read_p())
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The Evaluator built an argument list where some constants held no values.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The types of arguments that the CE Parser will build for numeric
|
|
Packit |
a4aae4 |
// constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
|
|
Packit |
a4aae4 |
// Expanded to work for any numeric type so it can be used for more than
|
|
Packit |
a4aae4 |
// just arguments.
|
|
Packit |
a4aae4 |
switch (arg->type()) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Byte*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<UInt16*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Int16*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<UInt32*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Int32*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Float32*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
return static_cast<Float64*>(arg)->value();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Support for DAP4 types.
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Byte*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Int8*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<UInt64*>(arg)->value());
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
return (double) (static_cast<Int64*>(arg)->value());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__,
|
|
Packit |
a4aae4 |
"The argument list built by the parser contained an unsupported numeric type.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Remove spaces from the start of a URL and from the start of any constraint
|
|
Packit |
a4aae4 |
// expression it contains. 4/7/98 jhrg
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Removed spaces from the front of a URL and also from the front of the CE.
|
|
Packit |
a4aae4 |
This function assumes that there are no holes in both the URL and the CE.
|
|
Packit |
a4aae4 |
It will remove \e leading space, but not other spaces.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param name The URL to process
|
|
Packit |
a4aae4 |
@return Returns a new string object that contains the pruned URL. */
|
|
Packit |
a4aae4 |
string prune_spaces(const string &name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If the URL does not even have white space return.
|
|
Packit |
a4aae4 |
if (name.find_first_of(' ') == name.npos)
|
|
Packit |
a4aae4 |
return name;
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// Strip leading spaces from http://...
|
|
Packit |
a4aae4 |
unsigned int i = name.find_first_not_of(' ');
|
|
Packit |
a4aae4 |
string tmp_name = name.substr(i);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Strip leading spaces from constraint part (following `?').
|
|
Packit |
a4aae4 |
unsigned int j = tmp_name.find('?') + 1;
|
|
Packit |
a4aae4 |
i = tmp_name.find_first_not_of(' ', j);
|
|
Packit |
a4aae4 |
tmp_name.erase(j, i - j);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return tmp_name;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Compare elements in a list of (BaseType *)s and return true if there are
|
|
Packit |
a4aae4 |
// no duplicate elements, otherwise return false.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool unique_names(vector<BaseType *> l, const string &var_name, const string &type_name, string &msg)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// copy the identifier names to a vector
|
|
Packit |
a4aae4 |
vector<string> names(l.size());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int nelem = 0;
|
|
Packit |
a4aae4 |
typedef std::vector<BaseType *>::const_iterator citer;
|
|
Packit |
a4aae4 |
for (citer i = l.begin(); i != l.end(); i++) {
|
|
Packit |
a4aae4 |
assert(*i);
|
|
Packit |
a4aae4 |
names[nelem++] = (*i)->name();
|
|
Packit |
a4aae4 |
DBG(cerr << "NAMES[" << nelem - 1 << "]=" << names[nelem-1] << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// sort the array of names
|
|
Packit |
a4aae4 |
sort(names.begin(), names.end());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// sort the array of names
|
|
Packit |
a4aae4 |
sort(names.begin(), names.end());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// look for any instance of consecutive names that are ==
|
|
Packit |
a4aae4 |
for (int j = 1; j < nelem; ++j) {
|
|
Packit |
a4aae4 |
if (names[j - 1] == names[j]) {
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
oss << "The variable `" << names[j] << "' is used more than once in " << type_name << " `" << var_name
|
|
Packit |
a4aae4 |
<< "'";
|
|
Packit |
a4aae4 |
msg = oss.str();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
const char *
|
|
Packit |
a4aae4 |
libdap_root()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return LIBDAP_ROOT;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the version string for this package.
|
|
Packit |
a4aae4 |
@note This function has C linkage so that it can be found using autoconf
|
|
Packit |
a4aae4 |
tests.
|
|
Packit |
a4aae4 |
@return The version string. */
|
|
Packit |
a4aae4 |
extern "C" const char *
|
|
Packit |
a4aae4 |
libdap_version()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return PACKAGE_VERSION;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
extern "C" const char *
|
|
Packit |
a4aae4 |
libdap_name()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return PACKAGE_NAME;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Use the system time() function to get the current time. Return a string,
|
|
Packit |
a4aae4 |
* removing the trailing newline that time() includes in its response.
|
|
Packit |
a4aae4 |
* @return A C++ string with the current system time as formatted by time()
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string systime()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
time_t TimBin;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (time(&TimBin) == (time_t) -1)
|
|
Packit |
a4aae4 |
return string("time() error");
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
char *ctime_value = ctime(&TimBin);
|
|
Packit |
a4aae4 |
if (ctime_value) {
|
|
Packit |
a4aae4 |
string TimStr = ctime_value;
|
|
Packit |
a4aae4 |
return TimStr.substr(0, TimStr.size() - 2); // remove the \n
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
return "Unknown";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Downcase the source string. This function modifies its argument.
|
|
Packit |
a4aae4 |
* @param The string to modify
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void downcase(string &s)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
for (unsigned int i = 0; i < s.length(); i++)
|
|
Packit |
a4aae4 |
s[i] = tolower(s[i]);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Is the string surrounded by double quotes?
|
|
Packit |
a4aae4 |
* @param s The source string
|
|
Packit |
a4aae4 |
* @reurn True if the string is quoted, false otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool is_quoted(const string &s)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (!s.empty() && s[0] == '\"' && s[s.length() - 1] == '\"');
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Return a new string that is not quoted. This will return a new string
|
|
Packit |
a4aae4 |
* regardless of whether the source string is actualy quoted.
|
|
Packit |
a4aae4 |
* @param s The source string
|
|
Packit |
a4aae4 |
* @return A new string without quotes
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string remove_quotes(const string &s)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_quoted(s))
|
|
Packit |
a4aae4 |
return s.substr(1, s.length() - 2);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
return s;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the Type enumeration value which matches the given name. */
|
|
Packit |
a4aae4 |
Type get_type(const char *name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (strcmp(name, "Byte") == 0) return dods_byte_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Char") == 0) return dods_char_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Int8") == 0) return dods_int8_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "UInt8") == 0) return dods_uint8_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Int16") == 0) return dods_int16_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "UInt16") == 0) return dods_uint16_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Int32") == 0) return dods_int32_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "UInt32") == 0) return dods_uint32_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Int64") == 0) return dods_int64_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "UInt64") == 0) return dods_uint64_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Float32") == 0) return dods_float32_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Float64") == 0) return dods_float64_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "String") == 0) return dods_str_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// accept both spellings; this might be confusing since URL
|
|
Packit |
a4aae4 |
// could be filtered through code and come out Url. Don't know...
|
|
Packit |
a4aae4 |
// jhrg 8/15/13
|
|
Packit |
a4aae4 |
if (strcmp(name, "Url") == 0 || strcmp(name, "URL") == 0) return dods_url_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Enum") == 0) return dods_enum_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Opaque") == 0) return dods_opaque_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Array") == 0) return dods_array_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Structure") == 0) return dods_structure_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Sequence") == 0) return dods_sequence_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (strcmp(name, "Grid") == 0) return dods_grid_c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return dods_null_c;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Returns the type of the class instance as a string.
|
|
Packit |
a4aae4 |
* Supports all DAP2 types and not the DAP4-only types. Also
|
|
Packit |
a4aae4 |
* returns Url (DAP2) and not "URL" (DAP4) for the URL type.
|
|
Packit |
a4aae4 |
* @param t The type code
|
|
Packit |
a4aae4 |
* @return The type name in a string
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string D2type_name(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
case dods_null_c:
|
|
Packit |
a4aae4 |
return string("Null");
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
return string("Byte");
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
return string("Int16");
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
return string("UInt16");
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
return string("Int32");
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
return string("UInt32");
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
return string("Float32");
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
return string("Float64");
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
return string("String");
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
return string("Url");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
return string("Array");
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
return string("Structure");
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
return string("Sequence");
|
|
Packit |
a4aae4 |
case dods_grid_c:
|
|
Packit |
a4aae4 |
return string("Grid");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Unknown type.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Returns the type of the class instance as a string.
|
|
Packit |
a4aae4 |
* Supports all DAP4 types and not the DAP2-only types. Also
|
|
Packit |
a4aae4 |
* returns URL (DAP4) and not "Url" (DAP2) for the URL type.
|
|
Packit |
a4aae4 |
* @param t The type code
|
|
Packit |
a4aae4 |
* @return The type name in a string
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string D4type_name(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
case dods_null_c:
|
|
Packit |
a4aae4 |
return string("Null");
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
return string("Byte");
|
|
Packit |
a4aae4 |
case dods_char_c:
|
|
Packit |
a4aae4 |
return string("Char");
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
return string("Int8");
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
return string("UInt8");
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
return string("Int16");
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
return string("UInt16");
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
return string("Int32");
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
return string("UInt32");
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
return string("Int64");
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
return string("UInt64");
|
|
Packit |
a4aae4 |
case dods_enum_c:
|
|
Packit |
a4aae4 |
return string("Enum");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
return string("Float32");
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
return string("Float64");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
return string("String");
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
return string("URL");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_opaque_c:
|
|
Packit |
a4aae4 |
return string("Opaque");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
return string("Array");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
return string("Structure");
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
return string("Sequence");
|
|
Packit |
a4aae4 |
case dods_group_c:
|
|
Packit |
a4aae4 |
return string("Group");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "Unknown type.");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the type name. This function provides backward compatibility
|
|
Packit |
a4aae4 |
* for older code that predates, and has not been ported to, DAP4. It
|
|
Packit |
a4aae4 |
* is prejudiced toward DAP4, but if no D4 type name can be found, it
|
|
Packit |
a4aae4 |
* types D2. If neither would return a type name, and InternalErr object
|
|
Packit |
a4aae4 |
* is thrown.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param t The DAP2/DAP4 type
|
|
Packit |
a4aae4 |
* @return A string naming the type, suitable for humans
|
|
Packit |
a4aae4 |
* @exception InternalErr If not such type can be found
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string type_name(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
return D4type_name(t);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (...) {
|
|
Packit |
a4aae4 |
return D2type_name(t);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns true if the instance is a numeric, string or URL
|
|
Packit |
a4aae4 |
type variable.
|
|
Packit |
a4aae4 |
@return True if the instance is a scalar numeric, String or URL variable,
|
|
Packit |
a4aae4 |
False otherwise. Arrays (even of simple types) return False.
|
|
Packit |
a4aae4 |
@see is_vector_type() */
|
|
Packit |
a4aae4 |
bool is_simple_type(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
case dods_char_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
case dods_enum_c:
|
|
Packit |
a4aae4 |
case dods_opaque_c:
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_null_c:
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
case dods_grid_c:
|
|
Packit |
a4aae4 |
case dods_group_c:
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns true if the instance is a vector (i.e., array) type
|
|
Packit |
a4aae4 |
variable.
|
|
Packit |
a4aae4 |
@return True if the instance is an Array, False otherwise. */
|
|
Packit |
a4aae4 |
bool is_vector_type(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
case dods_null_c:
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
case dods_char_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
case dods_enum_c:
|
|
Packit |
a4aae4 |
case dods_opaque_c:
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
case dods_grid_c:
|
|
Packit |
a4aae4 |
case dods_group_c:
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Returns true if the instance is a constructor (i.e., Structure,
|
|
Packit |
a4aae4 |
Sequence or Grid) type variable.
|
|
Packit |
a4aae4 |
@return True if the instance is a Structure, Sequence or Grid, False
|
|
Packit |
a4aae4 |
otherwise. */
|
|
Packit |
a4aae4 |
bool is_constructor_type(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
case dods_null_c:
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
case dods_char_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_float32_c:
|
|
Packit |
a4aae4 |
case dods_float64_c:
|
|
Packit |
a4aae4 |
case dods_str_c:
|
|
Packit |
a4aae4 |
case dods_url_c:
|
|
Packit |
a4aae4 |
case dods_enum_c:
|
|
Packit |
a4aae4 |
case dods_opaque_c:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_array_c:
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
case dods_grid_c:
|
|
Packit |
a4aae4 |
case dods_group_c:
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Is this an integer type?
|
|
Packit |
a4aae4 |
* @return True if the type holds an integer value, false otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool is_integer_type(Type t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
switch (t) {
|
|
Packit |
a4aae4 |
case dods_byte_c:
|
|
Packit |
a4aae4 |
case dods_char_c:
|
|
Packit |
a4aae4 |
case dods_int8_c:
|
|
Packit |
a4aae4 |
case dods_uint8_c:
|
|
Packit |
a4aae4 |
case dods_int16_c:
|
|
Packit |
a4aae4 |
case dods_uint16_c:
|
|
Packit |
a4aae4 |
case dods_int32_c:
|
|
Packit |
a4aae4 |
case dods_uint32_c:
|
|
Packit |
a4aae4 |
case dods_int64_c:
|
|
Packit |
a4aae4 |
case dods_uint64_c:
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Does the directory exist?
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param dir The pathname to test.
|
|
Packit |
a4aae4 |
* @return True if the directory exists, false otherwise
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool dir_exists(const string &dir)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
struct stat buf;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return (stat(dir.c_str(), &buf) == 0) && (buf.st_mode & S_IFDIR);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Jose Garcia
|
|
Packit |
a4aae4 |
void append_long_to_string(long val, int base, string &str_val)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// The array digits contains 36 elements which are the
|
|
Packit |
a4aae4 |
// posible valid digits for out bases in the range
|
|
Packit |
a4aae4 |
// [2,36]
|
|
Packit |
a4aae4 |
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
Packit |
a4aae4 |
// result of val / base
|
|
Packit |
a4aae4 |
ldiv_t r;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (base > 36 || base < 2) {
|
|
Packit |
a4aae4 |
// no conversion if wrong base
|
|
Packit |
a4aae4 |
std::invalid_argument ex("The parameter base has an invalid value.");
|
|
Packit |
a4aae4 |
throw ex;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
if (val < 0) str_val += '-';
|
|
Packit |
a4aae4 |
r = ldiv(labs(val), base);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// output digits of val/base first
|
|
Packit |
a4aae4 |
if (r.quot > 0) append_long_to_string(r.quot, base, str_val);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// output last digit
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
str_val += digits[(int) r.rem];
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// base defaults to 10
|
|
Packit |
a4aae4 |
string long_to_string(long val, int base)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
string s;
|
|
Packit |
a4aae4 |
append_long_to_string(val, base, s);
|
|
Packit |
a4aae4 |
return s;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Jose Garcia
|
|
Packit |
a4aae4 |
void append_double_to_string(const double &num, string &str)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// s having 100 characters should be enough for sprintf to do its job.
|
|
Packit |
a4aae4 |
// I want to banish all instances of sprintf. 10/5/2001 jhrg
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
oss.precision(9);
|
|
Packit |
a4aae4 |
oss << num;
|
|
Packit |
a4aae4 |
str += oss.str();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string double_to_string(const double &num)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
string s;
|
|
Packit |
a4aae4 |
append_double_to_string(num, s);
|
|
Packit |
a4aae4 |
return s;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Given a pathname, return the file at the end of the path. This is used
|
|
Packit |
a4aae4 |
// when reporting errors (maybe other times, too) to keep the server from
|
|
Packit |
a4aae4 |
// revealing too much about its organization when sending error responses
|
|
Packit |
a4aae4 |
// back to clients. 10/11/2000 jhrg
|
|
Packit |
a4aae4 |
// MT-safe. 08/05/02 jhrg
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef WIN32
|
|
Packit |
a4aae4 |
static const char path_sep[] =
|
|
Packit |
a4aae4 |
{ "\\"
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
static const char path_sep[] = { "/" };
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the filename part from a path. This function can be used to return a
|
|
Packit |
a4aae4 |
string that has the directory components stripped from a path. This is
|
|
Packit |
a4aae4 |
useful when building error message strings.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
If WIN32 is defined, use '\' as the path separator, otherwise use '/' as
|
|
Packit |
a4aae4 |
the path separator.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return A string containing only the filename given a path. */
|
|
Packit |
a4aae4 |
string path_to_filename(string path)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
string::size_type pos = path.rfind(path_sep);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return (pos == string::npos) ? path : path.substr(++pos);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
|
|
Packit |
a4aae4 |
#define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/*
|
|
Packit |
a4aae4 |
* globchars() - build a bitlist to check for character group match
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static void globchars(const char *s, const char *e, char *b)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
int neg = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
memset(b, '\0', BITLISTSIZE);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (*s == '^') neg++, s++;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while (s < e) {
|
|
Packit |
a4aae4 |
int c;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (s + 2 < e && s[1] == '-') {
|
|
Packit |
a4aae4 |
for (c = s[0]; c <= s[2]; c++)
|
|
Packit |
a4aae4 |
b[c / 8] |= (1 << (c % 8));
|
|
Packit |
a4aae4 |
s += 3;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
c = *s++;
|
|
Packit |
a4aae4 |
b[c / 8] |= (1 << (c % 8));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (neg) {
|
|
Packit |
a4aae4 |
int i;
|
|
Packit |
a4aae4 |
for (i = 0; i < BITLISTSIZE; i++)
|
|
Packit |
a4aae4 |
b[i] ^= 0377;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/* Don't include \0 in either $[chars] or $[^chars] */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
b[0] &= 0376;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* glob: match a string against a simple pattern
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* Understands the following patterns:
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* * any number of characters
|
|
Packit |
a4aae4 |
* ? any single character
|
|
Packit |
a4aae4 |
* [a-z] any single character in the range a-z
|
|
Packit |
a4aae4 |
* [^a-z] any single character not in the range a-z
|
|
Packit |
a4aae4 |
* \x match x
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param c The pattern
|
|
Packit |
a4aae4 |
* @param s The string
|
|
Packit |
a4aae4 |
* @return 0 on success, -1 if the pattern is exhausted but there are
|
|
Packit |
a4aae4 |
* characters remaining in the string and 1 if the pattern does not match
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
int glob(const char *c, const char *s)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!c || !s) return 1;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
char bitlist[BITLISTSIZE];
|
|
Packit |
a4aae4 |
int i = 0;
|
|
Packit |
a4aae4 |
for (;;) {
|
|
Packit |
a4aae4 |
++i;
|
|
Packit |
a4aae4 |
switch (*c++) {
|
|
Packit |
a4aae4 |
case '\0':
|
|
Packit |
a4aae4 |
return *s ? -1 : 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case '?':
|
|
Packit |
a4aae4 |
if (!*s++) return i/*1*/;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case '[': {
|
|
Packit |
a4aae4 |
/* scan for matching ] */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
const char *here = c;
|
|
Packit |
a4aae4 |
do {
|
|
Packit |
a4aae4 |
if (!*c++) return i/*1*/;
|
|
Packit |
a4aae4 |
} while (here == c || *c != ']');
|
|
Packit |
a4aae4 |
c++;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/* build character class bitlist */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
globchars(here, c, bitlist);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!CHECK_BIT(bitlist, *(unsigned char * )s)) return i/*1*/;
|
|
Packit |
a4aae4 |
s++;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case '*': {
|
|
Packit |
a4aae4 |
const char *here = s;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while (*s)
|
|
Packit |
a4aae4 |
s++;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/* Try to match the rest of the pattern in a recursive */
|
|
Packit |
a4aae4 |
/* call. If the match fails we'll back up chars, retrying. */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while (s != here) {
|
|
Packit |
a4aae4 |
int r;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/* A fast path for the last token in a pattern */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
r = *c ? glob(c, s) : *s ? -1 : 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!r)
|
|
Packit |
a4aae4 |
return 0;
|
|
Packit |
a4aae4 |
else if (r < 0) return i/*1*/;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
--s;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case '\\':
|
|
Packit |
a4aae4 |
/* Force literal match of next char. */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!*c || *s++ != *c++) return i/*1*/;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
if (*s++ != c[-1]) return i/*1*/;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return 1; // Should never get here; this quiets gcc's warning
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @name Security functions */
|
|
Packit |
a4aae4 |
//@{
|
|
Packit |
a4aae4 |
/** @brief sanitize the size of an array.
|
|
Packit |
a4aae4 |
Test for integer overflow when dynamically allocating an array.
|
|
Packit |
a4aae4 |
@param nelem Number of elements.
|
|
Packit |
a4aae4 |
@param sz size of each element.
|
|
Packit |
a4aae4 |
@return True if the \c nelem elements of \c sz size will overflow an array. */
|
|
Packit |
a4aae4 |
bool size_ok(unsigned int sz, unsigned int nelem)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (sz > 0 && nelem < UINT_MAX / sz);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Does the string name a potentially valid pathname?
|
|
Packit |
a4aae4 |
Test the given pathname to verify that it is a valid name. We define this
|
|
Packit |
a4aae4 |
as: Contains only printable characters; and Is less then 256 characters.
|
|
Packit |
a4aae4 |
If \e strict is true, test that the pathname consists of only letters,
|
|
Packit |
a4aae4 |
digits, and underscore, dash and dot characters instead of the more general
|
|
Packit |
a4aae4 |
case where a pathname can be composed of any printable characters.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note Using this function does not guarantee that the path is valid, only
|
|
Packit |
a4aae4 |
that the path \e could be valid. The intent is foil attacks where an
|
|
Packit |
a4aae4 |
exploit is encoded in a string then passed to a library function. This code
|
|
Packit |
a4aae4 |
does not address whether the pathname references a valid resource.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param path The pathname to test
|
|
Packit |
a4aae4 |
@param strict Apply more restrictive tests (true by default)
|
|
Packit |
a4aae4 |
@return true if the pathname consists of legal characters and is of legal
|
|
Packit |
a4aae4 |
size, false otherwise. */
|
|
Packit |
a4aae4 |
bool pathname_ok(const string &path, bool strict)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (path.length() > 255) return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Regex name("[-0-9A-z_./]+");
|
|
Packit |
a4aae4 |
if (!strict) name = "[:print:]+";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string::size_type len = path.length();
|
|
Packit |
a4aae4 |
int result = name.match(path.c_str(), len);
|
|
Packit |
a4aae4 |
// Protect against casting too big an uint to int
|
|
Packit |
a4aae4 |
// if LEN is bigger than the max int32, the second test can't work
|
|
Packit |
a4aae4 |
if (len > INT_MAX || result != static_cast<int>(len)) return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//@}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Get the version of the DAP library.
|
|
Packit |
a4aae4 |
* @deprecated
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string dap_version()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (string) "OPeNDAP DAP/" + libdap_version() + ": compiled on " + __DATE__ + ":" + __TIME__;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Using the given template, open a temporary file using the given
|
|
Packit |
a4aae4 |
* ofstream object. Uses mkstemp() in a 'safe' way.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param f Value-result parameter
|
|
Packit |
a4aae4 |
* @param name_template The template used to name the temporary file.
|
|
Packit |
a4aae4 |
* The template has the form templateXXXXXX where the six Xs will be
|
|
Packit |
a4aae4 |
* overwritten.
|
|
Packit |
a4aae4 |
* @param suffix If present, the template is 'templateXXXXXX.suffix'
|
|
Packit |
a4aae4 |
* @return The new file's name.
|
|
Packit |
a4aae4 |
* @exception Error if there is a problem.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix /* = "" */)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
vector<char> name;
|
|
Packit |
a4aae4 |
copy(name_template.begin(), name_template.end(), back_inserter(name));
|
|
Packit |
a4aae4 |
if (!suffix.empty())
|
|
Packit |
a4aae4 |
copy(suffix.begin(), suffix.end(), back_inserter(name));
|
|
Packit |
a4aae4 |
name.push_back('\0');
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Use mkstemp to make and open the temp file atomically
|
|
Packit |
a4aae4 |
int tmpfile = mkstemps(&name[0], suffix.length());
|
|
Packit |
a4aae4 |
if (tmpfile == -1)
|
|
Packit |
a4aae4 |
throw Error(internal_error, "Could not make a temporary file.");
|
|
Packit |
a4aae4 |
// Open the file using C++ ofstream; get a C++ fstream object
|
|
Packit |
a4aae4 |
f.open(&name[0]);
|
|
Packit |
a4aae4 |
// Close the file descriptor; the file stays open because of the fstream object
|
|
Packit |
a4aae4 |
close(tmpfile);
|
|
Packit |
a4aae4 |
// Now test that the fstream object is valid
|
|
Packit |
a4aae4 |
if (f.fail())
|
|
Packit |
a4aae4 |
throw Error(internal_error, "Could not make a temporary file.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return string(&name[0]);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|