libdap  Updated for version 3.18.2
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 
88 using namespace std;
89 
90 namespace 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 
131 template<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 
165 void 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 
234 template<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!
314 template<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 
342 void extract_double_array(Array *a, vector<double> &dest)
343 {
344  assert(a);
345 
346  // Simple types are Byte, ..., Float64, String and Url.
347  if ((a->type() == dods_array_c && !a->var()->is_simple_type()) || a->var()->type() == dods_str_c
348  || a->var()->type() == dods_url_c)
349  throw Error(malformed_expr, "The function requires a DAP numeric-type array argument.");
350 
351  if (!a->read_p())
352  throw InternalErr(__FILE__, __LINE__, string("The Array '") + a->name() + "' does not contain values.");
353 
354  dest.resize(a->length());
355 
356  // The types of arguments that the CE Parser will build for numeric
357  // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
358  // Expanded to work for any numeric type so it can be used for more than
359  // just arguments.
360  switch (a->var()->type()) {
361  case dods_byte_c:
362  return extract_double_array_helper<dods_byte>(a, dest);
363  case dods_uint16_c:
364  return extract_double_array_helper<dods_uint16>(a, dest);
365  case dods_int16_c:
366  return extract_double_array_helper<dods_int16>(a, dest);
367  case dods_uint32_c:
368  return extract_double_array_helper<dods_uint32>(a, dest);
369  case dods_int32_c:
370  return extract_double_array_helper<dods_int32>(a, dest);
371  case dods_float32_c:
372  return extract_double_array_helper<dods_float32>(a, dest);
373  case dods_float64_c:
374  return a->value(&dest[0]); // no need to copy the values
375  // return extract_double_array_helper<dods_float64>(a, dest);
376 
377  // Support for DAP4
378  case dods_uint8_c:
379  return extract_double_array_helper<dods_byte>(a, dest);
380  case dods_int8_c:
381  return extract_double_array_helper<dods_int8>(a, dest);
382  case dods_uint64_c:
383  return extract_double_array_helper<dods_uint64>(a, dest);
384  case dods_int64_c:
385  return extract_double_array_helper<dods_int64>(a, dest);
386  default:
387  throw InternalErr(__FILE__, __LINE__,
388  "The argument list built by the CE parser contained an unsupported numeric type.");
389  }
390 }
391 
402 {
403  assert(arg);
404 
405  // Simple types are Byte, ..., Float64, String and Url.
406  if (!arg->is_simple_type() || arg->type() == dods_str_c || arg->type() == dods_url_c)
407  throw Error(malformed_expr, "The function requires a numeric-type argument.");
408 
409  if (!arg->read_p())
410  throw InternalErr(__FILE__, __LINE__,
411  "The Evaluator built an argument list where some constants held no values.");
412 
413  // The types of arguments that the CE Parser will build for numeric
414  // constants are limited to Uint32, Int32 and Float64. See ce_expr.y.
415  // Expanded to work for any numeric type so it can be used for more than
416  // just arguments.
417  switch (arg->type()) {
418  case dods_byte_c:
419  return (double) (static_cast<Byte*>(arg)->value());
420  case dods_uint16_c:
421  return (double) (static_cast<UInt16*>(arg)->value());
422  case dods_int16_c:
423  return (double) (static_cast<Int16*>(arg)->value());
424  case dods_uint32_c:
425  return (double) (static_cast<UInt32*>(arg)->value());
426  case dods_int32_c:
427  return (double) (static_cast<Int32*>(arg)->value());
428  case dods_float32_c:
429  return (double) (static_cast<Float32*>(arg)->value());
430  case dods_float64_c:
431  return static_cast<Float64*>(arg)->value();
432 
433  // Support for DAP4 types.
434  case dods_uint8_c:
435  return (double) (static_cast<Byte*>(arg)->value());
436  case dods_int8_c:
437  return (double) (static_cast<Int8*>(arg)->value());
438  case dods_uint64_c:
439  return (double) (static_cast<UInt64*>(arg)->value());
440  case dods_int64_c:
441  return (double) (static_cast<Int64*>(arg)->value());
442 
443  default:
444  throw InternalErr(__FILE__, __LINE__,
445  "The argument list built by the parser contained an unsupported numeric type.");
446  }
447 }
448 
449 // Remove spaces from the start of a URL and from the start of any constraint
450 // expression it contains. 4/7/98 jhrg
451 
458 string prune_spaces(const string &name)
459 {
460  // If the URL does not even have white space return.
461  if (name.find_first_of(' ') == name.npos)
462  return name;
463  else {
464  // Strip leading spaces from http://...
465  unsigned int i = name.find_first_not_of(' ');
466  string tmp_name = name.substr(i);
467 
468  // Strip leading spaces from constraint part (following `?').
469  unsigned int j = tmp_name.find('?') + 1;
470  i = tmp_name.find_first_not_of(' ', j);
471  tmp_name.erase(j, i - j);
472 
473  return tmp_name;
474  }
475 }
476 
477 // Compare elements in a list of (BaseType *)s and return true if there are
478 // no duplicate elements, otherwise return false.
479 
480 bool unique_names(vector<BaseType *> l, const string &var_name, const string &type_name, string &msg)
481 {
482  // copy the identifier names to a vector
483  vector<string> names(l.size());
484 
485  int nelem = 0;
486  typedef std::vector<BaseType *>::const_iterator citer;
487  for (citer i = l.begin(); i != l.end(); i++) {
488  assert(*i);
489  names[nelem++] = (*i)->name();
490  DBG(cerr << "NAMES[" << nelem - 1 << "]=" << names[nelem-1] << endl);
491  }
492 
493  // sort the array of names
494  sort(names.begin(), names.end());
495 
496  // sort the array of names
497  sort(names.begin(), names.end());
498 
499  // look for any instance of consecutive names that are ==
500  for (int j = 1; j < nelem; ++j) {
501  if (names[j - 1] == names[j]) {
502  ostringstream oss;
503  oss << "The variable `" << names[j] << "' is used more than once in " << type_name << " `" << var_name
504  << "'";
505  msg = oss.str();
506 
507  return false;
508  }
509  }
510 
511  return true;
512 }
513 
514 const char *
515 libdap_root()
516 {
517  return LIBDAP_ROOT;
518 }
519 
524 extern "C" const char *
526 {
527  return PACKAGE_VERSION;
528 }
529 
530 extern "C" const char *
531 libdap_name()
532 {
533  return PACKAGE_NAME;
534 }
535 
541 string systime()
542 {
543  time_t TimBin;
544 
545  if (time(&TimBin) == (time_t) -1)
546  return string("time() error");
547  else {
548  char *ctime_value = ctime(&TimBin);
549  if (ctime_value) {
550  string TimStr = ctime_value;
551  return TimStr.substr(0, TimStr.size() - 2); // remove the \n
552  }
553  else
554  return "Unknown";
555  }
556 }
557 
562 void downcase(string &s)
563 {
564  for (unsigned int i = 0; i < s.length(); i++)
565  s[i] = tolower(s[i]);
566 }
567 
573 bool is_quoted(const string &s)
574 {
575  return (!s.empty() && s[0] == '\"' && s[s.length() - 1] == '\"');
576 }
577 
584 string remove_quotes(const string &s)
585 {
586  if (is_quoted(s))
587  return s.substr(1, s.length() - 2);
588  else
589  return s;
590 }
591 
593 Type get_type(const char *name)
594 {
595  if (strcmp(name, "Byte") == 0) return dods_byte_c;
596 
597  if (strcmp(name, "Char") == 0) return dods_char_c;
598 
599  if (strcmp(name, "Int8") == 0) return dods_int8_c;
600 
601  if (strcmp(name, "UInt8") == 0) return dods_uint8_c;
602 
603  if (strcmp(name, "Int16") == 0) return dods_int16_c;
604 
605  if (strcmp(name, "UInt16") == 0) return dods_uint16_c;
606 
607  if (strcmp(name, "Int32") == 0) return dods_int32_c;
608 
609  if (strcmp(name, "UInt32") == 0) return dods_uint32_c;
610 
611  if (strcmp(name, "Int64") == 0) return dods_int64_c;
612 
613  if (strcmp(name, "UInt64") == 0) return dods_uint64_c;
614 
615  if (strcmp(name, "Float32") == 0) return dods_float32_c;
616 
617  if (strcmp(name, "Float64") == 0) return dods_float64_c;
618 
619  if (strcmp(name, "String") == 0) return dods_str_c;
620 
621  // accept both spellings; this might be confusing since URL
622  // could be filtered through code and come out Url. Don't know...
623  // jhrg 8/15/13
624  if (strcmp(name, "Url") == 0 || strcmp(name, "URL") == 0) return dods_url_c;
625 
626  if (strcmp(name, "Enum") == 0) return dods_enum_c;
627 
628  if (strcmp(name, "Opaque") == 0) return dods_opaque_c;
629 
630  if (strcmp(name, "Array") == 0) return dods_array_c;
631 
632  if (strcmp(name, "Structure") == 0) return dods_structure_c;
633 
634  if (strcmp(name, "Sequence") == 0) return dods_sequence_c;
635 
636  if (strcmp(name, "Grid") == 0) return dods_grid_c;
637 
638  return dods_null_c;
639 }
640 
648 string D2type_name(Type t)
649 {
650  switch (t) {
651  case dods_null_c:
652  return string("Null");
653  case dods_byte_c:
654  return string("Byte");
655  case dods_int16_c:
656  return string("Int16");
657  case dods_uint16_c:
658  return string("UInt16");
659  case dods_int32_c:
660  return string("Int32");
661  case dods_uint32_c:
662  return string("UInt32");
663  case dods_float32_c:
664  return string("Float32");
665  case dods_float64_c:
666  return string("Float64");
667  case dods_str_c:
668  return string("String");
669  case dods_url_c:
670  return string("Url");
671 
672  case dods_array_c:
673  return string("Array");
674  case dods_structure_c:
675  return string("Structure");
676  case dods_sequence_c:
677  return string("Sequence");
678  case dods_grid_c:
679  return string("Grid");
680 
681  default:
682  throw InternalErr(__FILE__, __LINE__, "Unknown type.");
683  }
684 }
685 
693 string D4type_name(Type t)
694 {
695  switch (t) {
696  case dods_null_c:
697  return string("Null");
698  case dods_byte_c:
699  return string("Byte");
700  case dods_char_c:
701  return string("Char");
702  case dods_int8_c:
703  return string("Int8");
704  case dods_uint8_c:
705  return string("UInt8");
706  case dods_int16_c:
707  return string("Int16");
708  case dods_uint16_c:
709  return string("UInt16");
710  case dods_int32_c:
711  return string("Int32");
712  case dods_uint32_c:
713  return string("UInt32");
714  case dods_int64_c:
715  return string("Int64");
716  case dods_uint64_c:
717  return string("UInt64");
718  case dods_enum_c:
719  return string("Enum");
720 
721  case dods_float32_c:
722  return string("Float32");
723  case dods_float64_c:
724  return string("Float64");
725 
726  case dods_str_c:
727  return string("String");
728  case dods_url_c:
729  return string("URL");
730 
731  case dods_opaque_c:
732  return string("Opaque");
733 
734  case dods_array_c:
735  return string("Array");
736 
737  case dods_structure_c:
738  return string("Structure");
739  case dods_sequence_c:
740  return string("Sequence");
741  case dods_group_c:
742  return string("Group");
743 
744  default:
745  throw InternalErr(__FILE__, __LINE__, "Unknown type.");
746  }
747 }
748 
759 string type_name(Type t)
760 {
761  try {
762  return D4type_name(t);
763  }
764  catch (...) {
765  return D2type_name(t);
766  }
767 }
768 
775 {
776  switch (t) {
777 
778  case dods_byte_c:
779  case dods_char_c:
780 
781  case dods_int8_c:
782  case dods_uint8_c:
783 
784  case dods_int16_c:
785  case dods_uint16_c:
786  case dods_int32_c:
787  case dods_uint32_c:
788 
789  case dods_int64_c:
790  case dods_uint64_c:
791 
792  case dods_float32_c:
793  case dods_float64_c:
794  case dods_str_c:
795  case dods_url_c:
796  case dods_enum_c:
797  case dods_opaque_c:
798  return true;
799 
800  case dods_null_c:
801  case dods_array_c:
802  case dods_structure_c:
803  case dods_sequence_c:
804  case dods_grid_c:
805  case dods_group_c:
806  default:
807  return false;
808  }
809 
810  return false;
811 }
812 
817 {
818  switch (t) {
819  case dods_null_c:
820  case dods_byte_c:
821  case dods_char_c:
822 
823  case dods_int8_c:
824  case dods_uint8_c:
825 
826  case dods_int16_c:
827  case dods_uint16_c:
828 
829  case dods_int32_c:
830  case dods_uint32_c:
831 
832  case dods_int64_c:
833  case dods_uint64_c:
834 
835  case dods_float32_c:
836  case dods_float64_c:
837 
838  case dods_str_c:
839  case dods_url_c:
840  case dods_enum_c:
841  case dods_opaque_c:
842  return false;
843 
844  case dods_array_c:
845  return true;
846 
847  case dods_structure_c:
848  case dods_sequence_c:
849  case dods_grid_c:
850  case dods_group_c:
851  default:
852  return false;
853  }
854 
855  return false;
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  return false;
899 }
900 
906 {
907  switch (t) {
908  case dods_byte_c:
909  case dods_char_c:
910  case dods_int8_c:
911  case dods_uint8_c:
912  case dods_int16_c:
913  case dods_uint16_c:
914  case dods_int32_c:
915  case dods_uint32_c:
916  case dods_int64_c:
917  case dods_uint64_c:
918  return true;
919  default:
920  return false;
921  }
922 }
923 
930 bool dir_exists(const string &dir)
931 {
932  struct stat buf;
933 
934  return (stat(dir.c_str(), &buf) == 0) && (buf.st_mode & S_IFDIR);
935 }
936 
937 // Jose Garcia
938 void append_long_to_string(long val, int base, string &str_val)
939 {
940  // The array digits contains 36 elements which are the
941  // posible valid digits for out bases in the range
942  // [2,36]
943  char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
944  // result of val / base
945  ldiv_t r;
946 
947  if (base > 36 || base < 2) {
948  // no conversion if wrong base
949  std::invalid_argument ex("The parameter base has an invalid value.");
950  throw ex;
951  }
952  if (val < 0) str_val += '-';
953  r = ldiv(labs(val), base);
954 
955  // output digits of val/base first
956  if (r.quot > 0) append_long_to_string(r.quot, base, str_val);
957 
958  // output last digit
959 
960  str_val += digits[(int) r.rem];
961 }
962 
963 // base defaults to 10
964 string long_to_string(long val, int base)
965 {
966  string s;
967  append_long_to_string(val, base, s);
968  return s;
969 }
970 
971 // Jose Garcia
972 void append_double_to_string(const double &num, string &str)
973 {
974  // s having 100 characters should be enough for sprintf to do its job.
975  // I want to banish all instances of sprintf. 10/5/2001 jhrg
976  ostringstream oss;
977  oss.precision(9);
978  oss << num;
979  str += oss.str();
980 }
981 
982 string double_to_string(const double &num)
983 {
984  string s;
985  append_double_to_string(num, s);
986  return s;
987 }
988 
989 // Given a pathname, return the file at the end of the path. This is used
990 // when reporting errors (maybe other times, too) to keep the server from
991 // revealing too much about its organization when sending error responses
992 // back to clients. 10/11/2000 jhrg
993 // MT-safe. 08/05/02 jhrg
994 
995 #ifdef WIN32
996 static const char path_sep[] =
997 { "\\"
998 };
999 #else
1000 static const char path_sep[] = { "/" };
1001 #endif
1002 
1011 string path_to_filename(string path)
1012 {
1013  string::size_type pos = path.rfind(path_sep);
1014 
1015  return (pos == string::npos) ? path : path.substr(++pos);
1016 }
1017 
1018 #define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
1019 #define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
1020 
1021 /*
1022  * globchars() - build a bitlist to check for character group match
1023  */
1024 
1025 static void globchars(const char *s, const char *e, char *b)
1026 {
1027  int neg = 0;
1028 
1029  memset(b, '\0', BITLISTSIZE);
1030 
1031  if (*s == '^') neg++, s++;
1032 
1033  while (s < e) {
1034  int c;
1035 
1036  if (s + 2 < e && s[1] == '-') {
1037  for (c = s[0]; c <= s[2]; c++)
1038  b[c / 8] |= (1 << (c % 8));
1039  s += 3;
1040  }
1041  else {
1042  c = *s++;
1043  b[c / 8] |= (1 << (c % 8));
1044  }
1045  }
1046 
1047  if (neg) {
1048  int i;
1049  for (i = 0; i < BITLISTSIZE; i++)
1050  b[i] ^= 0377;
1051  }
1052 
1053  /* Don't include \0 in either $[chars] or $[^chars] */
1054 
1055  b[0] &= 0376;
1056 }
1057 
1074 int glob(const char *c, const char *s)
1075 {
1076  if (!c || !s) return 1;
1077 
1078  char bitlist[BITLISTSIZE];
1079  int i = 0;
1080  for (;;) {
1081  ++i;
1082  switch (*c++) {
1083  case '\0':
1084  return *s ? -1 : 0;
1085 
1086  case '?':
1087  if (!*s++) return i/*1*/;
1088  break;
1089 
1090  case '[': {
1091  /* scan for matching ] */
1092 
1093  const char *here = c;
1094  do {
1095  if (!*c++) return i/*1*/;
1096  } while (here == c || *c != ']');
1097  c++;
1098 
1099  /* build character class bitlist */
1100 
1101  globchars(here, c, bitlist);
1102 
1103  if (!CHECK_BIT(bitlist, *(unsigned char * )s)) return i/*1*/;
1104  s++;
1105  break;
1106  }
1107 
1108  case '*': {
1109  const char *here = s;
1110 
1111  while (*s)
1112  s++;
1113 
1114  /* Try to match the rest of the pattern in a recursive */
1115  /* call. If the match fails we'll back up chars, retrying. */
1116 
1117  while (s != here) {
1118  int r;
1119 
1120  /* A fast path for the last token in a pattern */
1121 
1122  r = *c ? glob(c, s) : *s ? -1 : 0;
1123 
1124  if (!r)
1125  return 0;
1126  else if (r < 0) return i/*1*/;
1127 
1128  --s;
1129  }
1130  break;
1131  }
1132 
1133  case '\\':
1134  /* Force literal match of next char. */
1135 
1136  if (!*c || *s++ != *c++) return i/*1*/;
1137  break;
1138 
1139  default:
1140  if (*s++ != c[-1]) return i/*1*/;
1141  break;
1142  }
1143  }
1144 
1145  return 1; // Should never get here; this quiets gcc's warning
1146 }
1147 
1155 bool size_ok(unsigned int sz, unsigned int nelem)
1156 {
1157  return (sz > 0 && nelem < UINT_MAX / sz);
1158 }
1159 
1176 bool pathname_ok(const string &path, bool strict)
1177 {
1178  if (path.length() > 255) return false;
1179 
1180  Regex name("[-0-9A-z_./]+");
1181  if (!strict) name = "[:print:]+";
1182 
1183  string::size_type len = path.length();
1184  int result = name.match(path.c_str(), len);
1185  // Protect against casting too big an uint to int
1186  // if LEN is bigger than the max int32, the second test can't work
1187  if (len > INT_MAX || result != static_cast<int>(len)) return false;
1188 
1189  return true;
1190 }
1191 
1193 
1198 string dap_version()
1199 {
1200  return (string) "OPeNDAP DAP/" + libdap_version() + ": compiled on " + __DATE__ + ":" + __TIME__;
1201 }
1202 
1215 string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix /* = "" */)
1216 {
1217  vector<char> name;
1218  copy(name_template.begin(), name_template.end(), back_inserter(name));
1219  if (!suffix.empty())
1220  copy(suffix.begin(), suffix.end(), back_inserter(name));
1221  name.push_back('\0');
1222 
1223  // Use mkstemp to make and open the temp file atomically
1224  int tmpfile = mkstemps(&name[0], suffix.length());
1225  if (tmpfile == -1)
1226  throw Error(internal_error, "Could not make a temporary file.");
1227  // Open the file using C++ ofstream; get a C++ fstream object
1228  f.open(&name[0]);
1229  // Close the file descriptor; the file stays open because of the fstream object
1230  close(tmpfile);
1231  // Now test that the fstream object is valid
1232  if (f.fail())
1233  throw Error(internal_error, "Could not make a temporary file.");
1234 
1235  return string(&name[0]);
1236 }
1237 
1238 
1239 } // namespace libdap
1240 
Holds an 8-bit signed integer value.
Definition: Int8.h:42
Holds a64-bit signed integer.
Definition: Int64.h:49
virtual bool read_p()
Has this variable been read?
Definition: BaseType.cc:425
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:265
void downcase(string &s)
Definition: util.cc:562
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
string prune_spaces(const string &name)
Definition: util.cc:458
string open_temp_fstream(ofstream &f, const string &name_template, const string &suffix)
Definition: util.cc:1215
Holds an unsigned 16-bit integer.
Definition: UInt16.h:57
virtual void set_read_p(bool state)
Indicates that the data is ready to send.
Definition: Vector.cc:392
string extract_string_argument(BaseType *arg)
Definition: util.cc:118
bool dir_exists(const string &dir)
Definition: util.cc:930
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:1155
STL namespace.
bool is_vector_type(Type t)
Returns true if the instance is a vector (i.e., array) type variable.
Definition: util.cc:816
virtual bool is_simple_type() const
Returns true if the instance is a numeric, string or URL type variable.
Definition: BaseType.cc:338
Type
Identifies the data type.
Definition: Type.h:94
Holds a 32-bit floating point value.
Definition: Float32.h:61
A class for software fault reporting.
Definition: InternalErr.h:64
int match(const char *s, int len, int pos=0)
Does the pattern match.
Definition: GNURegex.cc:115
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:434
Holds character string data.
Definition: Str.h:62
void set_array_using_double(Array *dest, double *src, int src_len)
Definition: util.cc:165
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:1176
double * extract_double_array(Array *a)
Definition: util.cc:260
Holds a 16-bit signed integer value.
Definition: Int16.h:59
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:310
ObjectType get_type(const string &value)
Definition: mime_util.cc:326
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:693
string path_to_filename(string path)
Definition: util.cc:1011
bool is_quoted(const string &s)
Definition: util.cc:573
bool is_simple_type(Type t)
Returns true if the instance is a numeric, string or URL type variable.
Definition: util.cc:774
string systime()
Definition: util.cc:541
Holds a 64-bit unsigned integer.
Definition: UInt64.h:49
double extract_double_value(BaseType *arg)
Definition: util.cc:401
string dap_version()
Definition: util.cc:1198
string remove_quotes(const string &s)
Definition: util.cc:584
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
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:648
Holds a 64-bit (double precision) floating point value.
Definition: Float64.h:60
virtual int length() const
Definition: Vector.cc:557
Holds a single byte.
Definition: Byte.h:60
A class for error processing.
Definition: Error.h:90
bool is_host_big_endian()
Does this host use big-endian byte order?
Definition: util.cc:93
Holds a 32-bit unsigned integer.
Definition: UInt32.h:59
string type_name(Type t)
Definition: util.cc:759
const char * libdap_version()
Definition: util.cc:525
A multidimensional array of identical data types.
Definition: Array.h:112
int glob(const char *c, const char *s)
Definition: util.cc:1074
bool is_integer_type(Type t)
Definition: util.cc:905
Holds a 32-bit signed integer.
Definition: Int32.h:65