libdap
Updated for version 3.17.0
|
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