From ac6979e4af3eabd3c71cffe2e925915a809b5b8d Mon Sep 17 00:00:00 2001 From: leitner Date: Wed, 13 May 2015 21:21:16 +0000 Subject: [PATCH] add scan_iso8601+test --- scan.h | 6 ++++ scan/scan_iso8601.c | 75 +++++++++++++++++++++++++++++++++++++++++++++ test/fmt_iso8691.c | 7 +++-- 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 scan/scan_iso8601.c diff --git a/scan.h b/scan.h index 78b1853..f366178 100644 --- a/scan.h +++ b/scan.h @@ -8,6 +8,8 @@ #include /* for time_t: */ #include +/* for struct timespec: */ +#include #ifdef __cplusplus extern "C" { @@ -103,6 +105,10 @@ size_t scan_noncharsetnskip(const char *in,const char *charset,size_t limit) __p */ size_t scan_httpdate(const char *in,time_t *t) __pure__; +/* try to parse ASCII ISO-8601 date; does not understand time zones. */ +/* example date: "2014-05-27T19:22:16Z" */ +size_t scan_iso8601(const char* in,struct timespec* t) __pure__; + /* some variable length encodings for integers */ size_t scan_utf8(const char* in,size_t len,uint32_t* n) __pure__; size_t scan_asn1derlength(const char* in,size_t len,unsigned long long* n) __pure__; diff --git a/scan/scan_iso8601.c b/scan/scan_iso8601.c new file mode 100644 index 0000000..02d8930 --- /dev/null +++ b/scan/scan_iso8601.c @@ -0,0 +1,75 @@ +#define _GNU_SOURCE +#define __deprecated__ +#include "scan.h" +#include "byte.h" +#include "case.h" +#include +#include + +#ifdef sgi +extern char** environ; +#endif + +/* "2014-05-27T19:22:16Z" */ +size_t scan_iso8601(const char* in,struct timespec* t) { + struct tm x; + const char* c; + unsigned long tmp; + if (!(c=in)) return 0; + if (scan_ulong(c,&tmp)!=4 || c[4]!='-') return 0; c+=5; x.tm_year=(int)(tmp-1900); + if (scan_ulong(c,&tmp)!=2 || c[2]!='-') return 0; c+=3; x.tm_mon=(int)(tmp-1); + if (scan_ulong(c,&tmp)!=2 || c[2]!='T') return 0; c+=3; x.tm_mday=(int)tmp; + if (scan_ulong(c,&tmp)!=2 || c[2]!=':') return 0; c+=3; x.tm_hour=(int)tmp; + if (scan_ulong(c,&tmp)!=2 || c[2]!=':') return 0; c+=3; x.tm_min=(int)tmp; + if (scan_ulong(c,&tmp)!=2) return 0; c+=2; x.tm_sec=(int)tmp; + if (*c=='.') { + size_t i; + ++c; + i=scan_ulong(c,&tmp); + c+=i; + if (i<1 || i>9) + t->tv_nsec=0; + else { + while (i<9) { + ++i; + tmp*=10; + } + t->tv_nsec=tmp; + } + } + + x.tm_wday=x.tm_yday=x.tm_isdst=0; +#if defined(__dietlibc__) || defined(__GLIBC__) + t->tv_sec=timegm(&x); +#elif defined(__MINGW32__) + t->tv_sec=mktime(&x); +#else + { +#ifdef sgi + char** old=environ; + char** newenv={0}; + environ=newenv; + t->tv_sec=mktime(&x); + environ=old; +#else + char* old=getenv("TZ"); + unsetenv("TZ"); + t->tv_sec=mktime(&x); + if (old) setenv("TZ",old,1); +#endif + } +#endif + + if (*c=='+' || *c=='-') { + int signum = (*c=='+') - (*c=='-'); + unsigned int val; + ++c; + if (scan_ulong(c,&tmp)!=2 || c[2]!=':') return 0; c+=3; val=tmp*60; + if (scan_ulong(c,&tmp)!=2) return 0; c+=2; val+=tmp; + t->tv_sec+=signum*val; + } else if (*c=='Z') + ++c; + else + return 0; + return (size_t)(c-in); +} diff --git a/test/fmt_iso8691.c b/test/fmt_iso8691.c index 44765b3..e586c30 100644 --- a/test/fmt_iso8691.c +++ b/test/fmt_iso8691.c @@ -1,10 +1,13 @@ #include +#include #include #include int main() { char buf[1024]; - write(1,buf,fmt_iso8601(buf,0)); - write(1,"\n",1); + buf[fmt_iso8601(buf,1431551843)]=0; // Wed May 13 14:17:23 PDT 2015 + assert(!strcmp(buf,"2015-05-13T21:17:23Z")); + struct timespec t; + assert(scan_iso8601("2015-05-13T21:17:23Z",&t)==20 && t.tv_sec==1431551843); return 0; }