libdap++ Updated for version 3.8.2

parser-util.cc

Go to the documentation of this file.
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