Browse Source

add scan_iso8601+test

master
Felix von Leitner 6 years ago
parent
commit
ba17f2b5df
  1. 6
      scan.h
  2. 75
      scan/scan_iso8601.c
  3. 7
      test/fmt_iso8691.c

6
scan.h

@ -8,6 +8,8 @@
#include <stdint.h>
/* for time_t: */
#include <sys/types.h>
/* for struct timespec: */
#include <time.h>
#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__;

75
scan/scan_iso8601.c

@ -0,0 +1,75 @@
#define _GNU_SOURCE
#define __deprecated__
#include "scan.h"
#include "byte.h"
#include "case.h"
#include <time.h>
#include <stdlib.h>
#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);
}

7
test/fmt_iso8691.c

@ -1,10 +1,13 @@
#include <fmt.h>
#include <scan.h>
#include <assert.h>
#include <unistd.h>
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;
}
Loading…
Cancel
Save