* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
20040911 +0200
*/
-#include "setup.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* for strtol() */
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
#endif
#include <curl/curl.h>
int offset; /* +/- in minutes */
};
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK - a fine conversion
+ * PARSEDATE_FAIL - failed to convert
+ * PARSEDATE_LATER - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output);
+
+#define PARSEDATE_OK 0
+#define PARSEDATE_FAIL -1
+#define PARSEDATE_LATER 1
+#define PARSEDATE_SOONER 2
+
/* Here's a bunch of frequently used time zone names. These were supported
by the old getdate parser. */
#define tDAYZONE -60 /* offset for daylight savings time */
{"G", +7 * 60}, /* Golf */
{"H", +8 * 60}, /* Hotel */
{"I", +9 * 60}, /* India */
- /* "J", Juliet is not used as a timezone, to indicate the observer's local time */
+ /* "J", Juliet is not used as a timezone, to indicate the observer's local
+ time */
{"K", +10 * 60}, /* Kilo */
{"L", +11 * 60}, /* Lima */
{"M", +12 * 60}, /* Mike */
year = tm->tm_year + 1900;
month = tm->tm_mon;
- if (month < 0) {
+ if(month < 0) {
year += (11 - month) / 12;
month = 11 - (11 - month) % 12;
}
- else if (month >= 12) {
+ else if(month >= 12) {
year -= month / 12;
month = month % 12;
}
}
/*
- * Curl_parsedate()
+ * parsedate()
*
* Returns:
*
* PARSEDATE_SOONER - time underflow at the low end of time_t
*/
-int Curl_parsedate(const char *date, time_t *output)
+static int parsedate(const char *date, time_t *output)
{
time_t t = 0;
int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */
/* a name coming up */
char buf[32]="";
size_t len;
- sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
- buf);
- len = strlen(buf);
+ if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz]", buf))
+ len = strlen(buf);
+ else
+ len = 0;
if(wdaynum == -1) {
wdaynum = checkday(buf, len);
secnum = 0;
}
else {
- val = curlx_sltosi(strtol(date, &end, 10));
+ long lval;
+ int error;
+ int old_errno;
+
+ old_errno = ERRNO;
+ SET_ERRNO(0);
+ lval = strtol(date, &end, 10);
+ error = ERRNO;
+ if(error != old_errno)
+ SET_ERRNO(old_errno);
+
+ if(error)
+ return PARSEDATE_FAIL;
+
+#if LONG_MAX != INT_MAX
+ if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
+ return PARSEDATE_FAIL;
+#endif
+
+ val = curlx_sltosi(lval);
if((tzoff == -1) &&
((end - date) == 4) &&
(indate< date) &&
((date[-1] == '+' || date[-1] == '-'))) {
/* four digits and a value less than or equal to 1400 (to take into
- account all sorts of funny time zone diffs) and it is preceeded
+ account all sorts of funny time zone diffs) and it is preceded
with a plus or minus. This is a time zone indication. 1400 is
picked since +1300 is frequently used and +1400 is mentioned as
an edge number in the document "ISO C 200X Proposal: Timezone
return PARSEDATE_SOONER;
}
+ if((mdaynum > 31) || (monnum > 11) ||
+ (hournum > 23) || (minnum > 59) || (secnum > 60))
+ return PARSEDATE_FAIL; /* clearly an illegal date */
+
tm.tm_sec = secnum;
tm.tm_min = minnum;
tm.tm_hour = hournum;
/* Add the time zone diff between local time zone and GMT. */
long delta = (long)(tzoff!=-1?tzoff:0);
- if((delta>0) && (t + delta < t))
- return -1; /* time_t overflow */
+ if((delta>0) && (t > LONG_MAX - delta)) {
+ *output = 0x7fffffff;
+ return PARSEDATE_LATER; /* time_t overflow */
+ }
t += delta;
}
time_t curl_getdate(const char *p, const time_t *now)
{
- time_t parsed;
- int rc = Curl_parsedate(p, &parsed);
+ time_t parsed = -1;
+ int rc = parsedate(p, &parsed);
(void)now; /* legacy argument from the past that we ignore */
switch(rc) {
/* everything else is fail */
return -1;
}
+
+/*
+ * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
+ * gmtime_r() or gmtime() functions anywhere else but here.
+ *
+ */
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store)
+{
+ const struct tm *tm;
+#ifdef HAVE_GMTIME_R
+ /* thread-safe version */
+ tm = (struct tm *)gmtime_r(&intime, store);
+#else
+ tm = gmtime(&intime);
+ if(tm)
+ *store = *tm; /* copy the pointed struct to the local copy */
+#endif
+
+ if(!tm)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ return CURLE_OK;
+}