libdap  Updated for version 3.17.0
util.cc
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 
00025 // (c) COPYRIGHT URI/MIT 1994-1999
00026 // Please read the full copyright statement in the file COPYRIGHT_URI.
00027 //
00028 // Authors:
00029 //      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
00030 
00031 // Utility functions used by the api.
00032 //
00033 // jhrg 9/21/94
00034 
00035 #include "config.h"
00036 
00037 #include <fstream>
00038 
00039 #include <cassert>
00040 #include <cstring>
00041 #include <climits>
00042 
00043 #include <ctype.h>
00044 #ifndef TM_IN_SYS_TIME
00045 #include <time.h>
00046 #else
00047 #include <sys/time.h>
00048 #endif
00049 
00050 #ifndef WIN32
00051 #include <unistd.h>    // for stat
00052 #else
00053 #include <io.h>
00054 #include <fcntl.h>
00055 #include <process.h>
00056 #endif
00057 
00058 #include <sys/types.h>
00059 #include <sys/stat.h>
00060 
00061 #include <string>
00062 #include <sstream>
00063 #include <vector>
00064 #include <algorithm>
00065 #include <stdexcept>
00066 
00067 #include "BaseType.h"
00068 #include "Byte.h"
00069 #include "Int16.h"
00070 #include "Int32.h"
00071 #include "UInt16.h"
00072 #include "UInt32.h"
00073 #include "Float32.h"
00074 #include "Float64.h"
00075 #include "Str.h"
00076 #include "Array.h"
00077 
00078 #include "Int64.h"
00079 #include "UInt64.h"
00080 #include "Int8.h"
00081 
00082 #include "Error.h"
00083 
00084 #include "util.h"
00085 #include "GNURegex.h"
00086 #include "debug.h"
00087 
00088 using namespace std;
00089 
00090 namespace libdap {
00091 
00093 bool is_host_big_endian()
00094 {
00095 #ifdef COMPUTE_ENDIAN_AT_RUNTIME
00096 
00097     dods_int16 i = 0x0100;
00098     char *c = reinterpret_cast<char*>(&i);
00099     return *c;
00100 
00101 #else
00102 
00103 #ifdef __BIG_ENDIAN__
00104     return true;
00105 #else
00106     return false;
00107 #endif
00108 
00109 #endif
00110 }
00111 
00118 string extract_string_argument(BaseType *arg)
00119 {
00120     assert(arg);
00121 
00122     if (arg->type() != dods_str_c) throw Error(malformed_expr, "The function requires a string argument.");
00123 
00124     if (!arg->read_p())
00125         throw InternalErr(__FILE__, __LINE__,
00126                 "The CE Evaluator built an argument list where some constants held no values.");
00127 
00128     return static_cast<Str*>(arg)->value();
00129 }
00130 
00131 template<class T> static void set_array_using_double_helper(Array *a, double *src, int src_len)
00132 {
00133     assert(a);
00134     assert(src);
00135     assert(src_len > 0);
00136 
00137     vector<T> values(src_len);
00138     for (int i = 0; i < src_len; ++i)
00139         values[i] = (T) src[i];
00140 
00141     // This copies the values
00142     a->set_value(values, src_len);
00143 }
00144 
00165 void set_array_using_double(Array *dest, double *src, int src_len)
00166 {
00167     assert(dest);
00168     assert(src);
00169     assert(src_len > 0);
00170 
00171     // Simple types are Byte, ..., Float64, String and Url.
00172     if ((dest->type() == dods_array_c && !dest->var()->is_simple_type()) || dest->var()->type() == dods_str_c
00173             || dest->var()->type() == dods_url_c)
00174         throw InternalErr(__FILE__, __LINE__, "The function requires a numeric-type array argument.");
00175 
00176     // Test sizes. Note that Array::length() takes any constraint into account
00177     // when it returns the length. Even if this was removed, the 'helper'
00178     // function this uses calls Vector::val2buf() which uses Vector::width()
00179     // which in turn uses length().
00180     if (dest->length() != src_len)
00181         throw InternalErr(__FILE__, __LINE__,
00182                 "The source and destination array sizes don't match (" + long_to_string(src_len) + " versus "
00183                         + long_to_string(dest->length()) + ").");
00184 
00185     // The types of arguments that the CE Parser will build for numeric
00186     // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
00187     // Expanded to work for any numeric type so it can be used for more than
00188     // just arguments.
00189     switch (dest->var()->type()) {
00190     case dods_byte_c:
00191         set_array_using_double_helper<dods_byte>(dest, src, src_len);
00192         break;
00193     case dods_uint16_c:
00194         set_array_using_double_helper<dods_uint16>(dest, src, src_len);
00195         break;
00196     case dods_int16_c:
00197         set_array_using_double_helper<dods_int16>(dest, src, src_len);
00198         break;
00199     case dods_uint32_c:
00200         set_array_using_double_helper<dods_uint32>(dest, src, src_len);
00201         break;
00202     case dods_int32_c:
00203         set_array_using_double_helper<dods_int32>(dest, src, src_len);
00204         break;
00205     case dods_float32_c:
00206         set_array_using_double_helper<dods_float32>(dest, src, src_len);
00207         break;
00208     case dods_float64_c:
00209         set_array_using_double_helper<dods_float64>(dest, src, src_len);
00210         break;
00211 
00212         // DAP4 support
00213     case dods_uint8_c:
00214         set_array_using_double_helper<dods_byte>(dest, src, src_len);
00215         break;
00216     case dods_int8_c:
00217         set_array_using_double_helper<dods_int8>(dest, src, src_len);
00218         break;
00219     case dods_uint64_c:
00220         set_array_using_double_helper<dods_uint64>(dest, src, src_len);
00221         break;
00222     case dods_int64_c:
00223         set_array_using_double_helper<dods_int64>(dest, src, src_len);
00224         break;
00225     default:
00226         throw InternalErr(__FILE__, __LINE__,
00227                 "The argument list built by the CE parser contained an unsupported numeric type.");
00228     }
00229 
00230     // Set the read_p property.
00231     dest->set_read_p(true);
00232 }
00233 
00234 template<class T> static double *extract_double_array_helper(Array * a)
00235 {
00236     assert(a);
00237 
00238     int length = a->length();
00239 
00240     vector<T> b(length);
00241     a->value(&b[0]);    // Extract the values of 'a' to 'b'
00242 
00243     double *dest = new double[length];
00244     for (int i = 0; i < length; ++i)
00245         dest[i] = (double) b[i];
00246 
00247     return dest;
00248 }
00249 
00260 double *extract_double_array(Array * a)
00261 {
00262     assert(a);
00263 
00264     // Simple types are Byte, ..., Float64, String and Url.
00265     if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
00266             || a->var()->type() == dods_url_c)
00267         throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
00268 
00269     if (!a->read_p())
00270         throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "'does not contain values.");
00271 
00272     // The types of arguments that the CE Parser will build for numeric
00273     // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
00274     // Expanded to work for any numeric type so it can be used for more than
00275     // just arguments.
00276     switch (a->var()->type()) {
00277     case dods_byte_c:
00278         return extract_double_array_helper<dods_byte>(a);
00279     case dods_uint16_c:
00280         return extract_double_array_helper<dods_uint16>(a);
00281     case dods_int16_c:
00282         return extract_double_array_helper<dods_int16>(a);
00283     case dods_uint32_c:
00284         return extract_double_array_helper<dods_uint32>(a);
00285     case dods_int32_c:
00286         return extract_double_array_helper<dods_int32>(a);
00287     case dods_float32_c:
00288         return extract_double_array_helper<dods_float32>(a);
00289     case dods_float64_c:
00290         // Should not be copying these values, just read them,
00291         // but older code may depend on the return of this function
00292         // being something that should be deleted, so leave this
00293         // alone. jhrg 2/24/15
00294         return extract_double_array_helper<dods_float64>(a);
00295 
00296         // Support for DAP4
00297     case dods_uint8_c:
00298         return extract_double_array_helper<dods_byte>(a);
00299     case dods_int8_c:
00300         return extract_double_array_helper<dods_int8>(a);
00301     case dods_uint64_c:
00302         return extract_double_array_helper<dods_uint64>(a);
00303     case dods_int64_c:
00304         return extract_double_array_helper<dods_int64>(a);
00305     default:
00306         throw InternalErr(__FILE__, __LINE__,
00307                 "The argument list built by the CE parser contained an unsupported numeric type.");
00308     }
00309 }
00310 
00311 // This helper function assumes 'dest' is the correct size. This should not
00312 // be called when the Array 'a' is a Float64, since the values are already
00313 // in a double array!
00314 template<class T> static void extract_double_array_helper(Array * a, vector<double> &dest)
00315 {
00316     assert(a);
00317     assert(dest.size() == (unsigned long )a->length());
00318 
00319     int length = a->length();
00320 
00321     vector<T> b(length);
00322     a->value(&b[0]);    // Extract the values of 'a' to 'b'
00323 
00324     for (int i = 0; i < length; ++i)
00325         dest[i] = (double) b[i];
00326 }
00327 
00339 void extract_double_array(Array *a, vector<double> &dest)
00340 {
00341     assert(a);
00342 
00343     // Simple types are Byte, ..., Float64, String and Url.
00344     if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
00345             || a->var()->type() == dods_url_c)
00346         throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
00347 
00348     if (!a->read_p())
00349         throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "'does not contain values.");
00350 
00351     dest.resize(a->length());
00352 
00353     // The types of arguments that the CE Parser will build for numeric
00354     // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
00355     // Expanded to work for any numeric type so it can be used for more than
00356     // just arguments.
00357     switch (a->var()->type()) {
00358     case dods_byte_c:
00359         return extract_double_array_helper<dods_byte>(a, dest);
00360     case dods_uint16_c:
00361         return extract_double_array_helper<dods_uint16>(a, dest);
00362     case dods_int16_c:
00363         return extract_double_array_helper<dods_int16>(a, dest);
00364     case dods_uint32_c:
00365         return extract_double_array_helper<dods_uint32>(a, dest);
00366     case dods_int32_c:
00367         return extract_double_array_helper<dods_int32>(a, dest);
00368     case dods_float32_c:
00369         return extract_double_array_helper<dods_float32>(a, dest);
00370     case dods_float64_c:
00371         return a->value(&dest[0]);      // no need to copy the values
00372         // return extract_double_array_helper<dods_float64>(a, dest);
00373 
00374         // Support for DAP4
00375     case dods_uint8_c:
00376         return extract_double_array_helper<dods_byte>(a, dest);
00377     case dods_int8_c:
00378         return extract_double_array_helper<dods_int8>(a, dest);
00379     case dods_uint64_c:
00380         return extract_double_array_helper<dods_uint64>(a, dest);
00381     case dods_int64_c:
00382         return extract_double_array_helper<dods_int64>(a, dest);
00383     default:
00384         throw InternalErr(__FILE__, __LINE__,
00385                 "The argument list built by the CE parser contained an unsupported numeric type.");
00386     }
00387 }
00388 
00398 double extract_double_value(BaseType *arg)
00399 {
00400     assert(arg);
00401 
00402     // Simple types are Byte, ..., Float64, String and Url.
00403     if (!arg->is_simple_type() || arg->type() == dods_str_c || arg->type() == dods_url_c)
00404         throw Error(malformed_expr, "The function requires a numeric-type argument.");
00405 
00406     if (!arg->read_p())
00407         throw InternalErr(__FILE__, __LINE__,
00408                 "The Evaluator built an argument list where some constants held no values.");
00409 
00410     // The types of arguments that the CE Parser will build for numeric
00411     // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
00412     // Expanded to work for any numeric type so it can be used for more than
00413     // just arguments.
00414     switch (arg->type()) {
00415     case dods_byte_c:
00416         return (double) (static_cast<Byte*>(arg)->value());
00417     case dods_uint16_c:
00418         return (double) (static_cast<UInt16*>(arg)->value());
00419     case dods_int16_c:
00420         return (double) (static_cast<Int16*>(arg)->value());
00421     case dods_uint32_c:
00422         return (double) (static_cast<UInt32*>(arg)->value());
00423     case dods_int32_c:
00424         return (double) (static_cast<Int32*>(arg)->value());
00425     case dods_float32_c:
00426         return (double) (static_cast<Float32*>(arg)->value());
00427     case dods_float64_c:
00428         return static_cast<Float64*>(arg)->value();
00429 
00430         // Support for DAP4 types.
00431     case dods_uint8_c:
00432         return (double) (static_cast<Byte*>(arg)->value());
00433     case dods_int8_c:
00434         return (double) (static_cast<Int8*>(arg)->value());
00435     case dods_uint64_c:
00436         return (double) (static_cast<UInt64*>(arg)->value());
00437     case dods_int64_c:
00438         return (double) (static_cast<Int64*>(arg)->value());
00439 
00440     default:
00441         throw InternalErr(__FILE__, __LINE__,
00442                 "The argument list built by the parser contained an unsupported numeric type.");
00443     }
00444 }
00445 
00446 // Remove spaces from the start of a URL and from the start of any constraint
00447 // expression it contains. 4/7/98 jhrg
00448 
00455 string prune_spaces(const string &name)
00456 {
00457     // If the URL does not even have white space return.
00458     if (name.find_first_of(' ') == name.npos)
00459         return name;
00460     else {
00461         // Strip leading spaces from http://...
00462         unsigned int i = name.find_first_not_of(' ');
00463         string tmp_name = name.substr(i);
00464 
00465         // Strip leading spaces from constraint part (following `?').
00466         unsigned int j = tmp_name.find('?') + 1;
00467         i = tmp_name.find_first_not_of(' ', j);
00468         tmp_name.erase(j, i - j);
00469 
00470         return tmp_name;
00471     }
00472 }
00473 
00474 // Compare elements in a list of (BaseType *)s and return true if there are
00475 // no duplicate elements, otherwise return false.
00476 
00477 bool unique_names(vector<BaseType *> l, const string &var_name, const string &type_name, string &msg)
00478 {
00479     // copy the identifier names to a vector
00480     vector<string> names(l.size());
00481 
00482     int nelem = 0;
00483     typedef std::vector<BaseType *>::const_iterator citer;
00484     for (citer i = l.begin(); i != l.end(); i++) {
00485         assert(*i);
00486         names[nelem++] = (*i)->name();
00487         DBG(cerr << "NAMES[" << nelem - 1 << "]=" << names[nelem-1] << endl);
00488     }
00489 
00490     // sort the array of names
00491     sort(names.begin(), names.end());
00492 
00493     // sort the array of names
00494     sort(names.begin(), names.end());
00495 
00496     // look for any instance of consecutive names that are ==
00497     for (int j = 1; j < nelem; ++j) {
00498         if (names[j - 1] == names[j]) {
00499             ostringstream oss;
00500             oss << "The variable `" << names[j] << "' is used more than once in " << type_name << " `" << var_name
00501                     << "'";
00502             msg = oss.str();
00503 
00504             return false;
00505         }
00506     }
00507 
00508     return true;
00509 }
00510 
00511 const char *
00512 libdap_root()
00513 {
00514     return LIBDAP_ROOT;
00515 }
00516 
00521 extern "C" const char *
00522 libdap_version()
00523 {
00524     return PACKAGE_VERSION;
00525 }
00526 
00527 extern "C" const char *
00528 libdap_name()
00529 {
00530     return PACKAGE_NAME;
00531 }
00532 
00538 string systime()
00539 {
00540     time_t TimBin;
00541 
00542     if (time(&TimBin) == (time_t) -1)
00543         return string("time() error");
00544     else {
00545         char *ctime_value = ctime(&TimBin);
00546         if (ctime_value) {
00547             string TimStr = ctime_value;
00548             return TimStr.substr(0, TimStr.size() - 2); // remove the \n
00549         }
00550         else
00551             return "Unknown";
00552     }
00553 }
00554 
00559 void downcase(string &s)
00560 {
00561     for (unsigned int i = 0; i < s.length(); i++)
00562         s[i] = tolower(s[i]);
00563 }
00564 
00570 bool is_quoted(const string &s)
00571 {
00572     return (!s.empty() && s[0] == '\"' && s[s.length() - 1] == '\"');
00573 }
00574 
00581 string remove_quotes(const string &s)
00582 {
00583     if (is_quoted(s))
00584         return s.substr(1, s.length() - 2);
00585     else
00586         return s;
00587 }
00588 
00590 Type get_type(const char *name)
00591 {
00592     if (strcmp(name, "Byte") == 0) return dods_byte_c;
00593 
00594     if (strcmp(name, "Char") == 0) return dods_char_c;
00595 
00596     if (strcmp(name, "Int8") == 0) return dods_int8_c;
00597 
00598     if (strcmp(name, "UInt8") == 0) return dods_uint8_c;
00599 
00600     if (strcmp(name, "Int16") == 0) return dods_int16_c;
00601 
00602     if (strcmp(name, "UInt16") == 0) return dods_uint16_c;
00603 
00604     if (strcmp(name, "Int32") == 0) return dods_int32_c;
00605 
00606     if (strcmp(name, "UInt32") == 0) return dods_uint32_c;
00607 
00608     if (strcmp(name, "Int64") == 0) return dods_int64_c;
00609 
00610     if (strcmp(name, "UInt64") == 0) return dods_uint64_c;
00611 
00612     if (strcmp(name, "Float32") == 0) return dods_float32_c;
00613 
00614     if (strcmp(name, "Float64") == 0) return dods_float64_c;
00615 
00616     if (strcmp(name, "String") == 0) return dods_str_c;
00617 
00618     // accept both spellings; this might be confusing since URL
00619     // could be filtered through code and come out Url. Don't know...
00620     // jhrg 8/15/13
00621     if (strcmp(name, "Url") == 0 || strcmp(name, "URL") == 0) return dods_url_c;
00622 
00623     if (strcmp(name, "Enum") == 0) return dods_enum_c;
00624 
00625     if (strcmp(name, "Opaque") == 0) return dods_opaque_c;
00626 
00627     if (strcmp(name, "Array") == 0) return dods_array_c;
00628 
00629     if (strcmp(name, "Structure") == 0) return dods_structure_c;
00630 
00631     if (strcmp(name, "Sequence") == 0) return dods_sequence_c;
00632 
00633     if (strcmp(name, "Grid") == 0) return dods_grid_c;
00634 
00635     return dods_null_c;
00636 }
00637 
00645 string D2type_name(Type t)
00646 {
00647     switch (t) {
00648     case dods_null_c:
00649         return string("Null");
00650     case dods_byte_c:
00651         return string("Byte");
00652     case dods_int16_c:
00653         return string("Int16");
00654     case dods_uint16_c:
00655         return string("UInt16");
00656     case dods_int32_c:
00657         return string("Int32");
00658     case dods_uint32_c:
00659         return string("UInt32");
00660     case dods_float32_c:
00661         return string("Float32");
00662     case dods_float64_c:
00663         return string("Float64");
00664     case dods_str_c:
00665         return string("String");
00666     case dods_url_c:
00667         return string("Url");
00668 
00669     case dods_array_c:
00670         return string("Array");
00671     case dods_structure_c:
00672         return string("Structure");
00673     case dods_sequence_c:
00674         return string("Sequence");
00675     case dods_grid_c:
00676         return string("Grid");
00677 
00678     default:
00679         throw InternalErr(__FILE__, __LINE__, "Unknown type.");
00680     }
00681 }
00682 
00690 string D4type_name(Type t)
00691 {
00692     switch (t) {
00693     case dods_null_c:
00694         return string("Null");
00695     case dods_byte_c:
00696         return string("Byte");
00697     case dods_char_c:
00698         return string("Char");
00699     case dods_int8_c:
00700         return string("Int8");
00701     case dods_uint8_c:
00702         return string("UInt8");
00703     case dods_int16_c:
00704         return string("Int16");
00705     case dods_uint16_c:
00706         return string("UInt16");
00707     case dods_int32_c:
00708         return string("Int32");
00709     case dods_uint32_c:
00710         return string("UInt32");
00711     case dods_int64_c:
00712         return string("Int64");
00713     case dods_uint64_c:
00714         return string("UInt64");
00715     case dods_enum_c:
00716         return string("Enum");
00717 
00718     case dods_float32_c:
00719         return string("Float32");
00720     case dods_float64_c:
00721         return string("Float64");
00722 
00723     case dods_str_c:
00724         return string("String");
00725     case dods_url_c:
00726         return string("URL");
00727 
00728     case dods_opaque_c:
00729         return string("Opaque");
00730 
00731     case dods_array_c:
00732         return string("Array");
00733 
00734     case dods_structure_c:
00735         return string("Structure");
00736     case dods_sequence_c:
00737         return string("Sequence");
00738     case dods_group_c:
00739         return string("Group");
00740 
00741     default:
00742         throw InternalErr(__FILE__, __LINE__, "Unknown type.");
00743     }
00744 }
00745 
00756 string type_name(Type t)
00757 {
00758     try {
00759         return D4type_name(t);
00760     }
00761     catch (...) {
00762         return D2type_name(t);
00763     }
00764 }
00765 
00771 bool is_simple_type(Type t)
00772 {
00773     switch (t) {
00774 
00775     case dods_byte_c:
00776     case dods_char_c:
00777 
00778     case dods_int8_c:
00779     case dods_uint8_c:
00780 
00781     case dods_int16_c:
00782     case dods_uint16_c:
00783     case dods_int32_c:
00784     case dods_uint32_c:
00785 
00786     case dods_int64_c:
00787     case dods_uint64_c:
00788 
00789     case dods_float32_c:
00790     case dods_float64_c:
00791     case dods_str_c:
00792     case dods_url_c:
00793     case dods_enum_c:
00794     case dods_opaque_c:
00795         return true;
00796 
00797     case dods_null_c:
00798     case dods_array_c:
00799     case dods_structure_c:
00800     case dods_sequence_c:
00801     case dods_grid_c:
00802     case dods_group_c:
00803     default:
00804         return false;
00805     }
00806 
00807     return false;
00808 }
00809 
00813 bool is_vector_type(Type t)
00814 {
00815     switch (t) {
00816     case dods_null_c:
00817     case dods_byte_c:
00818     case dods_char_c:
00819 
00820     case dods_int8_c:
00821     case dods_uint8_c:
00822 
00823     case dods_int16_c:
00824     case dods_uint16_c:
00825 
00826     case dods_int32_c:
00827     case dods_uint32_c:
00828 
00829     case dods_int64_c:
00830     case dods_uint64_c:
00831 
00832     case dods_float32_c:
00833     case dods_float64_c:
00834 
00835     case dods_str_c:
00836     case dods_url_c:
00837     case dods_enum_c:
00838     case dods_opaque_c:
00839         return false;
00840 
00841     case dods_array_c:
00842         return true;
00843 
00844     case dods_structure_c:
00845     case dods_sequence_c:
00846     case dods_grid_c:
00847     case dods_group_c:
00848     default:
00849         return false;
00850     }
00851 
00852     return false;
00853 }
00854 
00859 bool is_constructor_type(Type t)
00860 {
00861     switch (t) {
00862     case dods_null_c:
00863     case dods_byte_c:
00864     case dods_char_c:
00865 
00866     case dods_int8_c:
00867     case dods_uint8_c:
00868 
00869     case dods_int16_c:
00870     case dods_uint16_c:
00871     case dods_int32_c:
00872     case dods_uint32_c:
00873 
00874     case dods_int64_c:
00875     case dods_uint64_c:
00876 
00877     case dods_float32_c:
00878     case dods_float64_c:
00879     case dods_str_c:
00880     case dods_url_c:
00881     case dods_enum_c:
00882     case dods_opaque_c:
00883 
00884     case dods_array_c:
00885         return false;
00886 
00887     case dods_structure_c:
00888     case dods_sequence_c:
00889     case dods_grid_c:
00890     case dods_group_c:
00891     default:
00892         return true;
00893     }
00894 
00895     return false;
00896 }
00897 
00902 bool is_integer_type(Type t)
00903 {
00904     switch (t) {
00905     case dods_byte_c:
00906     case dods_char_c:
00907     case dods_int8_c:
00908     case dods_uint8_c:
00909     case dods_int16_c:
00910     case dods_uint16_c:
00911     case dods_int32_c:
00912     case dods_uint32_c:
00913     case dods_int64_c:
00914     case dods_uint64_c:
00915         return true;
00916     default:
00917         return false;
00918     }
00919 }
00920 
00927 bool dir_exists(const string &dir)
00928 {
00929     struct stat buf;
00930 
00931     return (stat(dir.c_str(), &buf) == 0) && (buf.st_mode & S_IFDIR);
00932 }
00933 
00934 // Jose Garcia
00935 void append_long_to_string(long val, int base, string &str_val)
00936 {
00937     // The array digits contains 36 elements which are the
00938     // posible valid digits for out bases in the range
00939     // [2,36]
00940     char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00941     // result of val / base
00942     ldiv_t r;
00943 
00944     if (base > 36 || base < 2) {
00945         // no conversion if wrong base
00946         std::invalid_argument ex("The parameter base has an invalid value.");
00947         throw ex;
00948     }
00949     if (val < 0) str_val += '-';
00950     r = ldiv(labs(val), base);
00951 
00952     // output digits of val/base first
00953     if (r.quot > 0) append_long_to_string(r.quot, base, str_val);
00954 
00955     // output last digit
00956 
00957     str_val += digits[(int) r.rem];
00958 }
00959 
00960 // base defaults to 10
00961 string long_to_string(long val, int base)
00962 {
00963     string s;
00964     append_long_to_string(val, base, s);
00965     return s;
00966 }
00967 
00968 // Jose Garcia
00969 void append_double_to_string(const double &num, string &str)
00970 {
00971     // s having 100 characters should be enough for sprintf to do its job.
00972     // I want to banish all instances of sprintf. 10/5/2001 jhrg
00973     ostringstream oss;
00974     oss.precision(9);
00975     oss << num;
00976     str += oss.str();
00977 }
00978 
00979 string double_to_string(const double &num)
00980 {
00981     string s;
00982     append_double_to_string(num, s);
00983     return s;
00984 }
00985 
00986 // Given a pathname, return the file at the end of the path. This is used
00987 // when reporting errors (maybe other times, too) to keep the server from
00988 // revealing too much about its organization when sending error responses
00989 // back to clients. 10/11/2000 jhrg
00990 // MT-safe. 08/05/02 jhrg
00991 
00992 #ifdef WIN32
00993 static const char path_sep[] =
00994 {   "\\"
00995 };
00996 #else
00997 static const char path_sep[] = { "/" };
00998 #endif
00999 
01008 string path_to_filename(string path)
01009 {
01010     string::size_type pos = path.rfind(path_sep);
01011 
01012     return (pos == string::npos) ? path : path.substr(++pos);
01013 }
01014 
01015 #define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
01016 #define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
01017 
01018 /*
01019  * globchars() - build a bitlist to check for character group match
01020  */
01021 
01022 static void globchars(const char *s, const char *e, char *b)
01023 {
01024     int neg = 0;
01025 
01026     memset(b, '\0', BITLISTSIZE);
01027 
01028     if (*s == '^') neg++, s++;
01029 
01030     while (s < e) {
01031         int c;
01032 
01033         if (s + 2 < e && s[1] == '-') {
01034             for (c = s[0]; c <= s[2]; c++)
01035                 b[c / 8] |= (1 << (c % 8));
01036             s += 3;
01037         }
01038         else {
01039             c = *s++;
01040             b[c / 8] |= (1 << (c % 8));
01041         }
01042     }
01043 
01044     if (neg) {
01045         int i;
01046         for (i = 0; i < BITLISTSIZE; i++)
01047             b[i] ^= 0377;
01048     }
01049 
01050     /* Don't include \0 in either $[chars] or $[^chars] */
01051 
01052     b[0] &= 0376;
01053 }
01054 
01071 int glob(const char *c, const char *s)
01072 {
01073     if (!c || !s) return 1;
01074 
01075     char bitlist[BITLISTSIZE];
01076     int i = 0;
01077     for (;;) {
01078         ++i;
01079         switch (*c++) {
01080         case '\0':
01081             return *s ? -1 : 0;
01082 
01083         case '?':
01084             if (!*s++) return i/*1*/;
01085             break;
01086 
01087         case '[': {
01088             /* scan for matching ] */
01089 
01090             const char *here = c;
01091             do {
01092                 if (!*c++) return i/*1*/;
01093             } while (here == c || *c != ']');
01094             c++;
01095 
01096             /* build character class bitlist */
01097 
01098             globchars(here, c, bitlist);
01099 
01100             if (!CHECK_BIT(bitlist, *(unsigned char * )s)) return i/*1*/;
01101             s++;
01102             break;
01103         }
01104 
01105         case '*': {
01106             const char *here = s;
01107 
01108             while (*s)
01109                 s++;
01110 
01111             /* Try to match the rest of the pattern in a recursive */
01112             /* call.  If the match fails we'll back up chars, retrying. */
01113 
01114             while (s != here) {
01115                 int r;
01116 
01117                 /* A fast path for the last token in a pattern */
01118 
01119                 r = *c ? glob(c, s) : *s ? -1 : 0;
01120 
01121                 if (!r)
01122                     return 0;
01123                 else if (r < 0) return i/*1*/;
01124 
01125                 --s;
01126             }
01127             break;
01128         }
01129 
01130         case '\\':
01131             /* Force literal match of next char. */
01132 
01133             if (!*c || *s++ != *c++) return i/*1*/;
01134             break;
01135 
01136         default:
01137             if (*s++ != c[-1]) return i/*1*/;
01138             break;
01139         }
01140     }
01141 
01142     return 1;   // Should never get here; this quiets gcc's warning
01143 }
01144 
01152 bool size_ok(unsigned int sz, unsigned int nelem)
01153 {
01154     return (sz > 0 && nelem < UINT_MAX / sz);
01155 }
01156 
01173 bool pathname_ok(const string &path, bool strict)
01174 {
01175     if (path.length() > 255) return false;
01176 
01177     Regex name("[-0-9A-z_./]+");
01178     if (!strict) name = "[:print:]+";
01179 
01180     string::size_type len = path.length();
01181     int result = name.match(path.c_str(), len);
01182     // Protect against casting too big an uint to int
01183     // if LEN is bigger than the max int32, the second test can't work
01184     if (len > INT_MAX || result != static_cast<int>(len)) return false;
01185 
01186     return true;
01187 }
01188 
01190 
01195 string dap_version()
01196 {
01197     return (string) "OPeNDAP DAP/" + libdap_version() + ": compiled on " + __DATE__ + ":" + __TIME__;
01198 }
01199 
01212 string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix /* = "" */)
01213 {
01214     vector<char> name;
01215     copy(name_template.begin(), name_template.end(), back_inserter(name));
01216     if (!suffix.empty())
01217         copy(suffix.begin(), suffix.end(), back_inserter(name));
01218     name.push_back('\0');
01219 
01220     // Use mkstemp to make and open the temp file atomically
01221     int tmpfile = mkstemps(&name[0], suffix.length());
01222     if (tmpfile == -1)
01223         throw Error(internal_error, "Could not make a temporary file.");
01224     // Open the file using C++ ofstream; get a C++ fstream object
01225     f.open(&name[0]);
01226     // Close the file descriptor; the file stays open because of the fstream object
01227     close(tmpfile);
01228     // Now test that the fstream object is valid
01229     if (f.fail())
01230         throw Error(internal_error, "Could not make a temporary file.");
01231 
01232     return string(&name[0]);
01233 }
01234 
01235 
01236 } // namespace libdap
01237