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