libdap  Updated for version 3.17.2
parser-util.cc
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 "Error.h"
55 #include "debug.h"
56 #include "parser.h" // defines constants such as ID_MAX
57 #include "dods-limits.h"
58 #include "util.h" // Jose Garcia: for append_long_to_string.
59 
60 using std::cerr;
61 using std::endl;
62 
63 #ifdef WIN32
64 // VC++ 6.x strtod() doesn't recognize "NaN". Account for it
65 // by wrapping it around a check for the Nan string. Use of
66 // the product is obsolete as of 1/2007, but it is unknown if
67 // the issue is still there in later releases of that product.
68 // ROM - 01/2007
69 double w32strtod(const char *val, char **ptr)
70 {
71  // Convert the two char arrays to compare to strings.
72  string *sval = new string(val);
73  string *snan = new string("NaN");
74 
75  // If val doesn't contain "NaN|Nan|nan|etc", use strtod as
76  // provided.
77  if (stricmp(sval->c_str(), snan->c_str()) != 0)
78  return (strtod(val, ptr));
79 
80  // But if it does, return the bit pattern for Nan and point
81  // the parsing ptr arg at the trailing '\0'.
82  *ptr = (char *) val + strlen(val);
83  return (std::numeric_limits < double >::quiet_NaN());
84 }
85 #endif
86 
87 namespace libdap {
88 
89 // Deprecated, but still used by the HDF4 EOS server code.
90 void
91 parse_error(parser_arg * arg, const char *msg, const int line_num,
92  const char *context)
93 {
94  // Jose Garcia
95  // This assert(s) is (are) only for developing purposes
96  // For production servers remove it by compiling with NDEBUG
97  assert(arg);
98  assert(msg);
99 
100  arg->set_status(FALSE);
101 
102  string oss = "";
103 
104  if (line_num != 0) {
105  oss += "Error parsing the text on line ";
106  append_long_to_string(line_num, 10, oss);
107  }
108  else {
109  oss += "Parse error.";
110  }
111 
112  if (context)
113  oss += (string) " at or near: " + context + (string) "\n" + msg
114  + (string) "\n";
115  else
116  oss += (string) "\n" + msg + (string) "\n";
117 
118  arg->set_error(new Error(unknown_error, oss));
119 }
120 
121 void
122 parse_error(const char *msg, const int line_num, const char *context)
123 {
124  // Jose Garcia
125  // This assert(s) is (are) only for developing purposes
126  // For production servers remove it by compiling with NDEBUG
127  assert(msg);
128 
129  string oss = "";
130 
131  if (line_num != 0) {
132  oss += "Error parsing the text on line ";
133  append_long_to_string(line_num, 10, oss);
134  }
135  else {
136  oss += "Parse error.";
137  }
138 
139  if (context)
140  oss += (string) " at or near: " + context + (string) "\n" + msg
141  + (string) "\n";
142  else
143  oss += (string) "\n" + msg + (string) "\n";
144 
145  throw Error(malformed_expr, oss);
146 }
147 
148 // context comes from the parser and will always be a char * unless the
149 // parsers change dramatically.
150 void
151 parse_error(const string & msg, const int line_num, const char *context)
152 {
153  parse_error(msg.c_str(), line_num, context);
154 }
155 
156 void save_str(char *dst, const char *src, const int line_num)
157 {
158  if (strlen(src) >= ID_MAX)
159  parse_error(string("The word `") + string(src)
160  + string("' is too long (it should be no longer than ")
161  + long_to_string(ID_MAX) + string(")."), line_num);
162 
163  strncpy(dst, src, ID_MAX);
164  dst[ID_MAX - 1] = '\0'; /* in case ... */
165 }
166 
167 void save_str(string & dst, const char *src, const int)
168 {
169  dst = src;
170 }
171 
172 bool is_keyword(string id, const string & keyword)
173 {
174  downcase(id);
175  id = prune_spaces(id);
176  DBG(cerr << "is_keyword: " << keyword << " = " << id << endl);
177  return id == keyword;
178 }
179 
180 int check_byte(const char *val)
181 {
182  char *ptr;
183  long v = strtol(val, &ptr, 0);
184 
185  if ((v == 0 && val == ptr) || *ptr != '\0') {
186  return FALSE;
187  }
188 
189  DBG(cerr << "v: " << v << endl);
190 
191  // We're very liberal here with values. Anything that can fit into 8 bits
192  // is allowed through. Clients will have to deal with the fact that the
193  // ASCII representation for the value might need to be tweaked. This is
194  // especially the case for Java clients where Byte datatypes are
195  // signed. 3/20/2000 jhrg
196  if ((v < 0 && v < DODS_SCHAR_MIN)
197  || (v > 0 && static_cast < unsigned long >(v) > DODS_UCHAR_MAX))
198  return FALSE;
199 
200  return TRUE;
201 }
202 
203 // This version of check_int will pass base 8, 10 and 16 numbers when they
204 // use the ANSI standard for string representation of those number bases.
205 
206 int check_int16(const char *val)
207 {
208  char *ptr;
209  long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
210 
211  if ((v == 0 && val == ptr) || *ptr != '\0') {
212  return FALSE;
213  }
214  // Don't use the constant from limits.h, use the ones in dods-limits.h
215  if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
216  return FALSE;
217  }
218 
219  return TRUE;
220 }
221 
222 int check_uint16(const char *val)
223 {
224  char *ptr;
225  unsigned long v = strtol(val, &ptr, 0);
226 
227  if ((v == 0 && val == ptr) || *ptr != '\0') {
228  return FALSE;
229  }
230 
231  if (v > DODS_USHRT_MAX) {
232  return FALSE;
233  }
234 
235  return TRUE;
236 }
237 
238 int check_int32(const char *val)
239 {
240  char *ptr;
241  errno = 0;
242  long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
243 
244 
245  if ((v == 0 && val == ptr) || *ptr != '\0') {
246  return FALSE;
247  }
248 
249  // We need to check errno since strtol return clamps on overflow so the
250  // check against the DODS values below will always pass, even for out of
251  // bounds values in the string. mjohnson 7/20/09
252  if (errno == ERANGE) {
253  return FALSE;
254  }
255  // This could be combined with the above, or course, but I'm making it
256  // separate to highlight the test. On 64-bit linux boxes 'long' may be
257  // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
258  else if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
259  return FALSE;
260  }
261  else {
262  return TRUE;
263  }
264 }
265 
266 int check_uint32(const char *val)
267 {
268  // Eat whitespace and check for an initial '-' sign...
269  // strtoul allows an initial minus. mjohnson
270  const char* c = val;
271  while (c && isspace(*c)) {
272  c++;
273  }
274  if (c && (*c == '-')) {
275  return FALSE;
276  }
277 
278  char *ptr;
279  errno = 0;
280  unsigned long v = strtoul(val, &ptr, 0);
281 
282  if ((v == 0 && val == ptr) || *ptr != '\0') {
283  return FALSE;
284  }
285 
286  // check overflow first, or the below check is invalid due to
287  // clamping to the maximum value by strtoul
288  // maybe consider using long long for these checks? mjohnson
289  if (errno == ERANGE) {
290  return FALSE;
291  }
292  // See above.
293  else if (v > DODS_UINT_MAX) {
294  return FALSE;
295  }
296  else {
297  return TRUE;
298  }
299 }
300 
301 unsigned long long get_ull(const char *val)
302 {
303  // Eat whitespace and check for an initial '-' sign...
304  // strtoul allows an initial minus. mjohnson
305  const char* c = val;
306  while (c && isspace(*c)) {
307  c++;
308  }
309  if (c && (*c == '-')) {
310  throw Error("The value '" + string(val) + "' is not a valid array index.");
311  // return FALSE;
312  }
313 
314  char *ptr;
315  errno = 0;
316  unsigned long long v = strtoull(val, &ptr, 0);
317 
318  if ((v == 0 && val == ptr) || *ptr != '\0') {
319  throw Error("The value '" + string(val) + "' contains extra characters.");
320  //return FALSE;
321  }
322 
323  if (errno == ERANGE) {
324  throw Error("The value '" + string(val) + "' is out of range.");
325  // return FALSE;
326  }
327  else if (v > DODS_MAX_ARRAY_INDEX) { // 2^61
328  throw Error("The value '" + string(val) + "' is out of range.");
329  // return FALSE;
330  }
331  else {
332  return v;
333  }
334 }
335 
336 
337 // Check first for system errors (like numbers so small they convert
338 // (erroneously) to zero. Then make sure that the value is within
339 // limits.
340 
341 int check_float32(const char *val)
342 {
343  char *ptr;
344  errno = 0; // Clear previous value. Fix for the 64bit
345  // IRIX from Rob Morris. 5/21/2001 jhrg
346 
347 #ifdef WIN32
348  double v = w32strtod(val, &ptr);
349 #else
350  double v = strtod(val, &ptr);
351 #endif
352 
353  DBG(cerr << "v: " << v << ", ptr: " << ptr
354  << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
355 
356  if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
357  return FALSE;
358 #if 0
359  if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
360  || *ptr != '\0') {
361  return FALSE;
362  }
363 #endif
364 
365  DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
366  double abs_val = fabs(v);
367  if (abs_val > DODS_FLT_MAX
368  || (abs_val != 0.0 && abs_val < DODS_FLT_MIN))
369  return FALSE;
370 
371  return TRUE;
372 }
373 
374 int check_float64(const char *val)
375 {
376  DBG(cerr << "val: " << val << endl);
377  char *ptr;
378  errno = 0; // Clear previous value. 5/21/2001 jhrg
379 
380 #ifdef WIN32
381  double v = w32strtod(val, &ptr);
382 #else
383  double v = strtod(val, &ptr);
384 #endif
385 
386  DBG(cerr << "v: " << v << ", ptr: " << ptr
387  << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
388 
389 
390  if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
391  return FALSE;
392 #if 0
393  if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
394  || *ptr != '\0') {
395  return FALSE;
396  }
397 #endif
398  DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
399  double abs_val = fabs(v);
400  if (abs_val > DODS_DBL_MAX
401  || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
402  return FALSE;
403 
404  return TRUE;
405 }
406 
407 /*
408  Maybe someday we will really check the Urls to see if they are valid...
409 */
410 
411 int check_url(const char *)
412 {
413  return TRUE;
414 }
415 
416 } // namespace libdap
void downcase(string &s)
Definition: util.cc:559
int check_int16(const char *val)
Is the value a valid integer?
Definition: parser-util.cc:206
string prune_spaces(const string &name)
Definition: util.cc:455
int check_byte(const char *val)
Is the value a valid byte?
Definition: parser-util.cc:180
int check_url(const char *)
Is the value a valid URL?
Definition: parser-util.cc:411
A class for error processing.
Definition: Error.h:90
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:156
int check_float32(const char *val)
Is the value a valid float?
Definition: parser-util.cc:341