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
58using namespace std;
59
60namespace libdap {
61
62static const char * months[12] =
63 {
64 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
65 };
66
67#ifndef HAVE_STRFTIME
68static 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
87static int
88strncasecomp(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
105static int
106make_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)
120static time_t
121offset_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
152time_t
153parse_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
273string 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