summaryrefslogtreecommitdiff
path: root/gpsutils.c
diff options
context:
space:
mode:
authorRob Norris <rw_norris@hotmail.com>2016-03-22 12:27:29 -0400
committerEric S. Raymond <esr@thyrsus.com>2016-03-22 12:27:29 -0400
commit2a52fb534a8a3845a89ffed89aeec44cb9dbe91e (patch)
tree3bd571cf4b8f68761753eb20de64aa59f4db785c /gpsutils.c
parent4d5e4aa13c19859aae982b7c56b0c8f0406f5d17 (diff)
downloadgpsd-2a52fb534a8a3845a89ffed89aeec44cb9dbe91e.tar.gz
Add Windows versions of time related functions.
Diffstat (limited to 'gpsutils.c')
-rw-r--r--gpsutils.c95
1 files changed, 92 insertions, 3 deletions
diff --git a/gpsutils.c b/gpsutils.c
index 3add68b0..254cd552 100644
--- a/gpsutils.c
+++ b/gpsutils.c
@@ -336,15 +336,99 @@ timestamp_t iso8601_to_unix(char *isotime)
#ifndef __clang_analyzer__
#ifndef USE_QT
char *dp = NULL;
- double usec;
+ double usec = 0;
struct tm tm;
memset(&tm,0,sizeof(tm));
+#ifdef HAVE_STRPTIME
dp = strptime(isotime, "%Y-%m-%dT%H:%M:%S", &tm);
+#else
+ /* Fallback for systems without strptime (i.e. Windows)
+ This is a simplistic conversion for iso8601 strings only,
+ rather than embedding a full copy of strptime() that handles all formats */
+ double sec;
+ unsigned int tmp; // Thus avoiding needing to test for (broken) negative date/time numbers in token reading - only need to check the upper range
+ bool failed = false;
+ char *isotime_tokenizer = strdup(isotime);
+ if (isotime_tokenizer) {
+ char *tmpbuf;
+ char *pch = strtok_r(isotime_tokenizer, "-T:", &tmpbuf);
+ int token_number = 0;
+ while (pch != NULL) {
+ token_number++;
+ // Give up if encountered way too many tokens.
+ if (token_number > 10) {
+ failed = true;
+ break;
+ }
+ switch (token_number) {
+ case 1: // Year token
+ tmp = atoi(pch);
+ if (tmp < 9999)
+ tm.tm_year = tmp - 1900; // Adjust to tm year
+ else
+ failed = true;
+ break;
+ case 2: // Month token
+ tmp = atoi(pch);
+ if (tmp < 13)
+ tm.tm_mon = tmp - 1; // Month indexing starts from zero
+ else
+ failed = true;
+ break;
+ case 3: // Day token
+ tmp = atoi(pch);
+ if (tmp < 32)
+ tm.tm_mday = tmp;
+ else
+ failed = true;
+ break;
+ case 4: // Hour token
+ tmp = atoi(pch);
+ if (tmp < 24)
+ tm.tm_hour = tmp;
+ else
+ failed = true;
+ break;
+ case 5: // Minute token
+ tmp = atoi(pch);
+ if (tmp < 60)
+ tm.tm_min = tmp;
+ else
+ failed = true;
+ break;
+ case 6: // Seconds token
+ sec = safe_atof(pch);
+ // NB To handle timestamps with leap seconds
+ if (sec >= 0.0 && sec < 61.5 ) {
+ tm.tm_sec = (unsigned int)sec; // Truncate to get integer value
+ usec = sec - (unsigned int)sec; // Get the fractional part (if any)
+ }
+ else
+ failed = true;
+ break;
+ default: break;
+ }
+ pch = strtok_r(NULL, "-T:", &tmpbuf);
+ }
+ free(isotime_tokenizer);
+ // Split may result in more than 6 tokens if the TZ has any t's in it
+ // So check that we've seen enough tokens rather than an exact number
+ if (token_number < 6)
+ failed = true;
+ }
+ if (failed)
+ memset(&tm,0,sizeof(tm));
+ else {
+ // When successful this normalizes tm so that tm_yday is set
+ // and thus tm is valid for use with other functions
+ if (mktime(&tm) == (time_t)-1)
+ // Failed mktime - so reset the timestamp
+ memset(&tm,0,sizeof(tm));
+ }
+#endif
if (dp != NULL && *dp == '.')
usec = strtod(dp, NULL);
- else
- usec = 0;
/*
* It would be nice if we could say mktime(&tm) - timezone + usec instead,
* but timezone is not available at all on some BSDs. Besides, when working
@@ -380,7 +464,12 @@ char *unix_to_iso8601(timestamp_t fixtime, /*@ out @*/
fractional = modf(fixtime, &integral);
intfixtime = (time_t) integral;
+#ifdef HAVE_GMTIME_R
(void)gmtime_r(&intfixtime, &when);
+#else
+ /* Fallback to try with gmtime_s - primarily for Windows */
+ (void)gmtime_s(&when, &intfixtime);
+#endif
(void)strftime(timestr, sizeof(timestr), "%Y-%m-%dT%H:%M:%S", &when);
/*