libdap Updated for version 3.21.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
util.cc
Go to the documentation of this file.
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of libdap, A C++ implementation of the OPeNDAP Data
4// Access Protocol.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// (c) COPYRIGHT URI/MIT 1994-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28// Authors:
29// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30
31// Utility functions used by the api.
32//
33// jhrg 9/21/94
34
35#include "config.h"
36
37#include <fstream>
38
39#include <cassert>
40#include <climits>
41#include <cstdlib>
42#include <cstring>
43
44#include <ctype.h>
45#ifndef TM_IN_SYS_TIME
46#include <time.h>
47#else
48#include <sys/time.h>
49#endif
50
51#ifndef WIN32
52#include <unistd.h> // for stat
53#else
54#include <fcntl.h>
55#include <io.h>
56#include <process.h>
57#endif
58
59#include <sys/stat.h>
60#include <sys/types.h>
61
62#include <algorithm>
63#include <sstream>
64#include <stdexcept>
65#include <string>
66#include <vector>
67
68#include "Array.h"
69#include "BaseType.h"
70#include "Byte.h"
71#include "Float32.h"
72#include "Float64.h"
73#include "Int16.h"
74#include "Int32.h"
75#include "Str.h"
76#include "UInt16.h"
77#include "UInt32.h"
78
79#include "Int64.h"
80#include "Int8.h"
81#include "UInt64.h"
82
83#include "Error.h"
84
85#include "GNURegex.h"
86#include "debug.h"
87#include "util.h"
88
89using namespace std;
90
91namespace libdap {
92
95#ifdef COMPUTE_ENDIAN_AT_RUNTIME
96
97 dods_int16 i = 0x0100;
98 char *c = reinterpret_cast<char *>(&i);
99 return *c;
100
101#else
102
103#if WORDS_BIGENDIAN
104 return true;
105#else
106 return false;
107#endif
108
109#endif
110}
111
119 assert(arg);
120
121 if (arg->type() != dods_str_c)
122 throw Error(malformed_expr, "The function requires a string argument.");
123
124 if (!arg->read_p())
125 throw InternalErr(__FILE__, __LINE__,
126 "The CE Evaluator built an argument list where some constants held no values.");
127
128 return static_cast<Str *>(arg)->value();
129}
130
131template <class T> static void set_array_using_double_helper(Array *a, double *src, int src_len) {
132 assert(a);
133 assert(src);
134 assert(src_len > 0);
135
136 vector<T> values(src_len);
137 for (int i = 0; i < src_len; ++i)
138 values[i] = (T)src[i];
139
140 // This copies the values
141 a->set_value(values, src_len);
142}
143
164void set_array_using_double(Array *dest, double *src, int src_len) {
165 assert(dest);
166 assert(src);
167 assert(src_len > 0);
168
169 // Simple types are Byte, ..., Float64, String and Url.
170 if ((dest->type() == dods_array_c && !dest->var()->is_simple_type()) || dest->var()->type() == dods_str_c ||
171 dest->var()->type() == dods_url_c)
172 throw InternalErr(__FILE__, __LINE__, "The function requires a numeric-type array argument.");
173
174 // Test sizes. Note that Array::length() takes any constraint into account
175 // when it returns the length. Even if this was removed, the 'helper'
176 // function this uses calls Vector::val2buf() which uses Vector::width()
177 // which in turn uses length().
178 if (dest->length() != src_len)
179 throw InternalErr(__FILE__, __LINE__,
180 "The source and destination array sizes don't match (" + long_to_string(src_len) +
181 " versus " + long_to_string(dest->length()) + ").");
182
183 // The types of arguments that the CE Parser will build for numeric
184 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
185 // Expanded to work for any numeric type so it can be used for more than
186 // just arguments.
187 switch (dest->var()->type()) {
188 case dods_byte_c:
189 set_array_using_double_helper<dods_byte>(dest, src, src_len);
190 break;
191 case dods_uint16_c:
192 set_array_using_double_helper<dods_uint16>(dest, src, src_len);
193 break;
194 case dods_int16_c:
195 set_array_using_double_helper<dods_int16>(dest, src, src_len);
196 break;
197 case dods_uint32_c:
198 set_array_using_double_helper<dods_uint32>(dest, src, src_len);
199 break;
200 case dods_int32_c:
201 set_array_using_double_helper<dods_int32>(dest, src, src_len);
202 break;
203 case dods_float32_c:
204 set_array_using_double_helper<dods_float32>(dest, src, src_len);
205 break;
206 case dods_float64_c:
207 set_array_using_double_helper<dods_float64>(dest, src, src_len);
208 break;
209
210 // DAP4 support
211 case dods_uint8_c:
212 set_array_using_double_helper<dods_byte>(dest, src, src_len);
213 break;
214 case dods_int8_c:
215 set_array_using_double_helper<dods_int8>(dest, src, src_len);
216 break;
217 case dods_uint64_c:
218 set_array_using_double_helper<dods_uint64>(dest, src, src_len);
219 break;
220 case dods_int64_c:
221 set_array_using_double_helper<dods_int64>(dest, src, src_len);
222 break;
223 default:
224 throw InternalErr(__FILE__, __LINE__,
225 "The argument list built by the CE parser contained an unsupported numeric type.");
226 }
227
228 // Set the read_p property.
229 dest->set_read_p(true);
230}
231
232template <class T> static double *extract_double_array_helper(Array *a) {
233 assert(a);
234
235 int length = a->length();
236
237 vector<T> b(length);
238 a->value(b.data()); // Extract the values of 'a' to 'b'
239
240 double *dest = new double[length];
241 for (int i = 0; i < length; ++i)
242 dest[i] = (double)b[i];
243
244 return dest;
245}
246
258 assert(a);
259
260 // Simple types are Byte, ..., Float64, String and Url.
261 if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c ||
262 a->var()->type() == dods_url_c)
263 throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
264
265 if (!a->read_p())
266 throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "'does not contain values.");
267
268 // The types of arguments that the CE Parser will build for numeric
269 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
270 // Expanded to work for any numeric type so it can be used for more than
271 // just arguments.
272 switch (a->var()->type()) {
273 case dods_byte_c:
274 return extract_double_array_helper<dods_byte>(a);
275 case dods_uint16_c:
276 return extract_double_array_helper<dods_uint16>(a);
277 case dods_int16_c:
278 return extract_double_array_helper<dods_int16>(a);
279 case dods_uint32_c:
280 return extract_double_array_helper<dods_uint32>(a);
281 case dods_int32_c:
282 return extract_double_array_helper<dods_int32>(a);
283 case dods_float32_c:
284 return extract_double_array_helper<dods_float32>(a);
285 case dods_float64_c:
286 // Should not be copying these values, just read them,
287 // but older code may depend on the return of this function
288 // being something that should be deleted, so leave this
289 // alone. jhrg 2/24/15
290 return extract_double_array_helper<dods_float64>(a);
291
292 // Support for DAP4
293 case dods_uint8_c:
294 return extract_double_array_helper<dods_byte>(a);
295 case dods_int8_c:
296 return extract_double_array_helper<dods_int8>(a);
297 case dods_uint64_c:
298 return extract_double_array_helper<dods_uint64>(a);
299 case dods_int64_c:
300 return extract_double_array_helper<dods_int64>(a);
301 default:
302 throw InternalErr(__FILE__, __LINE__,
303 "The argument list built by the CE parser contained an unsupported numeric type.");
304 }
305}
306
307// This helper function assumes 'dest' is the correct size. This should not
308// be called when the Array 'a' is a Float64, since the values are already
309// in a double array!
310template <class T> static void extract_double_array_helper(Array *a, vector<double> &dest) {
311 assert(a);
312 assert(dest.size() == (unsigned long)a->length());
313
314 int length = a->length();
315
316 vector<T> b(length);
317 a->value(b.data()); // Extract the values of 'a' to 'b'
318
319 for (int i = 0; i < length; ++i)
320 dest[i] = (double)b[i];
321}
322
337void extract_double_array(Array *a, vector<double> &dest) {
338 assert(a);
339
340 // Simple types are Byte, ..., Float64, String and Url.
341 if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c ||
342 a->var()->type() == dods_url_c)
343 throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
344
345 if (!a->read_p())
346 throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "' does not contain values.");
347
348 dest.resize(a->length());
349
350 // The types of arguments that the CE Parser will build for numeric
351 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
352 // Expanded to work for any numeric type so it can be used for more than
353 // just arguments.
354 switch (a->var()->type()) {
355 case dods_byte_c:
356 return extract_double_array_helper<dods_byte>(a, dest);
357 case dods_uint16_c:
358 return extract_double_array_helper<dods_uint16>(a, dest);
359 case dods_int16_c:
360 return extract_double_array_helper<dods_int16>(a, dest);
361 case dods_uint32_c:
362 return extract_double_array_helper<dods_uint32>(a, dest);
363 case dods_int32_c:
364 return extract_double_array_helper<dods_int32>(a, dest);
365 case dods_float32_c:
366 return extract_double_array_helper<dods_float32>(a, dest);
367 case dods_float64_c:
368 return a->value(dest.data()); // no need to copy the values
369 // return extract_double_array_helper<dods_float64>(a, dest);
370
371 // Support for DAP4
372 case dods_uint8_c:
373 return extract_double_array_helper<dods_byte>(a, dest);
374 case dods_int8_c:
375 return extract_double_array_helper<dods_int8>(a, dest);
376 case dods_uint64_c:
377 return extract_double_array_helper<dods_uint64>(a, dest);
378 case dods_int64_c:
379 return extract_double_array_helper<dods_int64>(a, dest);
380 default:
381 throw InternalErr(__FILE__, __LINE__,
382 "The argument list built by the CE parser contained an unsupported numeric type.");
383 }
384}
385
396 assert(arg);
397
398 // Simple types are Byte, ..., Float64, String and Url.
399 if (!arg->is_simple_type() || arg->type() == dods_str_c || arg->type() == dods_url_c)
400 throw Error(malformed_expr, "The function requires a numeric-type argument.");
401
402 if (!arg->read_p())
403 throw InternalErr(__FILE__, __LINE__,
404 "The Evaluator built an argument list where some constants held no values.");
405
406 // The types of arguments that the CE Parser will build for numeric
407 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
408 // Expanded to work for any numeric type so it can be used for more than
409 // just arguments.
410 switch (arg->type()) {
411 case dods_byte_c:
412 return (double)(static_cast<Byte *>(arg)->value());
413 case dods_uint16_c:
414 return (double)(static_cast<UInt16 *>(arg)->value());
415 case dods_int16_c:
416 return (double)(static_cast<Int16 *>(arg)->value());
417 case dods_uint32_c:
418 return (double)(static_cast<UInt32 *>(arg)->value());
419 case dods_int32_c:
420 return (double)(static_cast<Int32 *>(arg)->value());
421 case dods_float32_c:
422 return (double)(static_cast<Float32 *>(arg)->value());
423 case dods_float64_c:
424 return static_cast<Float64 *>(arg)->value();
425
426 // Support for DAP4 types.
427 case dods_uint8_c:
428 return (double)(static_cast<Byte *>(arg)->value());
429 case dods_int8_c:
430 return (double)(static_cast<Int8 *>(arg)->value());
431 case dods_uint64_c:
432 return (double)(static_cast<UInt64 *>(arg)->value());
433 case dods_int64_c:
434 return (double)(static_cast<Int64 *>(arg)->value());
435
436 default:
437 throw InternalErr(__FILE__, __LINE__,
438 "The argument list built by the parser contained an unsupported numeric type.");
439 }
440}
441
442// Remove spaces from the start of a URL and from the start of any constraint
443// expression it contains. 4/7/98 jhrg
444
451string prune_spaces(const string &name) {
452 // If the URL does not even have white space return.
453 if (name.find_first_of(' ') == name.npos)
454 return name;
455 else {
456 // Strip leading spaces from http://...
457 unsigned int i = name.find_first_not_of(' ');
458 string tmp_name = name.substr(i);
459
460 // Strip leading spaces from constraint part (following `?').
461 unsigned int j = tmp_name.find('?') + 1;
462 i = tmp_name.find_first_not_of(' ', j);
463 tmp_name.erase(j, i - j);
464
465 return tmp_name;
466 }
467}
468
469// Compare elements in a list of (BaseType *)s and return true if there are
470// no duplicate elements, otherwise return false.
471
472bool unique_names(vector<BaseType *> l, const string &var_name, const string &type_name, string &msg) {
473 // copy the identifier names to a vector
474 vector<string> names(l.size());
475
476 int nelem = 0;
477 typedef std::vector<BaseType *>::const_iterator citer;
478 for (citer i = l.begin(); i != l.end(); i++) {
479 assert(*i);
480 names[nelem++] = (*i)->name();
481 DBG(cerr << "NAMES[" << nelem - 1 << "]=" << names[nelem - 1] << endl);
482 }
483
484 // sort the array of names
485 sort(names.begin(), names.end());
486
487 // sort the array of names
488 sort(names.begin(), names.end());
489
490 // look for any instance of consecutive names that are ==
491 for (int j = 1; j < nelem; ++j) {
492 if (names[j - 1] == names[j]) {
493 ostringstream oss;
494 oss << "The variable `" << names[j] << "' is used more than once in " << type_name << " `" << var_name
495 << "'";
496 msg = oss.str();
497
498 return false;
499 }
500 }
501
502 return true;
503}
504
505const char *libdap_root() { return LIBDAP_ROOT; }
506
511extern "C" const char *libdap_version() {
512 // return PACKAGE_VERSION;
513 // Switched to CVER which is <version>-<build_number>
514 return CVER;
515}
516
517extern "C" const char *libdap_name() { return PACKAGE_NAME; }
518
524string systime() {
525 time_t TimBin;
526
527 if (time(&TimBin) == (time_t)-1)
528 return {"time() error"};
529 else {
530 char ctime_value[32];
531 const char *ret = ctime_r(&TimBin, ctime_value);
532 if (ret) {
533 string TimStr = ctime_value;
534 return TimStr.substr(0, TimStr.size() - 2); // remove the \n
535 } else
536 return {"Unknown"};
537 }
538}
539
544void downcase(string &s) {
545 for (unsigned int i = 0; i < s.length(); i++)
546 s[i] = tolower(s[i]);
547}
548
554bool is_quoted(const string &s) { return (!s.empty() && s[0] == '\"' && s[s.length() - 1] == '\"'); }
555
562string remove_quotes(const string &s) {
563 if (is_quoted(s))
564 return s.substr(1, s.length() - 2);
565 else
566 return s;
567}
568
570Type get_type(const char *name) {
571 if (strcmp(name, "Byte") == 0)
572 return dods_byte_c;
573
574 if (strcmp(name, "Char") == 0)
575 return dods_char_c;
576
577 if (strcmp(name, "Int8") == 0)
578 return dods_int8_c;
579
580 if (strcmp(name, "UInt8") == 0)
581 return dods_uint8_c;
582
583 if (strcmp(name, "Int16") == 0)
584 return dods_int16_c;
585
586 if (strcmp(name, "UInt16") == 0)
587 return dods_uint16_c;
588
589 if (strcmp(name, "Int32") == 0)
590 return dods_int32_c;
591
592 if (strcmp(name, "UInt32") == 0)
593 return dods_uint32_c;
594
595 if (strcmp(name, "Int64") == 0)
596 return dods_int64_c;
597
598 if (strcmp(name, "UInt64") == 0)
599 return dods_uint64_c;
600
601 if (strcmp(name, "Float32") == 0)
602 return dods_float32_c;
603
604 if (strcmp(name, "Float64") == 0)
605 return dods_float64_c;
606
607 if (strcmp(name, "String") == 0)
608 return dods_str_c;
609
610 // accept both spellings; this might be confusing since URL
611 // could be filtered through code and come out Url. Don't know...
612 // jhrg 8/15/13
613 if (strcmp(name, "Url") == 0 || strcmp(name, "URL") == 0)
614 return dods_url_c;
615
616 if (strcmp(name, "Enum") == 0)
617 return dods_enum_c;
618
619 if (strcmp(name, "Opaque") == 0)
620 return dods_opaque_c;
621
622 if (strcmp(name, "Array") == 0)
623 return dods_array_c;
624
625 if (strcmp(name, "Structure") == 0)
626 return dods_structure_c;
627
628 if (strcmp(name, "Sequence") == 0)
629 return dods_sequence_c;
630
631 if (strcmp(name, "Grid") == 0)
632 return dods_grid_c;
633
634 return dods_null_c;
635}
636
644string D2type_name(Type t) {
645 switch (t) {
646 case dods_null_c:
647 return string("Null");
648 case dods_byte_c:
649 return string("Byte");
650 case dods_int16_c:
651 return string("Int16");
652 case dods_uint16_c:
653 return string("UInt16");
654 case dods_int32_c:
655 return string("Int32");
656 case dods_uint32_c:
657 return string("UInt32");
658 case dods_float32_c:
659 return string("Float32");
660 case dods_float64_c:
661 return string("Float64");
662 case dods_str_c:
663 return string("String");
664 case dods_url_c:
665 return string("Url");
666
667 case dods_array_c:
668 return string("Array");
669 case dods_structure_c:
670 return string("Structure");
671 case dods_sequence_c:
672 return string("Sequence");
673 case dods_grid_c:
674 return string("Grid");
675
676 default:
677 throw InternalErr(__FILE__, __LINE__, "Unknown type.");
678 }
679}
680
688string D4type_name(Type t) {
689 switch (t) {
690 case dods_null_c:
691 return string("Null");
692 case dods_byte_c:
693 return string("Byte");
694 case dods_char_c:
695 return string("Char");
696 case dods_int8_c:
697 return string("Int8");
698 case dods_uint8_c:
699 return string("UInt8");
700 case dods_int16_c:
701 return string("Int16");
702 case dods_uint16_c:
703 return string("UInt16");
704 case dods_int32_c:
705 return string("Int32");
706 case dods_uint32_c:
707 return string("UInt32");
708 case dods_int64_c:
709 return string("Int64");
710 case dods_uint64_c:
711 return string("UInt64");
712 case dods_enum_c:
713 return string("Enum");
714
715 case dods_float32_c:
716 return string("Float32");
717 case dods_float64_c:
718 return string("Float64");
719
720 case dods_str_c:
721 return string("String");
722 case dods_url_c:
723 return string("URL");
724
725 case dods_opaque_c:
726 return string("Opaque");
727
728 case dods_array_c:
729 return string("Array");
730
731 case dods_structure_c:
732 return string("Structure");
733 case dods_sequence_c:
734 return string("Sequence");
735 case dods_group_c:
736 return string("Group");
737
738 default:
739 throw InternalErr(__FILE__, __LINE__, "Unknown type.");
740 }
741}
742
753string type_name(Type t) {
754 try {
755 return D4type_name(t);
756 } catch (...) {
757 return D2type_name(t);
758 }
759}
760
767 switch (t) {
768
769 case dods_byte_c:
770 case dods_char_c:
771
772 case dods_int8_c:
773 case dods_uint8_c:
774
775 case dods_int16_c:
776 case dods_uint16_c:
777 case dods_int32_c:
778 case dods_uint32_c:
779
780 case dods_int64_c:
781 case dods_uint64_c:
782
783 case dods_float32_c:
784 case dods_float64_c:
785 case dods_str_c:
786 case dods_url_c:
787 case dods_enum_c:
788 case dods_opaque_c:
789 return true;
790
791 case dods_null_c:
792 case dods_array_c:
793 case dods_structure_c:
794 case dods_sequence_c:
795 case dods_grid_c:
796 case dods_group_c:
797 default:
798 return false;
799 }
800}
801
806 switch (t) {
807 case dods_null_c:
808 case dods_byte_c:
809 case dods_char_c:
810
811 case dods_int8_c:
812 case dods_uint8_c:
813
814 case dods_int16_c:
815 case dods_uint16_c:
816
817 case dods_int32_c:
818 case dods_uint32_c:
819
820 case dods_int64_c:
821 case dods_uint64_c:
822
823 case dods_float32_c:
824 case dods_float64_c:
825
826 case dods_str_c:
827 case dods_url_c:
828 case dods_enum_c:
829 case dods_opaque_c:
830 return false;
831
832 case dods_array_c:
833 return true;
834
835 case dods_structure_c:
836 case dods_sequence_c:
837 case dods_grid_c:
838 case dods_group_c:
839 default:
840 return false;
841 }
842}
843
849 switch (t) {
850 case dods_null_c:
851 case dods_byte_c:
852 case dods_char_c:
853
854 case dods_int8_c:
855 case dods_uint8_c:
856
857 case dods_int16_c:
858 case dods_uint16_c:
859 case dods_int32_c:
860 case dods_uint32_c:
861
862 case dods_int64_c:
863 case dods_uint64_c:
864
865 case dods_float32_c:
866 case dods_float64_c:
867 case dods_str_c:
868 case dods_url_c:
869 case dods_enum_c:
870 case dods_opaque_c:
871
872 case dods_array_c:
873 return false;
874
875 case dods_structure_c:
876 case dods_sequence_c:
877 case dods_grid_c:
878 case dods_group_c:
879 default:
880 return true;
881 }
882}
883
889 switch (t) {
890 case dods_byte_c:
891 case dods_char_c:
892 case dods_int8_c:
893 case dods_uint8_c:
894 case dods_int16_c:
895 case dods_uint16_c:
896 case dods_int32_c:
897 case dods_uint32_c:
898 case dods_int64_c:
899 case dods_uint64_c:
900 return true;
901 default:
902 return false;
903 }
904}
905
912bool dir_exists(const string &dir) {
913 struct stat buf;
914
915 return (stat(dir.c_str(), &buf) == 0) && (buf.st_mode & S_IFDIR);
916}
917
918// Jose Garcia
919void append_long_to_string(long val, int base, string &str_val) {
920 // The array digits contains 36 elements which are the
921 // posible valid digits for out bases in the range
922 // [2,36]
923 char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
924 // result of val / base
925 ldiv_t r;
926
927 if (base > 36 || base < 2) {
928 // no conversion if wrong base
929 std::invalid_argument ex("The parameter base has an invalid value.");
930 throw ex;
931 }
932 if (val < 0)
933 str_val += '-';
934 r = ldiv(labs(val), base);
935
936 // output digits of val/base first
937 if (r.quot > 0)
938 append_long_to_string(r.quot, base, str_val);
939
940 // output last digit
941
942 str_val += digits[(int)r.rem];
943}
944
945// base defaults to 10
946string long_to_string(long val, int base) {
947 string s;
948 append_long_to_string(val, base, s);
949 return s;
950}
951
952// Jose Garcia
953void append_double_to_string(const double &num, string &str) {
954 // s having 100 characters should be enough for sprintf to do its job.
955 // I want to banish all instances of sprintf. 10/5/2001 jhrg
956 ostringstream oss;
957 oss.precision(9);
958 oss << num;
959 str += oss.str();
960}
961
962string double_to_string(const double &num) {
963 string s;
965 return s;
966}
967
968// Given a pathname, return the file at the end of the path. This is used
969// when reporting errors (maybe other times, too) to keep the server from
970// revealing too much about its organization when sending error responses
971// back to clients. 10/11/2000 jhrg
972// MT-safe. 08/05/02 jhrg
973
974#ifdef WIN32
975static const char path_sep[] = {"\\"};
976#else
977static const char path_sep[] = {"/"};
978#endif
979
988string path_to_filename(string path) {
989 string::size_type pos = path.rfind(path_sep);
990
991 return (pos == string::npos) ? path : path.substr(++pos);
992}
993
994#define CHECK_BIT(tab, bit) (tab[(bit) / 8] & (1 << ((bit) % 8)))
995#define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
996
997/*
998 * globchars() - build a bitlist to check for character group match
999 */
1000
1001static void globchars(const char *s, const char *e, char *b) {
1002 int neg = 0;
1003
1004 memset(b, '\0', BITLISTSIZE);
1005
1006 if (*s == '^')
1007 neg++, s++;
1008
1009 while (s < e) {
1010 int c;
1011
1012 if (s + 2 < e && s[1] == '-') {
1013 for (c = s[0]; c <= s[2]; c++)
1014 b[c / 8] |= (1 << (c % 8));
1015 s += 3;
1016 } else {
1017 c = *s++;
1018 b[c / 8] |= (1 << (c % 8));
1019 }
1020 }
1021
1022 if (neg) {
1023 int i;
1024 for (i = 0; i < BITLISTSIZE; i++)
1025 b[i] ^= 0377;
1026 }
1027
1028 /* Don't include \0 in either $[chars] or $[^chars] */
1029
1030 b[0] &= 0376;
1031}
1032
1049int glob(const char *c, const char *s) {
1050 if (!c || !s)
1051 return 1;
1052
1053 char bitlist[BITLISTSIZE];
1054 int i = 0;
1055 for (;;) {
1056 ++i;
1057 switch (*c++) {
1058 case '\0':
1059 return *s ? -1 : 0;
1060
1061 case '?':
1062 if (!*s++)
1063 return i /*1*/;
1064 break;
1065
1066 case '[': {
1067 /* scan for matching ] */
1068
1069 const char *here = c;
1070 do {
1071 if (!*c++)
1072 return i /*1*/;
1073 } while (here == c || *c != ']');
1074 c++;
1075
1076 /* build character class bitlist */
1077
1078 globchars(here, c, bitlist);
1079
1080 if (!CHECK_BIT(bitlist, *(unsigned char *)s))
1081 return i /*1*/;
1082 s++;
1083 break;
1084 }
1085
1086 case '*': {
1087 const char *here = s;
1088
1089 while (*s)
1090 s++;
1091
1092 /* Try to match the rest of the pattern in a recursive */
1093 /* call. If the match fails we'll back up chars, retrying. */
1094
1095 while (s != here) {
1096 int r;
1097
1098 /* A fast path for the last token in a pattern */
1099
1100 r = *c ? glob(c, s) : *s ? -1 : 0;
1101
1102 if (!r)
1103 return 0;
1104 else if (r < 0)
1105 return i /*1*/;
1106
1107 --s;
1108 }
1109 break;
1110 }
1111
1112 case '\\':
1113 /* Force literal match of next char. */
1114
1115 if (!*c || *s != *c) {
1116 return i /*1*/;
1117 } else {
1118 s++;
1119 c++;
1120 }
1121 break;
1122
1123 default:
1124 if (*s++ != c[-1])
1125 return i /*1*/;
1126 break;
1127 }
1128 }
1129}
1130
1133
1138bool size_ok(unsigned int sz, unsigned int nelem) { return (sz > 0 && nelem < UINT_MAX / sz); }
1139
1156bool pathname_ok(const string &path, bool strict) {
1157 if (path.length() > 255)
1158 return false;
1159
1160#if 0
1161 // Make this use a const regex 12/1/21
1162 Regex name("[-0-9A-z_./]+");
1163 if (!strict) name = "[:print:]+";
1164#endif
1165
1166 const Regex strict_name("[-0-9A-z_./]+");
1167 const Regex relaxed_name("[:print:]+");
1168
1169#if 0
1170 string::size_type len = path.length();
1171#endif
1172 unsigned long result;
1173 if (strict)
1174 result = strict_name.match(path);
1175 else
1176 result = relaxed_name.match(path);
1177
1178 return (result == path.length());
1179
1180#if 0
1181 // Protect against casting too big an uint to int
1182 // if LEN is bigger than the max int32, the second test can't work
1183
1184 // This makes no sense - len can never be > 255 given the test at the
1185 // start of this function. jhrg 12/1/21
1186 if (len > INT_MAX || result != static_cast<int>(len)) return false;
1187
1188 return true;
1189#endif
1190}
1191
1193
1198string dap_version() {
1199 return (string) "OPeNDAP DAP/" + libdap_version() + ": compiled on " + __DATE__ + ":" + __TIME__;
1200}
1201
1214string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix /* = "" */) {
1215 vector<char> name;
1216 copy(name_template.begin(), name_template.end(), back_inserter(name));
1217 if (!suffix.empty())
1218 copy(suffix.begin(), suffix.end(), back_inserter(name));
1219 name.push_back('\0');
1220
1221 // Use mkstemp to make and open the temp file atomically
1222 int tmpfile = mkstemps(name.data(), suffix.length());
1223 if (tmpfile == -1)
1224 throw Error(internal_error, "Could not make a temporary file.");
1225 // Open the file using C++ ofstream; get a C++ fstream object
1226 f.open(name.data());
1227 // Close the file descriptor; the file stays open because of the fstream object
1228 close(tmpfile);
1229 // Now test that the fstream object is valid
1230 if (f.fail())
1231 throw Error(internal_error, "Could not make a temporary file.");
1232
1233 return string(name.data());
1234}
1235
1236} // namespace libdap
#define internal_error
Internal server error (500)
Definition Error.h:63
#define malformed_expr
(400)
Definition Error.h:66
A multidimensional array of identical data types.
Definition Array.h:121
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual string name() const
Returns the name of the class instance.
Definition BaseType.cc:296
virtual bool read_p()
Has this variable been read?
Definition BaseType.cc:410
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition BaseType.cc:347
virtual Type type() const
Returns the type of the class instance.
Definition BaseType.cc:329
Holds a single byte.
Definition Byte.h:59
virtual dods_byte value() const
Definition Byte.cc:212
A class for error processing.
Definition Error.h:92
Holds a 32-bit floating point value.
Definition Float32.h:59
virtual dods_float32 value() const
Definition Float32.cc:192
Holds a 64-bit (double precision) floating point value.
Definition Float64.h:58
Holds a 16-bit signed integer value.
Definition Int16.h:57
virtual dods_int16 value() const
Definition Int16.cc:170
Holds a 32-bit signed integer.
Definition Int32.h:63
virtual dods_int32 value() const
Definition Int32.cc:177
Holds a64-bit signed integer.
Definition Int64.h:48
virtual dods_int64 value() const
Definition Int64.cc:135
Holds an 8-bit signed integer value.
Definition Int8.h:41
virtual dods_int8 value() const
Definition Int8.cc:115
A class for software fault reporting.
Definition InternalErr.h:61
Regular expression matching.
Definition GNURegex.h:54
int match(const char *s, int len, int pos=0) const
Does the pattern match.
Definition GNURegex.cc:136
Holds character string data.
Definition Str.h:61
Holds an unsigned 16-bit integer.
Definition UInt16.h:55
virtual dods_uint16 value() const
Definition UInt16.cc:170
Holds a 32-bit unsigned integer.
Definition UInt32.h:57
virtual dods_uint32 value() const
Definition UInt32.cc:172
Holds a 64-bit unsigned integer.
Definition UInt64.h:47
virtual dods_uint64 value() const
Definition UInt64.cc:113
int length() const override
Returns the number of elements in the vector. Note that some child classes of Vector use the length o...
Definition Vector.h:210
virtual void value(dods_byte *b) const
Definition Vector.cc:2295
void set_read_p(bool state) override
Indicates that the data is ready to send.
Definition Vector.cc:389
BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr) override
Definition Vector.cc:469
#define LIBDAP_ROOT
Definition config.h:877
#define PACKAGE_NAME
Definition config.h:915
#define CVER
Definition config.h:32
#define DBG(x)
Definition debug.h:58
top level DAP object to house generic methods
Definition AISConnect.cc:30
Type
Identifies the data type.
Definition Type.h:94
@ dods_group_c
Definition Type.h:122
@ dods_sequence_c
Definition Type.h:108
@ dods_uint32_c
Definition Type.h:100
@ dods_int16_c
Definition Type.h:97
@ dods_byte_c
Definition Type.h:96
@ dods_int32_c
Definition Type.h:99
@ dods_url_c
Definition Type.h:104
@ dods_int8_c
Definition Type.h:115
@ dods_float32_c
Definition Type.h:101
@ dods_char_c
Definition Type.h:114
@ dods_int64_c
Definition Type.h:118
@ dods_uint64_c
Definition Type.h:119
@ dods_uint16_c
Definition Type.h:98
@ dods_float64_c
Definition Type.h:102
@ dods_null_c
Definition Type.h:95
@ dods_enum_c
Definition Type.h:120
@ dods_grid_c
Definition Type.h:111
@ dods_uint8_c
Definition Type.h:116
@ dods_str_c
Definition Type.h:103
@ dods_structure_c
Definition Type.h:106
@ dods_array_c
Definition Type.h:107
@ dods_opaque_c
Definition Type.h:121
string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix)
Definition util.cc:1214
const char * libdap_name()
Definition util.cc:517
string long_to_string(long val, int base)
Definition util.cc:946
bool size_ok(unsigned int sz, unsigned int nelem)
sanitize the size of an array. Test for integer overflow when dynamically allocating an array.
Definition util.cc:1138
string remove_quotes(const string &s)
Definition util.cc:562
void append_double_to_string(const double &num, string &str)
Definition util.cc:953
string path_to_filename(string path)
Definition util.cc:988
bool is_host_big_endian()
Does this host use big-endian byte order?
Definition util.cc:94
const char * libdap_version()
Definition util.cc:511
double extract_double_value(BaseType *arg)
Definition util.cc:395
string prune_spaces(const string &name)
Definition util.cc:451
string type_name(Type t)
Definition util.cc:753
void append_long_to_string(long val, int base, string &str_val)
Definition util.cc:919
void set_array_using_double(Array *dest, double *src, int src_len)
Definition util.cc:164
bool is_simple_type(Type t)
Returns true if the instance is a numeric, string or URL type variable.
Definition util.cc:766
bool dir_exists(const string &dir)
Definition util.cc:912
bool pathname_ok(const string &path, bool strict)
Does the string name a potentially valid pathname? Test the given pathname to verify that it is a val...
Definition util.cc:1156
string double_to_string(const double &num)
Definition util.cc:962
void downcase(string &s)
Definition util.cc:544
string D2type_name(Type t)
Returns the type of the class instance as a string. Supports all DAP2 types and not the DAP4-only typ...
Definition util.cc:644
const char * libdap_root()
Definition util.cc:505
string D4type_name(Type t)
Returns the type of the class instance as a string. Supports all DAP4 types and not the DAP2-only typ...
Definition util.cc:688
string systime()
Definition util.cc:524
bool is_constructor_type(Type t)
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable.
Definition util.cc:848
bool is_vector_type(Type t)
Returns true if the instance is a vector (i.e., array) type variable.
Definition util.cc:805
bool is_integer_type(Type t)
Definition util.cc:888
int glob(const char *c, const char *s)
Definition util.cc:1049
string extract_string_argument(BaseType *arg)
Definition util.cc:118
ObjectType get_type(const string &value)
Definition mime_util.cc:300
double * extract_double_array(Array *a)
Definition util.cc:257
bool is_quoted(const string &s)
Definition util.cc:554
bool unique_names(vector< BaseType * > l, const string &var_name, const string &type_name, string &msg)
Definition util.cc:472
string dap_version()
Definition util.cc:1198
#define CHECK_BIT(tab, bit)
Definition util.cc:994
#define BITLISTSIZE
Definition util.cc:995