libdap++ Updated for version 3.8.2
|
00001 00002 // -*- mode: c++; c-basic-offset:4 -*- 00003 00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00005 // Access Protocol. 00006 00007 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00008 // Author: James Gallagher <jgallagher@opendap.org> 00009 // 00010 // This library is free software; you can redistribute it and/or 00011 // modify it under the terms of the GNU Lesser General Public 00012 // License as published by the Free Software Foundation; either 00013 // version 2.1 of the License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 // 00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00025 00026 // (c) COPYRIGHT URI/MIT 1995-1999 00027 // Please read the full copyright statement in the file COPYRIGHT_URI. 00028 // 00029 // Authors: 00030 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00031 00032 // These functions are utility functions used by the various DAP parsers (the 00033 // DAS, DDS and constraint expression parsers). 00034 // jhrg 9/7/95 00035 00036 #include "config.h" 00037 00038 static char rcsid[] not_used = 00039 { "$Id: parser-util.cc 22703 2010-05-11 18:10:01Z jimg $" 00040 }; 00041 00042 #include <cerrno> 00043 #include <cassert> 00044 #include <cstring> 00045 #include <cmath> 00046 #include <cstdlib> 00047 00048 #include <iostream> 00049 #include <sstream> 00050 00051 // We wrap VC++ 6.x strtod() to account for a short comming 00052 // in that function in regards to "NaN". 00053 #ifdef WIN32 00054 #include <limits> 00055 double w32strtod(const char *, char **); 00056 #endif 00057 00058 #include "debug.h" 00059 #include "parser.h" // defines constants such as ID_MAX 00060 #include "dods-limits.h" 00061 #include "util.h" // Jose Garcia: for append_long_to_string. 00062 00063 using std::cerr; 00064 using std::endl; 00065 00066 #ifdef WIN32 00067 // VC++ 6.x strtod() doesn't recognize "NaN". Account for it 00068 // by wrapping it around a check for the Nan string. Use of 00069 // the product is obsolete as of 1/2007, but it is unknown if 00070 // the issue is still there in later releases of that product. 00071 // ROM - 01/2007 00072 double w32strtod(const char *val, char **ptr) 00073 { 00074 // Convert the two char arrays to compare to strings. 00075 string *sval = new string(val); 00076 string *snan = new string("NaN"); 00077 00078 // If val doesn't contain "NaN|Nan|nan|etc", use strtod as 00079 // provided. 00080 if (stricmp(sval->c_str(), snan->c_str()) != 0) 00081 return (strtod(val, ptr)); 00082 00083 // But if it does, return the bit pattern for Nan and point 00084 // the parsing ptr arg at the trailing '\0'. 00085 *ptr = (char *) val + strlen(val); 00086 return (std::numeric_limits < double >::quiet_NaN()); 00087 } 00088 #endif 00089 00090 namespace libdap { 00091 00092 // Deprecated, but still used by the HDF4 EOS server code. 00093 void 00094 parse_error(parser_arg * arg, const char *msg, const int line_num, 00095 const char *context) 00096 { 00097 // Jose Garcia 00098 // This assert(s) is (are) only for developing purposes 00099 // For production servers remove it by compiling with NDEBUG 00100 assert(arg); 00101 assert(msg); 00102 00103 arg->set_status(FALSE); 00104 00105 string oss = ""; 00106 00107 if (line_num != 0) { 00108 oss += "Error parsing the text on line "; 00109 append_long_to_string(line_num, 10, oss); 00110 } 00111 else { 00112 oss += "Parse error."; 00113 } 00114 00115 if (context) 00116 oss += (string) " at or near: " + context + (string) "\n" + msg 00117 + (string) "\n"; 00118 else 00119 oss += (string) "\n" + msg + (string) "\n"; 00120 00121 arg->set_error(new Error(unknown_error, oss)); 00122 } 00123 00124 void 00125 parse_error(const char *msg, const int line_num, const char *context) 00126 { 00127 // Jose Garcia 00128 // This assert(s) is (are) only for developing purposes 00129 // For production servers remove it by compiling with NDEBUG 00130 assert(msg); 00131 00132 string oss = ""; 00133 00134 if (line_num != 0) { 00135 oss += "Error parsing the text on line "; 00136 append_long_to_string(line_num, 10, oss); 00137 } 00138 else { 00139 oss += "Parse error."; 00140 } 00141 00142 if (context) 00143 oss += (string) " at or near: " + context + (string) "\n" + msg 00144 + (string) "\n"; 00145 else 00146 oss += (string) "\n" + msg + (string) "\n"; 00147 00148 throw Error(oss); 00149 } 00150 00151 // context comes from the parser and will always be a char * unless the 00152 // parsers change dramatically. 00153 void 00154 parse_error(const string & msg, const int line_num, const char *context) 00155 { 00156 parse_error(msg.c_str(), line_num, context); 00157 } 00158 00159 void save_str(char *dst, const char *src, const int line_num) 00160 { 00161 if (strlen(src) >= ID_MAX) 00162 parse_error(string("The word `") + string(src) 00163 + string("' is too long (it should be no longer than ") 00164 + long_to_string(ID_MAX) + string(")."), line_num); 00165 00166 strncpy(dst, src, ID_MAX); 00167 dst[ID_MAX - 1] = '\0'; /* in case ... */ 00168 } 00169 00170 void save_str(string & dst, const char *src, const int) 00171 { 00172 dst = src; 00173 } 00174 00175 bool is_keyword(string id, const string & keyword) 00176 { 00177 downcase(id); 00178 id = prune_spaces(id); 00179 DBG(cerr << "is_keyword: " << keyword << " = " << id << endl); 00180 return id == keyword; 00181 } 00182 00183 int check_byte(const char *val) 00184 { 00185 char *ptr; 00186 long v = strtol(val, &ptr, 0); 00187 00188 if ((v == 0 && val == ptr) || *ptr != '\0') { 00189 return FALSE; 00190 } 00191 00192 DBG(cerr << "v: " << v << endl); 00193 00194 // We're very liberal here with values. Anything that can fit into 8 bits 00195 // is allowed through. Clients will have to deal with the fact that the 00196 // ASCII representation for the value might need to be tweaked. This is 00197 // especially the case for Java clients where Byte datatypes are 00198 // signed. 3/20/2000 jhrg 00199 if ((v < 0 && v < DODS_SCHAR_MIN) 00200 || (v > 0 && static_cast < unsigned long >(v) > DODS_UCHAR_MAX)) 00201 return FALSE; 00202 00203 return TRUE; 00204 } 00205 00206 // This version of check_int will pass base 8, 10 and 16 numbers when they 00207 // use the ANSI standard for string representation of those number bases. 00208 00209 int check_int16(const char *val) 00210 { 00211 char *ptr; 00212 long v = strtol(val, &ptr, 0); // `0' --> use val to determine base 00213 00214 if ((v == 0 && val == ptr) || *ptr != '\0') { 00215 return FALSE; 00216 } 00217 // Don't use the constant from limits.h, use the ones in dods-limits.h 00218 if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) { 00219 return FALSE; 00220 } 00221 00222 return TRUE; 00223 } 00224 00225 int check_uint16(const char *val) 00226 { 00227 char *ptr; 00228 unsigned long v = strtol(val, &ptr, 0); 00229 00230 if ((v == 0 && val == ptr) || *ptr != '\0') { 00231 return FALSE; 00232 } 00233 00234 if (v > DODS_USHRT_MAX) { 00235 return FALSE; 00236 } 00237 00238 return TRUE; 00239 } 00240 00241 int check_int32(const char *val) 00242 { 00243 char *ptr; 00244 errno = 0; 00245 long v = strtol(val, &ptr, 0); // `0' --> use val to determine base 00246 00247 00248 if ((v == 0 && val == ptr) || *ptr != '\0') { 00249 return FALSE; 00250 } 00251 00252 // We need to check errno since strtol return clamps on overflow so the 00253 // check against the DODS values below will always pass, even for out of 00254 // bounds values in the string. mjohnson 7/20/09 00255 if (errno == ERANGE) { 00256 return FALSE; 00257 } 00258 // This could be combined with the above, or course, but I'm making it 00259 // separate to highlite the test. On 64-bit linux boxes 'long' may be 00260 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10 00261 else if (v > DODS_INT_MAX || v < DODS_INT_MIN) { 00262 return FALSE; 00263 } 00264 else { 00265 return TRUE; 00266 } 00267 } 00268 00269 int check_uint32(const char *val) 00270 { 00271 // Eat whitespace and check for an initial '-' sign... 00272 // strtoul allows an initial minus. mjohnson 00273 const char* c = val; 00274 while (c && isspace(*c)) { 00275 c++; 00276 } 00277 if (c && (*c == '-')) { 00278 return FALSE; 00279 } 00280 00281 char *ptr; 00282 errno = 0; 00283 unsigned long v = strtoul(val, &ptr, 0); 00284 00285 if ((v == 0 && val == ptr) || *ptr != '\0') { 00286 return FALSE; 00287 } 00288 00289 // check overflow first, or the below check is invalid due to 00290 // clamping to the maximum value by strtoul 00291 // maybe consider using long long for these checks? mjohnson 00292 if (errno == ERANGE) { 00293 return FALSE; 00294 } 00295 // See above. 00296 else if (v > DODS_UINT_MAX) { 00297 return FALSE; 00298 } 00299 else { 00300 return TRUE; 00301 } 00302 } 00303 00304 // Check first for system errors (like numbers so small they convert 00305 // (erroneously) to zero. Then make sure that the value is within 00306 // limits. 00307 00308 int check_float32(const char *val) 00309 { 00310 char *ptr; 00311 errno = 0; // Clear previous value. Fix for the 64bit 00312 // IRIX from Rob Morris. 5/21/2001 jhrg 00313 00314 #ifdef WIN32 00315 double v = w32strtod(val, &ptr); 00316 #else 00317 double v = strtod(val, &ptr); 00318 #endif 00319 00320 DBG(cerr << "v: " << v << ", ptr: " << ptr 00321 << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl); 00322 00323 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0') 00324 return FALSE; 00325 #if 0 00326 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE)) 00327 || *ptr != '\0') { 00328 return FALSE; 00329 } 00330 #endif 00331 00332 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl); 00333 double abs_val = fabs(v); 00334 if (abs_val > DODS_FLT_MAX 00335 || (abs_val != 0.0 && abs_val < DODS_FLT_MIN)) 00336 return FALSE; 00337 00338 return TRUE; 00339 } 00340 00341 int check_float64(const char *val) 00342 { 00343 DBG(cerr << "val: " << val << endl); 00344 char *ptr; 00345 errno = 0; // Clear previous value. 5/21/2001 jhrg 00346 00347 #ifdef WIN32 00348 double v = w32strtod(val, &ptr); 00349 #else 00350 double v = strtod(val, &ptr); 00351 #endif 00352 00353 DBG(cerr << "v: " << v << ", ptr: " << ptr 00354 << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl); 00355 00356 00357 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0') 00358 return FALSE; 00359 #if 0 00360 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE)) 00361 || *ptr != '\0') { 00362 return FALSE; 00363 } 00364 #endif 00365 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl); 00366 double abs_val = fabs(v); 00367 if (abs_val > DODS_DBL_MAX 00368 || (abs_val != 0.0 && abs_val < DODS_DBL_MIN)) 00369 return FALSE; 00370 00371 return TRUE; 00372 } 00373 00374 /* 00375 Maybe someday we will really check the Urls to see if they are valid... 00376 */ 00377 00378 int check_url(const char *) 00379 { 00380 return TRUE; 00381 } 00382 00383 } // namespace libdap