libdap  Updated for version 3.20.6
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 
51 using std::cerr;
52 using std::endl;
53 using std::string;
54 
55 #include "debug.h"
56 
57 namespace libdap {
58 
59 static const char * months[12] =
60  {
61  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
62  };
63 
64 #ifndef HAVE_STRFTIME
65 static 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 
83 static int
84 strncasecomp(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 
100 static int
101 make_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 
128 time_t
129 parse_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 
281 string 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
time_t parse_time(const char *str, bool expand)
Definition: util_mit.cc:129
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:281