libdap  Updated for version 3.20.11
libdap4 is an implementation of OPeNDAP's DAP protocol.
util_mit.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 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 // This file was derived from the libwww source code of 1998/08/20. The
26 // copyright for the source of this derivative work can be found in the file
27 // COPYRIGHT_W3C.
28 
29 
30 #include "config.h"
31 
32 #include <cstdio>
33 #include <cstring>
34 #include <cstdlib>
35 #include <ctype.h>
36 
37 #ifndef TM_IN_SYS_TIME
38 #include <time.h>
39 #else
40 #include <sys/time.h>
41 #endif
42 
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 
46 #include <string>
47 #include <iostream>
48 #include <iomanip>
49 #include <sstream>
50 
51 #include "util_mit.h"
52 
53 #include "debug.h"
54 
55 #define _REENTRANT 1
56 #define MAX_TIME_STR_LEN 40 // one larger than the max rfc850 strlen. jhrg 3/7/22
57 
58 using namespace std;
59 
60 namespace libdap {
61 
62 static const char * months[12] =
63  {
64  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
65  };
66 
67 #ifndef HAVE_STRFTIME
68 static const char * wkdays[7] =
69  {
70  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
71  };
72 #endif
73 
74 /* Upper- and Lowercase macros
75 
76  The problem here is that toupper(x) is not defined officially unless
77  isupper(x) is. These macros are CERTAINLY needed on #if defined(pyr) ||
78  define(mips) or BDSI platforms. For safety, we make them mandatory.
79 */
80 
81 #ifndef TOLOWER
82 #define TOLOWER(c) tolower((int) (c))
83 #define TOUPPER(c) toupper((int) (c))
84 #endif
85 
86 #if 0
87 static int
88 strncasecomp(const char *a, const char *b, int n)
89 {
90  const char *p = a;
91  const char *q = b;
92 
93  for (p = a, q = b;; p++, q++) {
94  int diff;
95  if (p == a + n) return 0; /* Match up to n characters */
96  if (!(*p && *q)) return *p - *q;
97  diff = TOLOWER(*p) - TOLOWER(*q);
98  if (diff) return diff;
99  }
100  /*NOTREACHED*/
101  return -1; // silence gcc
102 }
103 #endif
104 
105 static int
106 make_month(char * s, char ** ends)
107 {
108  char * ptr = s;
109  while (!isalpha((int) *ptr)) ptr++;
110  if (*ptr) {
111  int i;
112  *ends = ptr + 3;
113  for (i = 0; i < 12; i++)
114  if (!strncasecmp(months[i], ptr, 3)) return i;
115  }
116  return 0;
117 }
118 
119 #if !defined(HAVE_TIMEGM) && defined(HAVE_MKTIME)
120 static time_t
121 offset_from_utc()
122 {
123  // Compute offset between localtime and GMT.
124  time_t offset;
125  time_t now = time(0);
126 #ifdef _REENTRANT
127  struct tm gmt, local;
128  offset = mktime(gmtime_r(&now, &gmt)) - mktime(localtime_r(&now, &local));
129 #else
130  offset = mktime(gmtime(&now)) - mktime(localtime(&now));
131 #endif // _REENTRANT
132  return offset;
133 }
134 #endif
135 
152 time_t
153 parse_time(const char * str, bool expand)
154 {
155  char * s;
156  struct tm tm;
157  time_t t;
158 
159  if (!str) return 0;
160 
161  if ((s = (char *)strchr(str, ','))) { /* Thursday, 10-Jun-93 01:29:59 GMT */
162  s++; /* or: Thu, 10 Jan 1993 01:29:59 GMT */
163  while (*s && *s == ' ') s++;
164  if (strchr(s, '-')) { /* First format */
165  DBG(cerr << "Format...... Weekday, 00-Mon-00 00:00:00 GMT" << endl);
166  if ((int)strnlen(s, MAX_TIME_STR_LEN) < 18) {
167  DBG(cerr << "ERROR....... Not a valid time format \"" << s << "\"" << endl);
168  return 0;
169  }
170  tm.tm_mday = strtol(s, &s, 10);
171  tm.tm_mon = make_month(s, &s);
172  ++s;
173  tm.tm_year = strtol(s, &s, 10);
174  tm.tm_hour = strtol(s, &s, 10);
175  ++s;
176  tm.tm_min = strtol(s, &s, 10);
177  ++s;
178  tm.tm_sec = strtol(s, &s, 10);
179  }
180  else { /* Second format */
181  DBG(cerr << "Format...... Wkd, 00 Mon 0000 00:00:00 GMT" << endl);
182  if ((int)strnlen(s, MAX_TIME_STR_LEN) < 20) {
183  DBG(cerr << "ERROR....... Not a valid time format \""
184  << s << "\"" << endl);
185  return 0;
186  }
187  tm.tm_mday = strtol(s, &s, 10);
188  tm.tm_mon = make_month(s, &s);
189  tm.tm_year = strtol(s, &s, 10) - 1900;
190  tm.tm_hour = strtol(s, &s, 10);
191  ++s;
192  tm.tm_min = strtol(s, &s, 10);
193  ++s;
194  tm.tm_sec = strtol(s, &s, 10);
195  }
196  }
197  else if (isdigit((int) *str)) {
198  if (strchr(str, 'T')) { /* ISO (limited format) date string */
199  DBG(cerr << "Format...... YYYY.MM.DDThh:mmStzWkd" << endl);
200  s = (char *) str;
201  while (*s && *s == ' ') s++;
202  if ((int)strnlen(s, MAX_TIME_STR_LEN) < 21) {
203  DBG(cerr << "ERROR....... Not a valid time format \"" << s << "\"" << endl);
204  return 0;
205  }
206  tm.tm_year = strtol(s, &s, 10) - 1900;
207  ++s;
208  tm.tm_mon = strtol(s, &s, 10); tm.tm_mon--; // tm_mon is zero-based
209  ++s;
210  tm.tm_mday = strtol(s, &s, 10);
211  ++s;
212  tm.tm_hour = strtol(s, &s, 10);
213  ++s;
214  tm.tm_min = strtol(s, &s, 10);
215  ++s;
216  tm.tm_sec = strtol(s, &s, 10);
217  }
218  else { /* delta seconds */
219  t = expand ? time(NULL) + atol(str) : atol(str);
220  return t;
221  }
222  }
223  else { /* Try the other format: Wed Jun 9 01:29:59 1993 GMT */
224  DBG(cerr << "Format...... Wkd Mon 00 00:00:00 0000 GMT" << endl);
225  s = (char *) str;
226  while (*s && *s == ' ') s++;
227  DBG(cerr << "Trying...... The Wrong time format: " << s << endl);
228  if ((int)strnlen(s, MAX_TIME_STR_LEN) < 24) {
229  DBG(cerr << "ERROR....... Not a valid time format \"" << s << "\"" << endl);
230  return 0;
231  }
232  tm.tm_mon = make_month(s, &s);
233  tm.tm_mday = strtol(s, &s, 10);
234  tm.tm_hour = strtol(s, &s, 10);
235  ++s;
236  tm.tm_min = strtol(s, &s, 10);
237  ++s;
238  tm.tm_sec = strtol(s, &s, 10);
239  tm.tm_year = strtol(s, &s, 10) - 1900;
240  }
241 
242  if (tm.tm_sec < 0 || tm.tm_sec > 59 ||
243  tm.tm_min < 0 || tm.tm_min > 59 ||
244  tm.tm_hour < 0 || tm.tm_hour > 23 ||
245  tm.tm_mday < 1 || tm.tm_mday > 31 ||
246  tm.tm_mon < 0 || tm.tm_mon > 11 ||
247  tm.tm_year < 70 || tm.tm_year > 138) { // Unix time will break iin 2038
248  DBG(cerr << "ERROR....... Parsed illegal time" << endl);
249  return 0;
250  }
251 
252  /* Let mktime decide whether we have DST or not */
253  tm.tm_isdst = -1;
254 
255 #if defined(HAVE_TIMEGM)
256  return timegm(&tm);
257 #elif defined(HAVE_MKTIME)
258  return mktime(&tm) + offset_from_utc();
259 #else
260 #error "Neither mktime nor timegm defined"
261 #endif // HAVE_TIMEGM OR HAVE_MKTIME
262 }
263 
273 string date_time_str(time_t *calendar, bool local)
274 {
275  if (!calendar) return "";
276 
277  char buf[MAX_TIME_STR_LEN];
278 
279 #ifdef HAVE_STRFTIME
280  if (local) {
281 #if defined(_REENTRANT) || defined(SOLARIS)
282  struct tm loctime;
283  localtime_r(calendar, &loctime);
284  strftime(buf, MAX_TIME_STR_LEN, "%a, %d %b %Y %H:%M:%S", &loctime);
285 #else
286  struct tm *loctime = localtime(calendar);
287  strftime(buf, MAX_TIME_STR_LEN, "%a, %d %b %Y %H:%M:%S", loctime);
288 #endif /* SOLARIS || _REENTRANT */
289  }
290  else {
291 #if defined(_REENTRANT) || defined(SOLARIS)
292  struct tm gmt;
293  gmtime_r(calendar, &gmt);
294  strftime(buf, MAX_TIME_STR_LEN, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
295 #else
296  struct tm *gmt = gmtime(calendar);
297  strftime(buf, MAX_TIME_STR_LEN, "%a, %d %b %Y %H:%M:%S GMT", gmt);
298 #endif /* SOLARIS || _REENTRANT */
299  }
300 
301 #else /* !HAVE_STRFTIME */
302 
303  if (local) {
304 #if defined(_REENTRANT)
305  struct tm loctime;
306  localtime_r(calendar, &loctime);
307  snprintf(buf, MAX_TIME_STR_LEN, "%s, %02d %s %04d %02d:%02d:%02d",
308  wkdays[loctime.tm_wday],
309  loctime.tm_mday,
310  months[loctime.tm_mon],
311  loctime.tm_year + 1900,
312  loctime.tm_hour,
313  loctime.tm_min,
314  loctime.tm_sec);
315 #else
316  struct tm *loctime = localtime(calendar);
317  if (!loctime)
318  return "";
319  snprintf(buf, MAX_TIME_STR_LEN, "%s, %02d %s %04d %02d:%02d:%02d",
320  wkdays[loctime->tm_wday],
321  loctime->tm_mday,
322  months[loctime->tm_mon],
323  loctime->tm_year + 1900,
324  loctime->tm_hour,
325  loctime->tm_min,
326  loctime->tm_sec);
327 #endif /* _REENTRANT */
328  }
329  else {
330 #if defined(_REENTRANT) || defined(SOLARIS)
331  struct tm gmt;
332  gmtime_r(calendar, &gmt);
333  snprintf(buf, MAX_TIME_STR_LEN, "%s, %02d %s %04d %02d:%02d:%02d GMT",
334  wkdays[gmt.tm_wday],
335  gmt.tm_mday,
336  months[gmt.tm_mon],
337  gmt.tm_year + 1900,
338  gmt.tm_hour,
339  gmt.tm_min,
340  gmt.tm_sec);
341 #else
342  struct tm *gmt = gmtime(calendar);
343  if (!gmt)
344  return "";
345  snprintf(buf, MAX_TIME_STR_LEN, "%s, %02d %s %04d %02d:%02d:%02d GMT",
346  wkdays[gmt->tm_wday],
347  gmt->tm_mday,
348  months[gmt->tm_mon],
349  gmt->tm_year + 1900,
350  gmt->tm_hour,
351  gmt->tm_min,
352  gmt->tm_sec);
353 #endif // defined(_REENTRANT) || defined(SOLARIS)
354  }
355 #endif
356  return string(buf);
357 }
358 
359 } // namespace libdap
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
string date_time_str(time_t *calendar, bool local)
Definition: util_mit.cc:273
time_t parse_time(const char *str, bool expand)
Definition: util_mit.cc:153