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