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 18315 2008-03-03 20:14:44Z jimg $"
00040     };
00041 
00042 #include <cerrno>
00043 #include <cassert>
00044 #include <cstring>
00045 #include <cmath>
00046 #include <iostream>
00047 #include <sstream>
00048 
00049 //  We wrap VC++ 6.x strtod() to account for a short comming
00050 //  in that function in regards to "NaN".
00051 #ifdef WIN32
00052 #include <limits>
00053 double w32strtod(const char *, char **);
00054 #endif
00055 
00056 #include "debug.h"
00057 #include "parser.h"             // defines constants such as ID_MAX
00058 #include "dods-limits.h"
00059 #include "util.h"               // Jose Garcia: for append_long_to_string.
00060 
00061 using std::cerr;
00062 using std::endl;
00063 
00064 #ifdef WIN32
00065 //  VC++ 6.x strtod() doesn't recognize "NaN".  Account for it
00066 //  by wrapping it around a check for the Nan string.  Use of
00067 //  the product is obsolete as of 1/2007, but it is unknown if
00068 //  the issue is still there in later releases of that product.
00069 //  ROM - 01/2007
00070 double w32strtod(const char *val, char **ptr)
00071 {
00072     //  Convert the two char arrays to compare to strings.
00073     string *sval = new string(val);
00074     string *snan = new string("NaN");
00075 
00076     //  If val doesn't contain "NaN|Nan|nan|etc", use strtod as
00077     //  provided.
00078     if (stricmp(sval->c_str(), snan->c_str()) != 0)
00079         return (strtod(val, ptr));
00080 
00081     //  But if it does, return the bit pattern for Nan and point
00082     //  the parsing ptr arg at the trailing '\0'.
00083     *ptr = (char *) val + strlen(val);
00084     return (std::numeric_limits < double >::quiet_NaN());
00085 }
00086 #endif
00087 
00088 namespace libdap {
00089 
00090 // Deprecated, but still used by the HDF4 EOS server code.
00091 void
00092 parse_error(parser_arg * arg, const char *msg, const int line_num,
00093             const char *context)
00094 {
00095     // Jose Garcia
00096     // This assert(s) is (are) only for developing purposes
00097     // For production servers remove it by compiling with NDEBUG
00098     assert(arg);
00099     assert(msg);
00100 
00101     arg->set_status(FALSE);
00102 
00103     string oss = "";
00104 
00105     if (line_num != 0) {
00106         oss += "Error parsing the text on line ";
00107         append_long_to_string(line_num, 10, oss);
00108     }
00109     else {
00110         oss += "Parse error.";
00111     }
00112 
00113     if (context)
00114         oss += (string) " at or near: " + context + (string) "\n" + msg
00115                + (string) "\n";
00116     else
00117         oss += (string) "\n" + msg + (string) "\n";
00118 
00119     arg->set_error(new Error(unknown_error, oss));
00120 }
00121 
00122 void
00123 parse_error(const char *msg, const int line_num, const char *context)
00124 {
00125     // Jose Garcia
00126     // This assert(s) is (are) only for developing purposes
00127     // For production servers remove it by compiling with NDEBUG
00128     assert(msg);
00129 
00130     string oss = "";
00131 
00132     if (line_num != 0) {
00133         oss += "Error parsing the text on line ";
00134         append_long_to_string(line_num, 10, oss);
00135     }
00136     else {
00137         oss += "Parse error.";
00138     }
00139 
00140     if (context)
00141         oss += (string) " at or near: " + context + (string) "\n" + msg
00142                + (string) "\n";
00143     else
00144         oss += (string) "\n" + msg + (string) "\n";
00145 
00146     throw Error(oss);
00147 }
00148 
00149 // context comes from the parser and will always be a char * unless the
00150 // parsers change dramatically.
00151 void
00152 parse_error(const string & msg, const int line_num, const char *context)
00153 {
00154     parse_error(msg.c_str(), line_num, context);
00155 }
00156 
00157 void save_str(char *dst, const char *src, const int line_num)
00158 {
00159     if (strlen(src) >= ID_MAX)
00160         parse_error(string("The word `") + string(src)
00161                     + string("' is too long (it should be no longer than ")
00162                     + long_to_string(ID_MAX) + string(")."), line_num);
00163 
00164     strncpy(dst, src, ID_MAX);
00165     dst[ID_MAX - 1] = '\0';     /* in case ... */
00166 }
00167 
00168 void save_str(string & dst, const char *src, const int)
00169 {
00170     dst = src;
00171 }
00172 
00173 bool is_keyword(string id, const string & keyword)
00174 {
00175     downcase(id);
00176     id = prune_spaces(id);
00177     DBG(cerr << "is_keyword: " << keyword << " = " << id << endl);
00178     return id == keyword;
00179 }
00180 
00181 int check_byte(const char *val)
00182 {
00183     char *ptr;
00184     long v = strtol(val, &ptr, 0);
00185 
00186     if ((v == 0 && val == ptr) || *ptr != '\0') {
00187         return FALSE;
00188     }
00189 
00190     DBG(cerr << "v: " << v << endl);
00191 
00192     // We're very liberal here with values. Anything that can fit into 8 bits
00193     // is allowed through. Clients will have to deal with the fact that the
00194     // ASCII representation for the value might need to be tweaked. This is
00195     // especially the case for Java clients where Byte datatypes are
00196     // signed. 3/20/2000 jhrg
00197     if ((v < 0 && v < DODS_SCHAR_MIN)
00198         || v > 0 && static_cast < unsigned long >(v) > DODS_UCHAR_MAX)
00199         return FALSE;
00200 
00201     return TRUE;
00202 }
00203 
00204 // This version of check_int will pass base 8, 10 and 16 numbers when they
00205 // use the ANSI standard for string representation of those number bases.
00206 
00207 int check_int16(const char *val)
00208 {
00209     char *ptr;
00210     long v = strtol(val, &ptr, 0);      // `0' --> use val to determine base
00211 
00212     if ((v == 0 && val == ptr) || *ptr != '\0') {
00213         return FALSE;
00214     }
00215     // Don't use the constant from limits.h, use the ones in dods-limits.h
00216     if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
00217         return FALSE;
00218     }
00219 
00220     return TRUE;
00221 }
00222 
00223 int check_uint16(const char *val)
00224 {
00225     char *ptr;
00226     unsigned long v = strtol(val, &ptr, 0);
00227 
00228     if ((v == 0 && val == ptr) || *ptr != '\0') {
00229         return FALSE;
00230     }
00231 
00232     if (v > DODS_USHRT_MAX) {
00233         return FALSE;
00234     }
00235 
00236     return TRUE;
00237 }
00238 
00239 int check_int32(const char *val)
00240 {
00241     char *ptr;
00242     long v = strtol(val, &ptr, 0);      // `0' --> use val to determine base
00243 
00244     if ((v == 0 && val == ptr) || *ptr != '\0') {
00245         return FALSE;
00246     }
00247 
00248     if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
00249         return FALSE;
00250     }
00251 
00252     return TRUE;
00253 }
00254 
00255 int check_uint32(const char *val)
00256 {
00257     char *ptr;
00258     unsigned long v = strtol(val, &ptr, 0);
00259 
00260     if ((v == 0 && val == ptr) || *ptr != '\0') {
00261         return FALSE;
00262     }
00263 
00264     return TRUE;
00265 }
00266 
00267 // Check first for system errors (like numbers so small they convert
00268 // (erroneously) to zero. Then make sure that the value is within
00269 // limits.
00270 
00271 int check_float32(const char *val)
00272 {
00273     char *ptr;
00274     errno = 0;                  // Clear previous value. Fix for the 64bit
00275     // IRIX from Rob Morris. 5/21/2001 jhrg
00276 
00277 #ifdef WIN32
00278     double v = w32strtod(val, &ptr);
00279 #else
00280     double v = strtod(val, &ptr);
00281 #endif
00282 
00283     DBG(cerr << "v: " << v << ", ptr: " << ptr
00284         << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
00285     if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
00286         || *ptr != '\0') {
00287         return FALSE;
00288     }
00289 
00290     DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
00291     double abs_val = fabs(v);
00292     if (abs_val > DODS_FLT_MAX
00293         || (abs_val != 0.0 && abs_val < DODS_FLT_MIN))
00294         return FALSE;
00295 
00296     return TRUE;
00297 }
00298 
00299 int check_float64(const char *val)
00300 {
00301     DBG(cerr << "val: " << val << endl);
00302     char *ptr;
00303     errno = 0;                  // Clear previous value. 5/21/2001 jhrg
00304 
00305 #ifdef WIN32
00306     double v = w32strtod(val, &ptr);
00307 #else
00308     double v = strtod(val, &ptr);
00309 #endif
00310 
00311     DBG(cerr << "v: " << v << ", ptr: " << ptr
00312         << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
00313 
00314     if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
00315         || *ptr != '\0') {
00316         return FALSE;
00317     }
00318 
00319     DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
00320     double abs_val = fabs(v);
00321     if (abs_val > DODS_DBL_MAX
00322         || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
00323         return FALSE;
00324 
00325     return TRUE;
00326 }
00327 
00328 /*
00329   Maybe someday we will really check the Urls to see if they are valid...
00330 */
00331 
00332 int check_url(const char *)
00333 {
00334     return TRUE;
00335 }
00336 
00337 } // namespace libdap

Generated on Wed Mar 5 15:27:11 2008 for libdap++ by  doxygen 1.5.4