libdap  Updated for version 3.20.10
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 
89 using namespace std;
90 
91 namespace 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 
132 template<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 
166 void 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 
235 template<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!
315 template<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 
343 void 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 
459 string 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 
481 bool 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 
515 const char *
516 libdap_root()
517 {
518  return LIBDAP_ROOT;
519 }
520 
525 extern "C" const char *
527 {
528  // return PACKAGE_VERSION;
529  // Switched to CVER which is <version>-<build_number>
530  return CVER;
531 }
532 
533 extern "C" const char *
534 libdap_name()
535 {
536  return PACKAGE_NAME;
537 }
538 
544 string 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 
566 void downcase(string &s)
567 {
568  for (unsigned int i = 0; i < s.length(); i++)
569  s[i] = tolower(s[i]);
570 }
571 
577 bool is_quoted(const string &s)
578 {
579  return (!s.empty() && s[0] == '\"' && s[s.length() - 1] == '\"');
580 }
581 
588 string 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 
597 Type 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 
652 string D2type_name(Type t)
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 
697 string D4type_name(Type t)
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 
763 string type_name(Type t)
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 
928 bool 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
936 void 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
962 string 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
970 void 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 
980 string 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
994 static const char path_sep[] =
995 { "\\"
996 };
997 #else
998 static const char path_sep[] = { "/" };
999 #endif
1000 
1009 string 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 
1023 static 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 
1072 int 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 
1152 bool size_ok(unsigned int sz, unsigned int nelem)
1153 {
1154  return (sz > 0 && nelem < UINT_MAX / sz);
1155 }
1156 
1173 bool 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 
1215 string dap_version()
1216 {
1217  return (string) "OPeNDAP DAP/" + libdap_version() + ": compiled on " + __DATE__ + ":" + __TIME__;
1218 }
1219 
1232 string 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