libdap Updated for version 3.20.11
libdap4 is an implementation of OPeNDAP's DAP protocol.
util.cc
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 <cstring>
41#include <climits>
42#include <cstdlib>
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 <io.h>
55#include <fcntl.h>
56#include <process.h>
57#endif
58
59#include <sys/types.h>
60#include <sys/stat.h>
61
62#include <string>
63#include <sstream>
64#include <vector>
65#include <algorithm>
66#include <stdexcept>
67
68#include "BaseType.h"
69#include "Byte.h"
70#include "Int16.h"
71#include "Int32.h"
72#include "UInt16.h"
73#include "UInt32.h"
74#include "Float32.h"
75#include "Float64.h"
76#include "Str.h"
77#include "Array.h"
78
79#include "Int64.h"
80#include "UInt64.h"
81#include "Int8.h"
82
83#include "Error.h"
84
85#include "util.h"
86#include "GNURegex.h"
87#include "debug.h"
88
89using namespace std;
90
91namespace libdap {
92
95{
96#ifdef COMPUTE_ENDIAN_AT_RUNTIME
97
98 dods_int16 i = 0x0100;
99 char *c = reinterpret_cast<char*>(&i);
100 return *c;
101
102#else
103
104#if WORDS_BIGENDIAN
105 return true;
106#else
107 return false;
108#endif
109
110#endif
111}
112
120{
121 assert(arg);
122
123 if (arg->type() != dods_str_c) throw Error(malformed_expr, "The function requires a string argument.");
124
125 if (!arg->read_p())
126 throw InternalErr(__FILE__, __LINE__,
127 "The CE Evaluator built an argument list where some constants held no values.");
128
129 return static_cast<Str*>(arg)->value();
130}
131
132template<class T> static void set_array_using_double_helper(Array *a, double *src, int src_len)
133{
134 assert(a);
135 assert(src);
136 assert(src_len > 0);
137
138 vector<T> values(src_len);
139 for (int i = 0; i < src_len; ++i)
140 values[i] = (T) src[i];
141
142 // This copies the values
143 a->set_value(values, src_len);
144}
145
166void set_array_using_double(Array *dest, double *src, int src_len)
167{
168 assert(dest);
169 assert(src);
170 assert(src_len > 0);
171
172 // Simple types are Byte, ..., Float64, String and Url.
173 if ((dest->type() == dods_array_c && !dest->var()->is_simple_type()) || dest->var()->type() == dods_str_c
174 || dest->var()->type() == dods_url_c)
175 throw InternalErr(__FILE__, __LINE__, "The function requires a numeric-type array argument.");
176
177 // Test sizes. Note that Array::length() takes any constraint into account
178 // when it returns the length. Even if this was removed, the 'helper'
179 // function this uses calls Vector::val2buf() which uses Vector::width()
180 // which in turn uses length().
181 if (dest->length() != src_len)
182 throw InternalErr(__FILE__, __LINE__,
183 "The source and destination array sizes don't match (" + long_to_string(src_len) + " versus "
184 + long_to_string(dest->length()) + ").");
185
186 // The types of arguments that the CE Parser will build for numeric
187 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
188 // Expanded to work for any numeric type so it can be used for more than
189 // just arguments.
190 switch (dest->var()->type()) {
191 case dods_byte_c:
192 set_array_using_double_helper<dods_byte>(dest, src, src_len);
193 break;
194 case dods_uint16_c:
195 set_array_using_double_helper<dods_uint16>(dest, src, src_len);
196 break;
197 case dods_int16_c:
198 set_array_using_double_helper<dods_int16>(dest, src, src_len);
199 break;
200 case dods_uint32_c:
201 set_array_using_double_helper<dods_uint32>(dest, src, src_len);
202 break;
203 case dods_int32_c:
204 set_array_using_double_helper<dods_int32>(dest, src, src_len);
205 break;
206 case dods_float32_c:
207 set_array_using_double_helper<dods_float32>(dest, src, src_len);
208 break;
209 case dods_float64_c:
210 set_array_using_double_helper<dods_float64>(dest, src, src_len);
211 break;
212
213 // DAP4 support
214 case dods_uint8_c:
215 set_array_using_double_helper<dods_byte>(dest, src, src_len);
216 break;
217 case dods_int8_c:
218 set_array_using_double_helper<dods_int8>(dest, src, src_len);
219 break;
220 case dods_uint64_c:
221 set_array_using_double_helper<dods_uint64>(dest, src, src_len);
222 break;
223 case dods_int64_c:
224 set_array_using_double_helper<dods_int64>(dest, src, src_len);
225 break;
226 default:
227 throw InternalErr(__FILE__, __LINE__,
228 "The argument list built by the CE parser contained an unsupported numeric type.");
229 }
230
231 // Set the read_p property.
232 dest->set_read_p(true);
233}
234
235template<class T> static double *extract_double_array_helper(Array * a)
236{
237 assert(a);
238
239 int length = a->length();
240
241 vector<T> b(length);
242 a->value(b.data()); // Extract the values of 'a' to 'b'
243
244 double *dest = new double[length];
245 for (int i = 0; i < length; ++i)
246 dest[i] = (double) b[i];
247
248 return dest;
249}
250
262{
263 assert(a);
264
265 // Simple types are Byte, ..., Float64, String and Url.
266 if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
267 || a->var()->type() == dods_url_c)
268 throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
269
270 if (!a->read_p())
271 throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "'does not contain values.");
272
273 // The types of arguments that the CE Parser will build for numeric
274 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
275 // Expanded to work for any numeric type so it can be used for more than
276 // just arguments.
277 switch (a->var()->type()) {
278 case dods_byte_c:
279 return extract_double_array_helper<dods_byte>(a);
280 case dods_uint16_c:
281 return extract_double_array_helper<dods_uint16>(a);
282 case dods_int16_c:
283 return extract_double_array_helper<dods_int16>(a);
284 case dods_uint32_c:
285 return extract_double_array_helper<dods_uint32>(a);
286 case dods_int32_c:
287 return extract_double_array_helper<dods_int32>(a);
288 case dods_float32_c:
289 return extract_double_array_helper<dods_float32>(a);
290 case dods_float64_c:
291 // Should not be copying these values, just read them,
292 // but older code may depend on the return of this function
293 // being something that should be deleted, so leave this
294 // alone. jhrg 2/24/15
295 return extract_double_array_helper<dods_float64>(a);
296
297 // Support for DAP4
298 case dods_uint8_c:
299 return extract_double_array_helper<dods_byte>(a);
300 case dods_int8_c:
301 return extract_double_array_helper<dods_int8>(a);
302 case dods_uint64_c:
303 return extract_double_array_helper<dods_uint64>(a);
304 case dods_int64_c:
305 return extract_double_array_helper<dods_int64>(a);
306 default:
307 throw InternalErr(__FILE__, __LINE__,
308 "The argument list built by the CE parser contained an unsupported numeric type.");
309 }
310}
311
312// This helper function assumes 'dest' is the correct size. This should not
313// be called when the Array 'a' is a Float64, since the values are already
314// in a double array!
315template<class T> static void extract_double_array_helper(Array * a, vector<double> &dest)
316{
317 assert(a);
318 assert(dest.size() == (unsigned long )a->length());
319
320 int length = a->length();
321
322 vector<T> b(length);
323 a->value(b.data()); // Extract the values of 'a' to 'b'
324
325 for (int i = 0; i < length; ++i)
326 dest[i] = (double) b[i];
327}
328
343void extract_double_array(Array *a, vector<double> &dest)
344{
345 assert(a);
346
347 // Simple types are Byte, ..., Float64, String and Url.
348 if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
349 || a->var()->type() == dods_url_c)
350 throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
351
352 if (!a->read_p())
353 throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "' does not contain values.");
354
355 dest.resize(a->length());
356
357 // The types of arguments that the CE Parser will build for numeric
358 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
359 // Expanded to work for any numeric type so it can be used for more than
360 // just arguments.
361 switch (a->var()->type()) {
362 case dods_byte_c:
363 return extract_double_array_helper<dods_byte>(a, dest);
364 case dods_uint16_c:
365 return extract_double_array_helper<dods_uint16>(a, dest);
366 case dods_int16_c:
367 return extract_double_array_helper<dods_int16>(a, dest);
368 case dods_uint32_c:
369 return extract_double_array_helper<dods_uint32>(a, dest);
370 case dods_int32_c:
371 return extract_double_array_helper<dods_int32>(a, dest);
372 case dods_float32_c:
373 return extract_double_array_helper<dods_float32>(a, dest);
374 case dods_float64_c:
375 return a->value(dest.data()); // no need to copy the values
376 // return extract_double_array_helper<dods_float64>(a, dest);
377
378 // Support for DAP4
379 case dods_uint8_c:
380 return extract_double_array_helper<dods_byte>(a, dest);
381 case dods_int8_c:
382 return extract_double_array_helper<dods_int8>(a, dest);
383 case dods_uint64_c:
384 return extract_double_array_helper<dods_uint64>(a, dest);
385 case dods_int64_c:
386 return extract_double_array_helper<dods_int64>(a, dest);
387 default:
388 throw InternalErr(__FILE__, __LINE__,
389 "The argument list built by the CE parser contained an unsupported numeric type.");
390 }
391}
392
403{
404 assert(arg);
405
406 // Simple types are Byte, ..., Float64, String and Url.
407 if (!arg->is_simple_type() || arg->type() == dods_str_c || arg->type() == dods_url_c)
408 throw Error(malformed_expr, "The function requires a numeric-type argument.");
409
410 if (!arg->read_p())
411 throw InternalErr(__FILE__, __LINE__,
412 "The Evaluator built an argument list where some constants held no values.");
413
414 // The types of arguments that the CE Parser will build for numeric
415 // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
416 // Expanded to work for any numeric type so it can be used for more than
417 // just arguments.
418 switch (arg->type()) {
419 case dods_byte_c:
420 return (double) (static_cast<Byte*>(arg)->value());
421 case dods_uint16_c:
422 return (double) (static_cast<UInt16*>(arg)->value());
423 case dods_int16_c:
424 return (double) (static_cast<Int16*>(arg)->value());
425 case dods_uint32_c:
426 return (double) (static_cast<UInt32*>(arg)->value());
427 case dods_int32_c:
428 return (double) (static_cast<Int32*>(arg)->value());
429 case dods_float32_c:
430 return (double) (static_cast<Float32*>(arg)->value());
431 case dods_float64_c:
432 return static_cast<Float64*>(arg)->value();
433
434 // Support for DAP4 types.
435 case dods_uint8_c:
436 return (double) (static_cast<Byte*>(arg)->value());
437 case dods_int8_c:
438 return (double) (static_cast<Int8*>(arg)->value());
439 case dods_uint64_c:
440 return (double) (static_cast<UInt64*>(arg)->value());
441 case dods_int64_c:
442 return (double) (static_cast<Int64*>(arg)->value());
443
444 default:
445 throw InternalErr(__FILE__, __LINE__,
446 "The argument list built by the parser contained an unsupported numeric type.");
447 }
448}
449
450// Remove spaces from the start of a URL and from the start of any constraint
451// expression it contains. 4/7/98 jhrg
452
459string prune_spaces(const string &name)
460{
461 // If the URL does not even have white space return.
462 if (name.find_first_of(' ') == name.npos)
463 return name;
464 else {
465 // Strip leading spaces from http://...
466 unsigned int i = name.find_first_not_of(' ');
467 string tmp_name = name.substr(i);
468
469 // Strip leading spaces from constraint part (following `?').
470 unsigned int j = tmp_name.find('?') + 1;
471 i = tmp_name.find_first_not_of(' ', j);
472 tmp_name.erase(j, i - j);
473
474 return tmp_name;
475 }
476}
477
478// Compare elements in a list of (BaseType *)s and return true if there are
479// no duplicate elements, otherwise return false.
480
481bool unique_names(vector<BaseType *> l, const string &var_name, const string &type_name, string &msg)
482{
483 // copy the identifier names to a vector
484 vector<string> names(l.size());
485
486 int nelem = 0;
487 typedef std::vector<BaseType *>::const_iterator citer;
488 for (citer i = l.begin(); i != l.end(); i++) {
489 assert(*i);
490 names[nelem++] = (*i)->name();
491 DBG(cerr << "NAMES[" << nelem - 1 << "]=" << names[nelem-1] << endl);
492 }
493
494 // sort the array of names
495 sort(names.begin(), names.end());
496
497 // sort the array of names
498 sort(names.begin(), names.end());
499
500 // look for any instance of consecutive names that are ==
501 for (int j = 1; j < nelem; ++j) {
502 if (names[j - 1] == names[j]) {
503 ostringstream oss;
504 oss << "The variable `" << names[j] << "' is used more than once in " << type_name << " `" << var_name
505 << "'";
506 msg = oss.str();
507
508 return false;
509 }
510 }
511
512 return true;
513}
514
515const char *
516libdap_root()
517{
518 return LIBDAP_ROOT;
519}
520
525extern "C" const char *
527{
528 // return PACKAGE_VERSION;
529 // Switched to CVER which is <version>-<build_number>
530 return CVER;
531}
532
533extern "C" const char *
534libdap_name()
535{
536 return PACKAGE_NAME;
537}
538
544string systime()
545{
546 time_t TimBin;
547
548 if (time(&TimBin) == (time_t) -1)
549 return {"time() error"};
550 else {
551 char ctime_value[32];
552 const char *ret = ctime_r(&TimBin, ctime_value);
553 if (ret) {
554 string TimStr = ctime_value;
555 return TimStr.substr(0, TimStr.size() - 2); // remove the \n
556 }
557 else
558 return {"Unknown"};
559 }
560}
561
566void downcase(string &s)
567{
568 for (unsigned int i = 0; i < s.length(); i++)
569 s[i] = tolower(s[i]);
570}
571
577bool is_quoted(const string &s)
578{
579 return (!s.empty() && s[0] == '\"' && s[s.length() - 1] == '\"');
580}
581
588string remove_quotes(const string &s)
589{
590 if (is_quoted(s))
591 return s.substr(1, s.length() - 2);
592 else
593 return s;
594}
595
597Type get_type(const char *name)
598{
599 if (strcmp(name, "Byte") == 0) return dods_byte_c;
600
601 if (strcmp(name, "Char") == 0) return dods_char_c;
602
603 if (strcmp(name, "Int8") == 0) return dods_int8_c;
604
605 if (strcmp(name, "UInt8") == 0) return dods_uint8_c;
606
607 if (strcmp(name, "Int16") == 0) return dods_int16_c;
608
609 if (strcmp(name, "UInt16") == 0) return dods_uint16_c;
610
611 if (strcmp(name, "Int32") == 0) return dods_int32_c;
612
613 if (strcmp(name, "UInt32") == 0) return dods_uint32_c;
614
615 if (strcmp(name, "Int64") == 0) return dods_int64_c;
616
617 if (strcmp(name, "UInt64") == 0) return dods_uint64_c;
618
619 if (strcmp(name, "Float32") == 0) return dods_float32_c;
620
621 if (strcmp(name, "Float64") == 0) return dods_float64_c;
622
623 if (strcmp(name, "String") == 0) return dods_str_c;
624
625 // accept both spellings; this might be confusing since URL
626 // could be filtered through code and come out Url. Don't know...
627 // jhrg 8/15/13
628 if (strcmp(name, "Url") == 0 || strcmp(name, "URL") == 0) return dods_url_c;
629
630 if (strcmp(name, "Enum") == 0) return dods_enum_c;
631
632 if (strcmp(name, "Opaque") == 0) return dods_opaque_c;
633
634 if (strcmp(name, "Array") == 0) return dods_array_c;
635
636 if (strcmp(name, "Structure") == 0) return dods_structure_c;
637
638 if (strcmp(name, "Sequence") == 0) return dods_sequence_c;
639
640 if (strcmp(name, "Grid") == 0) return dods_grid_c;
641
642 return dods_null_c;
643}
644
653{
654 switch (t) {
655 case dods_null_c:
656 return string("Null");
657 case dods_byte_c:
658 return string("Byte");
659 case dods_int16_c:
660 return string("Int16");
661 case dods_uint16_c:
662 return string("UInt16");
663 case dods_int32_c:
664 return string("Int32");
665 case dods_uint32_c:
666 return string("UInt32");
667 case dods_float32_c:
668 return string("Float32");
669 case dods_float64_c:
670 return string("Float64");
671 case dods_str_c:
672 return string("String");
673 case dods_url_c:
674 return string("Url");
675
676 case dods_array_c:
677 return string("Array");
678 case dods_structure_c:
679 return string("Structure");
680 case dods_sequence_c:
681 return string("Sequence");
682 case dods_grid_c:
683 return string("Grid");
684
685 default:
686 throw InternalErr(__FILE__, __LINE__, "Unknown type.");
687 }
688}
689
698{
699 switch (t) {
700 case dods_null_c:
701 return string("Null");
702 case dods_byte_c:
703 return string("Byte");
704 case dods_char_c:
705 return string("Char");
706 case dods_int8_c:
707 return string("Int8");
708 case dods_uint8_c:
709 return string("UInt8");
710 case dods_int16_c:
711 return string("Int16");
712 case dods_uint16_c:
713 return string("UInt16");
714 case dods_int32_c:
715 return string("Int32");
716 case dods_uint32_c:
717 return string("UInt32");
718 case dods_int64_c:
719 return string("Int64");
720 case dods_uint64_c:
721 return string("UInt64");
722 case dods_enum_c:
723 return string("Enum");
724
725 case dods_float32_c:
726 return string("Float32");
727 case dods_float64_c:
728 return string("Float64");
729
730 case dods_str_c:
731 return string("String");
732 case dods_url_c:
733 return string("URL");
734
735 case dods_opaque_c:
736 return string("Opaque");
737
738 case dods_array_c:
739 return string("Array");
740
741 case dods_structure_c:
742 return string("Structure");
743 case dods_sequence_c:
744 return string("Sequence");
745 case dods_group_c:
746 return string("Group");
747
748 default:
749 throw InternalErr(__FILE__, __LINE__, "Unknown type.");
750 }
751}
752
764{
765 try {
766 return D4type_name(t);
767 }
768 catch (...) {
769 return D2type_name(t);
770 }
771}
772
779{
780 switch (t) {
781
782 case dods_byte_c:
783 case dods_char_c:
784
785 case dods_int8_c:
786 case dods_uint8_c:
787
788 case dods_int16_c:
789 case dods_uint16_c:
790 case dods_int32_c:
791 case dods_uint32_c:
792
793 case dods_int64_c:
794 case dods_uint64_c:
795
796 case dods_float32_c:
797 case dods_float64_c:
798 case dods_str_c:
799 case dods_url_c:
800 case dods_enum_c:
801 case dods_opaque_c:
802 return true;
803
804 case dods_null_c:
805 case dods_array_c:
806 case dods_structure_c:
807 case dods_sequence_c:
808 case dods_grid_c:
809 case dods_group_c:
810 default:
811 return false;
812 }
813}
814
819{
820 switch (t) {
821 case dods_null_c:
822 case dods_byte_c:
823 case dods_char_c:
824
825 case dods_int8_c:
826 case dods_uint8_c:
827
828 case dods_int16_c:
829 case dods_uint16_c:
830
831 case dods_int32_c:
832 case dods_uint32_c:
833
834 case dods_int64_c:
835 case dods_uint64_c:
836
837 case dods_float32_c:
838 case dods_float64_c:
839
840 case dods_str_c:
841 case dods_url_c:
842 case dods_enum_c:
843 case dods_opaque_c:
844 return false;
845
846 case dods_array_c:
847 return true;
848
849 case dods_structure_c:
850 case dods_sequence_c:
851 case dods_grid_c:
852 case dods_group_c:
853 default:
854 return false;
855 }
856}
857
863{
864 switch (t) {
865 case dods_null_c:
866 case dods_byte_c:
867 case dods_char_c:
868
869 case dods_int8_c:
870 case dods_uint8_c:
871
872 case dods_int16_c:
873 case dods_uint16_c:
874 case dods_int32_c:
875 case dods_uint32_c:
876
877 case dods_int64_c:
878 case dods_uint64_c:
879
880 case dods_float32_c:
881 case dods_float64_c:
882 case dods_str_c:
883 case dods_url_c:
884 case dods_enum_c:
885 case dods_opaque_c:
886
887 case dods_array_c:
888 return false;
889
890 case dods_structure_c:
891 case dods_sequence_c:
892 case dods_grid_c:
893 case dods_group_c:
894 default:
895 return true;
896 }
897}
898
904{
905 switch (t) {
906 case dods_byte_c:
907 case dods_char_c:
908 case dods_int8_c:
909 case dods_uint8_c:
910 case dods_int16_c:
911 case dods_uint16_c:
912 case dods_int32_c:
913 case dods_uint32_c:
914 case dods_int64_c:
915 case dods_uint64_c:
916 return true;
917 default:
918 return false;
919 }
920}
921
928bool dir_exists(const string &dir)
929{
930 struct stat buf;
931
932 return (stat(dir.c_str(), &buf) == 0) && (buf.st_mode & S_IFDIR);
933}
934
935// Jose Garcia
936void append_long_to_string(long val, int base, string &str_val)
937{
938 // The array digits contains 36 elements which are the
939 // posible valid digits for out bases in the range
940 // [2,36]
941 char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
942 // result of val / base
943 ldiv_t r;
944
945 if (base > 36 || base < 2) {
946 // no conversion if wrong base
947 std::invalid_argument ex("The parameter base has an invalid value.");
948 throw ex;
949 }
950 if (val < 0) str_val += '-';
951 r = ldiv(labs(val), base);
952
953 // output digits of val/base first
954 if (r.quot > 0) append_long_to_string(r.quot, base, str_val);
955
956 // output last digit
957
958 str_val += digits[(int) r.rem];
959}
960
961// base defaults to 10
962string long_to_string(long val, int base)
963{
964 string s;
965 append_long_to_string(val, base, s);
966 return s;
967}
968
969// Jose Garcia
970void append_double_to_string(const double &num, string &str)
971{
972 // s having 100 characters should be enough for sprintf to do its job.
973 // I want to banish all instances of sprintf. 10/5/2001 jhrg
974 ostringstream oss;
975 oss.precision(9);
976 oss << num;
977 str += oss.str();
978}
979
980string double_to_string(const double &num)
981{
982 string s;
983 append_double_to_string(num, s);
984 return s;
985}
986
987// Given a pathname, return the file at the end of the path. This is used
988// when reporting errors (maybe other times, too) to keep the server from
989// revealing too much about its organization when sending error responses
990// back to clients. 10/11/2000 jhrg
991// MT-safe. 08/05/02 jhrg
992
993#ifdef WIN32
994static const char path_sep[] =
995{ "\\"
996};
997#else
998static const char path_sep[] = { "/" };
999#endif
1000
1009string path_to_filename(string path)
1010{
1011 string::size_type pos = path.rfind(path_sep);
1012
1013 return (pos == string::npos) ? path : path.substr(++pos);
1014}
1015
1016#define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
1017#define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
1018
1019/*
1020 * globchars() - build a bitlist to check for character group match
1021 */
1022
1023static void globchars(const char *s, const char *e, char *b)
1024{
1025 int neg = 0;
1026
1027 memset(b, '\0', BITLISTSIZE);
1028
1029 if (*s == '^') neg++, s++;
1030
1031 while (s < e) {
1032 int c;
1033
1034 if (s + 2 < e && s[1] == '-') {
1035 for (c = s[0]; c <= s[2]; c++)
1036 b[c / 8] |= (1 << (c % 8));
1037 s += 3;
1038 }
1039 else {
1040 c = *s++;
1041 b[c / 8] |= (1 << (c % 8));
1042 }
1043 }
1044
1045 if (neg) {
1046 int i;
1047 for (i = 0; i < BITLISTSIZE; i++)
1048 b[i] ^= 0377;
1049 }
1050
1051 /* Don't include \0 in either $[chars] or $[^chars] */
1052
1053 b[0] &= 0376;
1054}
1055
1072int glob(const char *c, const char *s)
1073{
1074 if (!c || !s) return 1;
1075
1076 char bitlist[BITLISTSIZE];
1077 int i = 0;
1078 for (;;) {
1079 ++i;
1080 switch (*c++) {
1081 case '\0':
1082 return *s ? -1 : 0;
1083
1084 case '?':
1085 if (!*s++) return i/*1*/;
1086 break;
1087
1088 case '[': {
1089 /* scan for matching ] */
1090
1091 const char *here = c;
1092 do {
1093 if (!*c++) return i/*1*/;
1094 } while (here == c || *c != ']');
1095 c++;
1096
1097 /* build character class bitlist */
1098
1099 globchars(here, c, bitlist);
1100
1101 if (!CHECK_BIT(bitlist, *(unsigned char * )s)) return i/*1*/;
1102 s++;
1103 break;
1104 }
1105
1106 case '*': {
1107 const char *here = s;
1108
1109 while (*s)
1110 s++;
1111
1112 /* Try to match the rest of the pattern in a recursive */
1113 /* call. If the match fails we'll back up chars, retrying. */
1114
1115 while (s != here) {
1116 int r;
1117
1118 /* A fast path for the last token in a pattern */
1119
1120 r = *c ? glob(c, s) : *s ? -1 : 0;
1121
1122 if (!r)
1123 return 0;
1124 else if (r < 0) return i/*1*/;
1125
1126 --s;
1127 }
1128 break;
1129 }
1130
1131 case '\\':
1132 /* Force literal match of next char. */
1133
1134 if (!*c || *s != *c) { return i/*1*/; }
1135 else { s++; c++; }
1136 break;
1137
1138 default:
1139 if (*s++ != c[-1]) return i/*1*/;
1140 break;
1141 }
1142 }
1143}
1144
1152bool size_ok(unsigned int sz, unsigned int nelem)
1153{
1154 return (sz > 0 && nelem < UINT_MAX / sz);
1155}
1156
1173bool pathname_ok(const string &path, bool strict)
1174{
1175 if (path.length() > 255) return false;
1176
1177#if 0
1178 // Make this use a const regex 12/1/21
1179 Regex name("[-0-9A-z_./]+");
1180 if (!strict) name = "[:print:]+";
1181#endif
1182
1183 const Regex strict_name("[-0-9A-z_./]+");
1184 const Regex relaxed_name("[:print:]+");
1185
1186#if 0
1187 string::size_type len = path.length();
1188#endif
1189 unsigned long result;
1190 if (strict)
1191 result = strict_name.match(path);
1192 else
1193 result = relaxed_name.match(path);
1194
1195 return (result == path.length());
1196
1197#if 0
1198 // Protect against casting too big an uint to int
1199 // if LEN is bigger than the max int32, the second test can't work
1200
1201 // This makes no sense - len can never be > 255 given the test at the
1202 // start of this function. jhrg 12/1/21
1203 if (len > INT_MAX || result != static_cast<int>(len)) return false;
1204
1205 return true;
1206#endif
1207}
1208
1210
1216{
1217 return (string) "OPeNDAP DAP/" + libdap_version() + ": compiled on " + __DATE__ + ":" + __TIME__;
1218}
1219
1232string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix /* = "" */)
1233{
1234 vector<char> name;
1235 copy(name_template.begin(), name_template.end(), back_inserter(name));
1236 if (!suffix.empty())
1237 copy(suffix.begin(), suffix.end(), back_inserter(name));
1238 name.push_back('\0');
1239
1240 // Use mkstemp to make and open the temp file atomically
1241 int tmpfile = mkstemps(name.data(), suffix.length());
1242 if (tmpfile == -1)
1243 throw Error(internal_error, "Could not make a temporary file.");
1244 // Open the file using C++ ofstream; get a C++ fstream object
1245 f.open(name.data());
1246 // Close the file descriptor; the file stays open because of the fstream object
1247 close(tmpfile);
1248 // Now test that the fstream object is valid
1249 if (f.fail())
1250 throw Error(internal_error, "Could not make a temporary file.");
1251
1252 return string(name.data());
1253}
1254
1255
1256} // namespace libdap
1257
A multidimensional array of identical data types.
Definition: Array.h:113
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:316
virtual bool read_p()
Has this variable been read?
Definition: BaseType.cc:476
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition: BaseType.cc:389
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:361
Holds a single byte.
Definition: Byte.h:61
A class for error processing.
Definition: Error.h:94
Holds a 32-bit floating point value.
Definition: Float32.h:62
Holds a 64-bit (double precision) floating point value.
Definition: Float64.h:61
Holds a 16-bit signed integer value.
Definition: Int16.h:60
Holds a 32-bit signed integer.
Definition: Int32.h:66
Holds a64-bit signed integer.
Definition: Int64.h:50
Holds an 8-bit signed integer value.
Definition: Int8.h:43
A class for software fault reporting.
Definition: InternalErr.h:65
Regular expression matching.
Definition: GNURegex.h:57
int match(const char *s, int len, int pos=0) const
Does the pattern match.
Definition: GNURegex.cc:141
Holds character string data.
Definition: Str.h:63
Holds an unsigned 16-bit integer.
Definition: UInt16.h:58
Holds a 32-bit unsigned integer.
Definition: UInt32.h:60
Holds a 64-bit unsigned integer.
Definition: UInt64.h:50
virtual int length() const
Definition: Vector.cc:548
virtual void set_read_p(bool state)
Indicates that the data is ready to send.
Definition: Vector.cc:391
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:433
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
Type
Identifies the data type.
Definition: Type.h:94
string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix)
Definition: util.cc:1232
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:1152
string remove_quotes(const string &s)
Definition: util.cc:588
string path_to_filename(string path)
Definition: util.cc:1009
bool is_host_big_endian()
Does this host use big-endian byte order?
Definition: util.cc:94
const char * libdap_version()
Definition: util.cc:526
double extract_double_value(BaseType *arg)
Definition: util.cc:402
string prune_spaces(const string &name)
Definition: util.cc:459
string type_name(Type t)
Definition: util.cc:763
void set_array_using_double(Array *dest, double *src, int src_len)
Definition: util.cc:166
bool is_simple_type(Type t)
Returns true if the instance is a numeric, string or URL type variable.
Definition: util.cc:778
bool dir_exists(const string &dir)
Definition: util.cc:928
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:1173
void downcase(string &s)
Definition: util.cc:566
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:652
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:697
string systime()
Definition: util.cc:544
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:862
bool is_vector_type(Type t)
Returns true if the instance is a vector (i.e., array) type variable.
Definition: util.cc:818
bool is_integer_type(Type t)
Definition: util.cc:903
int glob(const char *c, const char *s)
Definition: util.cc:1072
string extract_string_argument(BaseType *arg)
Definition: util.cc:119
ObjectType get_type(const string &value)
Definition: mime_util.cc:324
double * extract_double_array(Array *a)
Definition: util.cc:261
bool is_quoted(const string &s)
Definition: util.cc:577
string dap_version()
Definition: util.cc:1215