From d61e77f9dc92f90cacfe4be93c04bab87ca99a71 Mon Sep 17 00:00:00 2001 From: Laurence Withers Date: Sun, 15 Oct 2006 22:11:17 +0100 Subject: [PATCH] WIP on parser --- src/libiso8601/functions.h | 4 +- src/libiso8601/parser.c | 266 ++++++++++++++++++++++++++++++++++++- src/tests/parser.c | 74 +++++++++++ 3 files changed, 340 insertions(+), 4 deletions(-) create mode 100644 src/tests/parser.c diff --git a/src/libiso8601/functions.h b/src/libiso8601/functions.h index c13bf29..950557c 100644 --- a/src/libiso8601/functions.h +++ b/src/libiso8601/functions.h @@ -6,8 +6,8 @@ */ /* parse.c */ -void iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest, - struct iso8601_details* details); +int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest, + struct iso8601_details* details); /* c_library.c */ void iso8601_now(struct iso8601_date* date, struct iso8601_details* details); diff --git a/src/libiso8601/parser.c b/src/libiso8601/parser.c index 754515b..2166321 100644 --- a/src/libiso8601/parser.c +++ b/src/libiso8601/parser.c @@ -7,10 +7,272 @@ -void iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest, +int iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest, struct iso8601_details* details) { - + enum { + state_none, + state_year, // e.g. `2006' or `2006123' + state_date2, // 2nd component of date, e.g. `2006-' or `2006-1' + state_day, // e.g. `2006-01-' or `2006-01-01' + state_week_basic, // e.g. `2006W' or `2006W123' + state_week_extended, // e.g. `2006-W' or `2006-W31' + state_week_day, // e.g. `2006-W31-' + state_week_done, // `2006-W31-1' + state_time_basic, + state_time_hour + }state = state_none; + + char ch; + int num = 0, neg = 0, dig = 0; + int y = 0, m = 0, d = 0, w = 0, wd = 0, hour = 0, min = 0, sec = 0; + + while(1) { + ch = *str++; +printf("ch = '%c', state = %d, num = %d, dig = %d\n", ch, state, num, dig); + + switch(state) { + case state_none: + switch(ch) { + case '0' ... '9': + state = state_year; + num = ch - '0'; + ++dig; + break; + + case '-': + neg = 1; + state = state_year; + break; + + default: + errno = EILSEQ; + return -1; + } + break; + + case state_year: + switch(ch) { + case '0' ... '9': + ++dig; + num *= 10; + num += ch - '0'; + if(num > 1000000000) { + errno = EDOM; + return -1; + } + break; + + case '-': + if(!dig) { + errno = EILSEQ; + return -1; + } + y = num; + num = 0; + dig = 0; + state = state_date2; + break; + + case 'T': + case 0: + switch(dig) { + case 4: + if(ch) { + errno = EILSEQ; + return -1; + } + y = num; + goto done; + + case 6: + if(ch) { + errno = EILSEQ; + return -1; + } + y = num / 100; + m = num - y * 100; + goto done; + + case 7: + y = num / 1000; + d = num - (y * 1000); + break; + + case 8: + y = num / 10000; + num -= y * 10000; + m = num / 100; + d = num - m * 100; + break; + + default: + errno = EILSEQ; + return -1; + } + if(!ch) goto done; + state = state_time_basic; + num = 0; + dig = 0; + break; + + case 'W': + y = num; + num = 0; + dig = 0; + state = state_week_basic; + break; + } + break; + + case state_date2: + switch(ch) { + case '0' ... '9': + num *= 10; + num += ch - '0'; + ++dig; + break; + + case '-': + if(num < 1 || num > 12 || dig != 2) { + errno = EDOM; + return -1; + } + m = num; + num = 0; + dig = 0; + state = state_day; + + case 'W': + if(dig) { + errno = EILSEQ; + return -1; + } + state = state_week_extended; + break; + + case 0: + case 'T': + if(dig != 3) { + errno = EILSEQ; + return -1; + } + d = num; + if(!ch) goto done; + state = state_time_hour; + num = 0; + dig = 0; + break; + + default: + errno = EILSEQ; + return -1; + } + break; + + case state_day: + switch(ch) { + case '0' ... '9': + num *= 10; + num += ch; + ++dig; + break; + + case 0: + case 'T': + if(dig != 2) { + errno = EILSEQ; + return -1; + } + d = num; + if(!ch) goto done; + state = state_time_hour; + break; + + default: + errno = EILSEQ; + return -1; + } + break; + + case state_week_basic: + switch(ch) { + case '0' ... '9': + num *= 10; + num += ch - '0'; + ++dig; + break; + + case 0: + case 'T': + switch(dig) { + case 3: + w = num / 10; + wd = num % 10; + break; + + case 2: + w = num; + if(!ch) break; + + default: + errno = EILSEQ; + return -1; + } + if(!ch) goto done; + break; + } + break; + + case state_week_extended: + switch(ch) { + case '0' ... '9': + num *= 10; + num += ch - '0'; + ++dig; + break; + + case 0: + case '-': + if(dig != 2) { + errno = EILSEQ; + return -1; + } + w = num; + num = 0; + dig = 0; + if(!ch) goto done; + state = state_week_day; + break; + } + break; + + case state_week_day: + if(ch < '1' || ch > '7') { + errno = EILSEQ; + return -1; + } + wd = ch - '0'; + state = state_week_done; + break; + + case state_week_done: + if(!ch) goto done; + if(ch != 'T') { + errno = EILSEQ; + return -1; + } + state = state_time_hour; + break; + + default: + goto done; + } + } + +done: + printf("y=%d, m=%d, d=%d, w=%d, wd=%d\n", y, m, d, w, wd); + abort(); } diff --git a/src/tests/parser.c b/src/tests/parser.c new file mode 100644 index 0000000..1489e35 --- /dev/null +++ b/src/tests/parser.c @@ -0,0 +1,74 @@ +/* libiso8601/src/tests/parser.c + * + * (c)2006, Laurence Withers, . + * Released under the GNU GPLv2. See file COPYING or + * http://www.gnu.org/copyleft/gpl.html for details. +*/ + +#include "iso8601.h" + +#include +#include + + + +int do_date(const char* str) +{ + struct iso8601_date earliest, latest; + struct iso8601_details details; + char buf[100], buf2[100]; + + if(iso8601_parse(str, &earliest, &latest, &details)) { + perror("iso8601_parse"); + return 1; + } + + iso8601_print(buf, sizeof(buf), &earliest, &details); + iso8601_print(buf2, sizeof(buf2), &latest, &details); + + printf("Results for ``%s'':\n" + " Earliest: day=%d, sec=%05d, nsec=%09d; %s\n" + " Latest : day=%d, sec=%05d, nsec=%09d; %s\n" + " Details : date_prec=%d, time_prec=%d, extended=%d, tz_sec=%d\n" + "\n", + str, + earliest.day, earliest.sec, earliest.nsec, buf, + latest.day, latest.sec, latest.nsec, buf2, + details.date_prec, details.time_prec, details.extended, details.tz_sec); + + return 0; +} + + + +int main(int argc, char* argv[]) +{ + int ret = 0, i; + char buf[100]; + + if(argc == 2 && !strcmp(argv[1], "--print-summary")) { + printf("One line summary.\n"); + return 0; + } + + if(argc == 1) { + while(!feof(stdin)) { + printf("date >> "); + scanf("%s", buf); + do_date(buf); + } + + return 0; + } + + for(i = 1; i < argc; ++i) { + ret |= do_date(argv[i]); + } + + return ret; +} + +/* options for text editors +kate: replace-trailing-space-save true; space-indent true; tab-width 4; +vim: expandtab:ts=4:sw=4 +*/