libdap Updated for version 3.20.5
libdap4 is an implementation of OPeNDAP's DAP protocol.
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>
51double 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
60using std::cerr;
61using 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
69double 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
87namespace libdap {
88
89// Deprecated, but still used by the HDF4 EOS server code.
90void
91parse_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
121void
122parse_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.
150void
151parse_error(const string & msg, const int line_num, const char *context)
152{
153 parse_error(msg.c_str(), line_num, context);
154}
155
156void 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
167void save_str(string & dst, const char *src, const int)
168{
169 dst = src;
170}
171
172bool 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
190int check_byte(const char *val)
191{
192 char *ptr;
193 long v = strtol(val, &ptr, 0);
194
195 if ((v == 0 && val == ptr) || *ptr != '\0') {
196 return FALSE;
197 }
198
199 DBG(cerr << "v: " << v << endl);
200
201 // We're very liberal here with values. Anything that can fit into 8 bits
202 // is allowed through. Clients will have to deal with the fact that the
203 // ASCII representation for the value might need to be tweaked. This is
204 // especially the case for Java clients where Byte datatypes are
205 // signed. 3/20/2000 jhrg
206 if ((v < 0 && v < DODS_SCHAR_MIN)
207 || (v > 0 && static_cast < unsigned long >(v) > DODS_UCHAR_MAX))
208 return FALSE;
209
210 return TRUE;
211}
212
213// This version of check_int will pass base 8, 10 and 16 numbers when they
214// use the ANSI standard for string representation of those number bases.
215
216int check_int16(const char *val)
217{
218 char *ptr;
219 long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
220
221 if ((v == 0 && val == ptr) || *ptr != '\0') {
222 return FALSE;
223 }
224 // Don't use the constant from limits.h, use the ones in dods-limits.h
225 if (v > DODS_SHRT_MAX || v < DODS_SHRT_MIN) {
226 return FALSE;
227 }
228
229 return TRUE;
230}
231
232int check_uint16(const char *val)
233{
234 char *ptr;
235 unsigned long v = strtol(val, &ptr, 0);
236
237 if ((v == 0 && val == ptr) || *ptr != '\0') {
238 return FALSE;
239 }
240
241 if (v > DODS_USHRT_MAX) {
242 return FALSE;
243 }
244
245 return TRUE;
246}
247
248int check_int32(const char *val)
249{
250 char *ptr;
251 errno = 0;
252 long v = strtol(val, &ptr, 0); // `0' --> use val to determine base
253
254 if ((v == 0 && val == ptr) || *ptr != '\0') {
255 return FALSE;
256 }
257
258 // We need to check errno since strtol return clamps on overflow so the
259 // check against the DODS values below will always pass, even for out of
260 // bounds values in the string. mjohnson 7/20/09
261 if (errno == ERANGE) {
262 return FALSE;
263 }
264 // This could be combined with the above, or course, but I'm making it
265 // separate to highlight the test. On 64-bit linux boxes 'long' may be
266 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
267 else if (v > DODS_INT_MAX || v < DODS_INT_MIN) {
268 return FALSE;
269 }
270 else {
271 return TRUE;
272 }
273}
274
275int check_uint32(const char *val)
276{
277 // Eat whitespace and check for an initial '-' sign...
278 // strtoul allows an initial minus. mjohnson
279 const char* c = val;
280 while (c && isspace(*c)) {
281 c++;
282 }
283 if (c && (*c == '-')) {
284 return FALSE;
285 }
286
287 char *ptr;
288 errno = 0;
289 unsigned long v = strtoul(val, &ptr, 0);
290
291 if ((v == 0 && val == ptr) || *ptr != '\0') {
292 return FALSE;
293 }
294
295 // check overflow first, or the below check is invalid due to
296 // clamping to the maximum value by strtoul
297 // maybe consider using long long for these checks? mjohnson
298 if (errno == ERANGE) {
299 return FALSE;
300 }
301 // See above.
302 else if (v > DODS_UINT_MAX) {
303 return FALSE;
304 }
305 else {
306 return TRUE;
307 }
308}
309
310int check_int64(const char *val)
311{
312 char *ptr;
313 errno = 0;
314 long long v = strtoll(val, &ptr, 0); // `0' --> use val to determine base
315
316 if ((v == 0 && val == ptr) || *ptr != '\0') {
317 return FALSE;
318 }
319
320 // We need to check errno since strtol return clamps on overflow so the
321 // check against the DODS values below will always pass, even for out of
322 // bounds values in the string. mjohnson 7/20/09
323 if (errno == ERANGE) {
324 return FALSE;
325 }
326#if 0
327 // This could be combined with the above, or course, but I'm making it
328 // separate to highlight the test. On 64-bit linux boxes 'long' may be
329 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
330 //
331 // Removed - Coverity says it can never be false. Makes sense. jhrg 5/10/16
332 else if (v <= DODS_LLONG_MAX && v >= DODS_LLONG_MIN) {
333 return FALSE;
334 }
335#endif
336 else {
337 return TRUE;
338 }
339}
340
341int check_uint64(const char *val)
342{
343 // Eat whitespace and check for an initial '-' sign...
344 // strtoul allows an initial minus. mjohnson
345 const char* c = val;
346 while (c && isspace(*c)) {
347 c++;
348 }
349 if (c && (*c == '-')) {
350 return FALSE;
351 }
352
353 char *ptr;
354 errno = 0;
355 unsigned long long v = strtoull(val, &ptr, 0);
356
357 if ((v == 0 && val == ptr) || *ptr != '\0') {
358 return FALSE;
359 }
360
361 if (errno == ERANGE) {
362 return FALSE;
363 }
364 else if (v > DODS_ULLONG_MAX) { // 2^61
365 return FALSE;
366 }
367 else {
368 return v;
369 }
370}
371
372// Check first for system errors (like numbers so small they convert
373// (erroneously) to zero. Then make sure that the value is within
374// limits.
375
376int check_float32(const char *val)
377{
378 char *ptr;
379 errno = 0; // Clear previous value. Fix for the 64bit
380 // IRIX from Rob Morris. 5/21/2001 jhrg
381
382#ifdef WIN32
383 double v = w32strtod(val, &ptr);
384#else
385 double v = strtod(val, &ptr);
386#endif
387
388 DBG(cerr << "v: " << v << ", ptr: " << ptr
389 << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
390
391 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
392 return FALSE;
393
394#if 0
395 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
396 || *ptr != '\0') {
397 return FALSE;
398 }
399#endif
400
401 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
402 double abs_val = fabs(v);
403 if (abs_val > DODS_FLT_MAX
404 || (abs_val != 0.0 && abs_val < DODS_FLT_MIN))
405 return FALSE;
406
407 return TRUE;
408}
409
410int check_float64(const char *val)
411{
412 DBG(cerr << "val: " << val << endl);
413 char *ptr;
414 errno = 0; // Clear previous value. 5/21/2001 jhrg
415
416#ifdef WIN32
417 double v = w32strtod(val, &ptr);
418#else
419 double v = strtod(val, &ptr);
420#endif
421
422 DBG(cerr << "v: " << v << ", ptr: " << ptr
423 << ", errno: " << errno << ", val==ptr: " << (val == ptr) << endl);
424
425
426 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
427 return FALSE;
428#if 0
429 if ((v == 0.0 && (val == ptr || errno == HUGE_VAL || errno == ERANGE))
430 || *ptr != '\0') {
431 return FALSE;
432 }
433#endif
434 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
435 double abs_val = fabs(v);
436 if (abs_val > DODS_DBL_MAX
437 || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
438 return FALSE;
439
440 return TRUE;
441}
442
443long long get_int64(const char *val)
444{
445 char *ptr;
446 errno = 0;
447 long long v = strtoll(val, &ptr, 0); // `0' --> use val to determine base
448
449 if ((v == 0 && val == ptr) || *ptr != '\0') {
450 throw Error("The value '" + string(val) + "' contains extra characters.");
451 }
452
453 // We need to check errno since strtol return clamps on overflow so the
454 // check against the DODS values below will always pass, even for out of
455 // bounds values in the string. mjohnson 7/20/09
456 if (errno == ERANGE) {
457 throw Error("The value '" + string(val) + "' is out of range.");
458 }
459
460#if 0
461 // This could be combined with the above, or course, but I'm making it
462 // separate to highlight the test. On 64-bit linux boxes 'long' may be
463 // 64-bits and so 'v' can hold more than a DODS_INT32. jhrg 3/23/10
464 //
465 // Removed because coverity flags it as useless, which it is until we
466 // have 128-bit ints... jhrg 5/9/16
467 else if (v > DODS_LLONG_MAX || v < DODS_LLONG_MIN) {
468 throw Error("The value '" + string(val) + "' is out of range.");
469 }
470#endif
471
472 else {
473 return v;
474 }
475}
476
477unsigned long long get_uint64(const char *val)
478{
479 // Eat whitespace and check for an initial '-' sign...
480 // strtoul allows an initial minus. mjohnson
481 const char* c = val;
482 while (c && isspace(*c)) {
483 c++;
484 }
485 if (c && (*c == '-')) {
486 throw Error("The value '" + string(val) + "' is not a valid array index.");
487 }
488
489 char *ptr;
490 errno = 0;
491 unsigned long long v = strtoull(val, &ptr, 0);
492
493 if ((v == 0 && val == ptr) || *ptr != '\0') {
494 throw Error("The value '" + string(val) + "' contains extra characters.");
495 }
496
497 if (errno == ERANGE) {
498 throw Error("The value '" + string(val) + "' is out of range.");
499 }
500#if 0
501 // Coverity; see above. jhrg 5/9/16
502 else if (v > DODS_MAX_ARRAY_INDEX) { // 2^61
503 throw Error("The value '" + string(val) + "' is out of range.");
504 }
505#endif
506 else {
507 return v;
508 }
509}
510
511double get_float64(const char *val)
512{
513 DBG(cerr << "val: " << val << endl);
514 char *ptr;
515 errno = 0; // Clear previous value. 5/21/2001 jhrg
516
517#ifdef WIN32
518 double v = w32strtod(val, &ptr);
519#else
520 double v = strtod(val, &ptr);
521#endif
522
523 if (errno == ERANGE || (v == 0.0 && val == ptr) || *ptr != '\0')
524 throw Error("The value '" + string(val) + "' is out of range.");;
525
526 DBG(cerr << "fabs(" << val << ") = " << fabs(v) << endl);
527 double abs_val = fabs(v);
528 if (abs_val > DODS_DBL_MAX || (abs_val != 0.0 && abs_val < DODS_DBL_MIN))
529 throw Error("The value '" + string(val) + "' is out of range.");;
530
531 return v;
532}
533
534/*
535 Maybe someday we will really check the Urls to see if they are valid...
536*/
537
538int check_url(const char *)
539{
540 return TRUE;
541}
542
543} // namespace libdap
int check_url(const char *)
Is the value a valid URL?
Definition: parser-util.cc:538
int check_byte(const char *val)
Is the value a valid byte?
Definition: parser-util.cc:190
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
string prune_spaces(const string &name)
Definition: util.cc:459
void downcase(string &s)
Definition: util.cc:563
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