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