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