libdap++  Updated for version 3.13.3
parser-util.cc
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2002,2003 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 // (c) COPYRIGHT URI/MIT 1995-1999
27 // Please read the full copyright statement in the file COPYRIGHT_URI.
28 //
29 // Authors:
30 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31 
32 // These functions are utility functions used by the various DAP parsers (the
33 // DAS, DDS and constraint expression parsers).
34 // jhrg 9/7/95
35 
36 #include "config.h"
37 
38 #include <cerrno>
39 #include <cassert>
40 #include <cstring>
41 #include <cmath>
42 #include <cstdlib>
43 
44 #include <iostream>
45 #include <sstream>
46 
47 // We wrap VC++ 6.x strtod() to account for a short comming
48 // in that function in regards to "NaN".
49 #ifdef WIN32
50 #include <limits>
51 double w32strtod(const char *, char **);
52 #endif
53 
54 #include "debug.h"
55 #include "parser.h" // defines constants such as ID_MAX
56 #include "dods-limits.h"
57 #include "util.h" // Jose Garcia: for append_long_to_string.
58 
59 using std::cerr;
60 using std::endl;
61 
62 #ifdef WIN32
63 // VC++ 6.x strtod() doesn't recognize "NaN". Account for it
64 // by wrapping it around a check for the Nan string. Use of
65 // the product is obsolete as of 1/2007, but it is unknown if
66 // the issue is still there in later releases of that product.
67 // ROM - 01/2007
68 double w32strtod(const char *val, char **ptr)
69 {
70  // Convert the two char arrays to compare to strings.
71  string *sval = new string(val);
72  string *snan = new string("NaN");
73 
74  // If val doesn't contain "NaN|Nan|nan|etc", use strtod as
75  // provided.
76  if (stricmp(sval->c_str(), snan->c_str()) != 0)
77  return (strtod(val, ptr));
78 
79  // But if it does, return the bit pattern for Nan and point
80  // the parsing ptr arg at the trailing '\0'.
81  *ptr = (char *) val + strlen(val);
82  return (std::numeric_limits < double >::quiet_NaN());
83 }
84 #endif
85 
86 namespace libdap {
87 
88 // Deprecated, but still used by the HDF4 EOS server code.
89 void
90 parse_error(parser_arg * arg, const char *msg, const int line_num,
91  const char *context)
92 {
93  // Jose Garcia
94  // This assert(s) is (are) only for developing purposes
95  // For production servers remove it by compiling with NDEBUG
96  assert(arg);
97  assert(msg);
98 
99  arg->set_status(FALSE);
100 
101  string oss = "";
102 
103  if (line_num != 0) {
104  oss += "Error parsing the text on line ";
105  append_long_to_string(line_num, 10, oss);
106  }
107  else {
108  oss += "Parse error.";
109  }
110 
111  if (context)
112  oss += (string) " at or near: " + context + (string) "\n" + msg
113  + (string) "\n";
114  else
115  oss += (string) "\n" + msg + (string) "\n";
116 
117  arg->set_error(new Error(unknown_error, oss));
118 }
119 
120 void
121 parse_error(const char *msg, const int line_num, const char *context)
122 {
123  // Jose Garcia
124  // This assert(s) is (are) only for developing purposes
125  // For production servers remove it by compiling with NDEBUG
126  assert(msg);
127 
128  string oss = "";
129 
130  if (line_num != 0) {
131  oss += "Error parsing the text on line ";
132  append_long_to_string(line_num, 10, oss);
133  }
134  else {
135  oss += "Parse error.";
136  }
137 
138  if (context)
139  oss += (string) " at or near: " + context + (string) "\n" + msg
140  + (string) "\n";
141  else
142  oss += (string) "\n" + msg + (string) "\n";
143 
144  throw Error(oss);
145 }
146 
147 // context comes from the parser and will always be a char * unless the
148 // parsers change dramatically.
149 void
150 parse_error(const string & msg, const int line_num, const char *context)
151 {
152  parse_error(msg.c_str(), line_num, context);
153 }
154 
155 void save_str(char *dst, const char *src, const int line_num)
156 {
157  if (strlen(src) >= ID_MAX)
158  parse_error(string("The word `") + string(src)
159  + string("' is too long (it should be no longer than ")
160  + long_to_string(ID_MAX) + string(")."), line_num);
161 
162  strncpy(dst, src, ID_MAX);
163  dst[ID_MAX - 1] = '\0'; /* in case ... */
164 }
165 
166 void save_str(string & dst, const char *src, const int)
167 {
168  dst = src;
169 }
170 
171 bool is_keyword(string id, const string & keyword)
172 {
173  downcase(id);
174  id = prune_spaces(id);
175  DBG(cerr << "is_keyword: " << keyword << " = " << id << endl);
176  return id == keyword;
177 }
178 
179 int check_byte(const char *val)
180 {
181  char *ptr;
182  long v = strtol(val, &ptr, 0);
183 
184  if ((v == 0 && val == ptr) || *ptr != '\0') {
185  return FALSE;
186  }
187 
188  DBG(cerr << "v: " << v << endl);
189 
190  // We're very liberal here with values. Anything that can fit into 8 bits
191  // is allowed through. Clients will have to deal with the fact that the
192  // ASCII representation for the value might need to be tweaked. This is
193  // especially the case for Java clients where Byte datatypes are
194  // signed. 3/20/2000 jhrg
195  if ((v < 0 && v < DODS_SCHAR_MIN)
196  || (v > 0 && static_cast < unsigned long >(v) > DODS_UCHAR_MAX))
197  return FALSE;
198 
199  return TRUE;
200 }
201 
202 // This version of check_int will pass base 8, 10 and 16 numbers when they
203 // use the ANSI standard for string representation of those number bases.
204 
205 int check_int16(const char *val)
206 {
207  char *ptr;
208  long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
209 
210  if ((v == 0 && val == ptr) || *ptr != '\0') {
211  return FALSE;
212  }
213  // Don't use the constant from limits.h, use the ones in dods-limits.h
214  if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
215  return FALSE;
216  }
217 
218  return TRUE;
219 }
220 
221 int check_uint16(const char *val)
222 {
223  char *ptr;
224  unsigned long v = strtol(val, &ptr, 0);
225 
226  if ((v == 0 && val == ptr) || *ptr != '\0') {
227  return FALSE;
228  }
229 
230  if (v > DODS_USHRT_MAX) {
231  return FALSE;
232  }
233 
234  return TRUE;
235 }
236 
237 int check_int32(const char *val)
238 {
239  char *ptr;
240  errno = 0;
241  long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
242 
243 
244  if ((v == 0 && val == ptr) || *ptr != '\0') {
245  return FALSE;
246  }
247 
248  // We need to check errno since strtol return clamps on overflow so the
249  // check against the DODS values below will always pass, even for out of
250  // bounds values in the string. mjohnson 7/20/09
251  if (errno == ERANGE) {
252  return FALSE;
253  }
254  // This could be combined with the above, or course, but I'm making it
255  // separate to highlite the test. On 64-bit linux boxes 'long' may be
256  // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
257  else if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
258  return FALSE;
259  }
260  else {
261  return TRUE;
262  }
263 }
264 
265 int check_uint32(const char *val)
266 {
267  // Eat whitespace and check for an initial '-' sign...
268  // strtoul allows an initial minus. mjohnson
269  const char* c = val;
270  while (c && isspace(*c)) {
271  c++;
272  }
273  if (c && (*c == '-')) {
274  return FALSE;
275  }
276 
277  char *ptr;
278  errno = 0;
279  unsigned long v = strtoul(val, &ptr, 0);
280 
281  if ((v == 0 && val == ptr) || *ptr != '\0') {
282  return FALSE;
283  }
284 
285  // check overflow first, or the below check is invalid due to
286  // clamping to the maximum value by strtoul
287  // maybe consider using long long for these checks? mjohnson
288  if (errno == ERANGE) {
289  return FALSE;
290  }
291  // See above.
292  else if (v > DODS_UINT_MAX) {
293  return FALSE;
294  }
295  else {
296  return TRUE;
297  }
298 }
299 
300 // Check first for system errors (like numbers so small they convert
301 // (erroneously) to zero. Then make sure that the value is within
302 // limits.
303 
304 int check_float32(const char *val)
305 {
306  char *ptr;
307  errno = 0; // Clear previous value. Fix for the 64bit
308  // IRIX from Rob Morris. 5/21/2001 jhrg
309 
310 #ifdef WIN32
311  double v = w32strtod(val, &ptr);
312 #else
313  double v = strtod(val, &ptr);
314 #endif
315 
316  DBG(cerr << "v: " << v << ", ptr: " << ptr
317  << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
318 
319  if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
320  return FALSE;
321 #if 0
322  if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
323  || *ptr != '\0') {
324  return FALSE;
325  }
326 #endif
327 
328  DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
329  double abs_val = fabs(v);
330  if (abs_val > DODS_FLT_MAX
331  || (abs_val != 0.0 && abs_val < DODS_FLT_MIN))
332  return FALSE;
333 
334  return TRUE;
335 }
336 
337 int check_float64(const char *val)
338 {
339  DBG(cerr << "val: " << val << endl);
340  char *ptr;
341  errno = 0; // Clear previous value. 5/21/2001 jhrg
342 
343 #ifdef WIN32
344  double v = w32strtod(val, &ptr);
345 #else
346  double v = strtod(val, &ptr);
347 #endif
348 
349  DBG(cerr << "v: " << v << ", ptr: " << ptr
350  << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
351 
352 
353  if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
354  return FALSE;
355 #if 0
356  if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
357  || *ptr != '\0') {
358  return FALSE;
359  }
360 #endif
361  DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
362  double abs_val = fabs(v);
363  if (abs_val > DODS_DBL_MAX
364  || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
365  return FALSE;
366 
367  return TRUE;
368 }
369 
370 /*
371  Maybe someday we will really check the Urls to see if they are valid...
372 */
373 
374 int check_url(const char *)
375 {
376  return TRUE;
377 }
378 
379 } // namespace libdap
int check_float64(const char *val)
Definition: parser-util.cc:337
int check_int32(const char *val)
Definition: parser-util.cc:237
#define DODS_DBL_MIN
Definition: dods-limits.h:88
void downcase(string &s)
Definition: util.cc:428
int check_int16(const char *val)
Is the value a valid integer?
Definition: parser-util.cc:205
string prune_spaces(const string &name)
Definition: util.cc:315
#define TRUE
Definition: parser.h:50
#define DODS_DBL_MAX
Definition: dods-limits.h:86
#define DODS_FLT_MIN
Definition: dods-limits.h:92
#define unknown_error
Unknown error.
Definition: Error.h:60
#define DBG(x)
Definition: debug.h:58
void set_status(int val=0)
Definition: parser.h:105
#define DODS_INT_MIN
Definition: dods-limits.h:72
int check_byte(const char *val)
Is the value a valid byte?
Definition: parser-util.cc:179
#define DODS_SHRT_MAX
Definition: dods-limits.h:69
void append_long_to_string(long val, int base, string &str_val)
Definition: util.cc:744
#define FALSE
Definition: parser.h:51
void set_error(Error *obj)
Definition: parser.h:97
string long_to_string(long val, int base)
Definition: util.cc:773
int check_url(const char *)
Is the value a valid URL?
Definition: parser-util.cc:374
void parse_error(parser_arg *arg, const char *msg, const int line_num, const char *context)
Definition: parser-util.cc:90
#define DODS_SHRT_MIN
Definition: dods-limits.h:68
#define DODS_USHRT_MAX
Definition: dods-limits.h:70
Pass parameters by reference to a parser.
Definition: parser.h:68
#define DODS_UCHAR_MAX
Definition: dods-limits.h:65
bool is_keyword(string id, const string &keyword)
Definition: parser-util.cc:171
#define ID_MAX
Definition: parser.h:47
int check_uint32(const char *val)
Definition: parser-util.cc:265
#define DODS_SCHAR_MIN
Definition: dods-limits.h:63
A class for error processing.
Definition: Error.h:90
int check_uint16(const char *val)
Definition: parser-util.cc:221
#define DODS_FLT_MAX
Definition: dods-limits.h:91
void save_str(char *dst, const char *src, const int line_num)
Save a string to a temporary variable during the parse.
Definition: parser-util.cc:155
#define DODS_UINT_MAX
Definition: dods-limits.h:74
#define DODS_INT_MAX
Definition: dods-limits.h:73
int check_float32(const char *val)
Is the value a valid float?
Definition: parser-util.cc:304