derick Sun Jan 13 15:16:11 2008 UTC Modified files: (Branch: PHP_5_3) /php-src NEWS /php-src/ext/date php_date.c php_date.h /php-src/ext/date/lib parse_date.c parse_date.re timelib.h Log: - Added new date/time functionality: * date_parse_from_format(): Parse date/time strings according to a format. * date_create_from_format()/DateTime::createFromFormat(): Create a date/time object by parsing a date/time string according to a given format. * date_get_last_errors()/DateTime::getLastErrors(): Return a list of warnings and errors that were found while parsing a date/time string through: - strtotime() / new DateTime - date_create_from_format() / DateTime::createFromFormat() - date_parse_from_format() # [DOC]
http://cvs.php.net/viewvc.cgi/php-src/NEWS?r1=1.2027.2.547.2.965.2.69&r2=1.2027.2.547.2.965.2.70&diff_format=u Index: php-src/NEWS diff -u php-src/NEWS:1.2027.2.547.2.965.2.69 php-src/NEWS:1.2027.2.547.2.965.2.70 --- php-src/NEWS:1.2027.2.547.2.965.2.69 Sun Jan 13 14:44:28 2008 +++ php-src/NEWS Sun Jan 13 15:15:48 2008 @@ -1,6 +1,17 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 20??, PHP 5.3.0 +- Added new date/time functionality: + + * date_parse_from_format(): Parse date/time strings according to a format. + * date_create_from_format()/DateTime::createFromFormat(): Create a date/time + object by parsing a date/time string according to a given format. + * date_get_last_errors()/DateTime::getLastErrors(): Return a list of warnings + and errors that were found while parsing a date/time string through: + - strtotime() / new DateTime + - date_create_from_format() / DateTime::createFromFormat() + - date_parse_from_format() + - Added ability to use Traversable objects instead of plain arrays in ext/soap. (Joshua Reese, Dmitry) - Added "?:" operator. (Marcus) http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.c?r1=1.43.2.45.2.51.2.6&r2=1.43.2.45.2.51.2.7&diff_format=u Index: php-src/ext/date/php_date.c diff -u php-src/ext/date/php_date.c:1.43.2.45.2.51.2.6 php-src/ext/date/php_date.c:1.43.2.45.2.51.2.7 --- php-src/ext/date/php_date.c:1.43.2.45.2.51.2.6 Mon Dec 31 07:17:07 2007 +++ php-src/ext/date/php_date.c Sun Jan 13 15:15:48 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_date.c,v 1.43.2.45.2.51.2.6 2007/12/31 07:17:07 sebastian Exp $ */ +/* $Id: php_date.c,v 1.43.2.45.2.51.2.7 2008/01/13 15:15:48 derick Exp $ */ #include "php.h" #include "php_streams.h" @@ -168,7 +168,10 @@ /* Advanced Interface */ PHP_FE(date_create, NULL) + PHP_FE(date_create_from_format, NULL) PHP_FE(date_parse, NULL) + PHP_FE(date_parse_from_format, NULL) + PHP_FE(date_get_last_errors, NULL) PHP_FE(date_format, NULL) PHP_FE(date_modify, NULL) PHP_FE(date_timezone_get, NULL) @@ -201,6 +204,8 @@ const zend_function_entry date_funcs_date[] = { PHP_ME(DateTime, __construct, NULL, ZEND_ACC_CTOR|ZEND_ACC_PUBLIC) + PHP_ME_MAPPING(createFromFormat, date_create_from_format, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME_MAPPING(getLastErrors, date_get_last_errors, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) PHP_ME_MAPPING(format, date_format, NULL, 0) PHP_ME_MAPPING(modify, date_modify, NULL, 0) PHP_ME_MAPPING(getTimezone, date_timezone_get, NULL, 0) @@ -510,7 +515,8 @@ php_date_global_timezone_db = NULL; php_date_global_timezone_db_enabled = 0; - + + DATEG(last_errors) = NULL; return SUCCESS; } /* }}} */ @@ -520,6 +526,10 @@ { UNREGISTER_INI_ENTRIES(); + if (DATEG(last_errors)) { + timelib_error_container_dtor(DATEG(last_errors)); + } + return SUCCESS; } /* }}} */ @@ -1634,7 +1644,18 @@ return object; } -static void date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, zval *timezone_object TSRMLS_DC) +/* Helper function used to store the latest found warnings and errors while + * parsing, from either strtotime or parse_from_format. */ +static void update_errors_warnings(timelib_error_container *last_errors) +{ + if (DATEG(last_errors)) { + timelib_error_container_dtor(DATEG(last_errors)); + DATEG(last_errors) = NULL; + } + DATEG(last_errors) = last_errors; +} + +static void date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int time_str_len, char *format, zval *timezone_object TSRMLS_DC) { timelib_time *now; timelib_tzinfo *tzi; @@ -1647,16 +1668,15 @@ } timelib_time_dtor(dateobj->time); } - dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB); - if (err) { - if (err->error_count) { - /* spit out the first library error message, at least */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", time_str, - err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message); - } - timelib_error_container_dtor(err); + if (format) { + dateobj->time = timelib_parse_from_format(format, time_str_len ? time_str : "", time_str_len ? time_str_len : 0, &err, DATE_TIMEZONEDB); + } else { + dateobj->time = timelib_strtotime(time_str_len ? time_str : "now", time_str_len ? time_str_len : sizeof("now") -1, &err, DATE_TIMEZONEDB); } + // update last errors and warnings + update_errors_warnings(err); + if (timezone_object) { php_timezone_obj *tzobj; @@ -1703,7 +1723,25 @@ } date_instantiate(date_ce_date, return_value TSRMLS_CC); - date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, timezone_object TSRMLS_CC); + date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, NULL, timezone_object TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto DateTime date_create(string format, string time[, DateTimeZone object]) + Returns new DateTime object +*/ +PHP_FUNCTION(date_create_from_format) +{ + zval *timezone_object = NULL; + char *time_str = NULL, *format_str = NULL; + int time_str_len = 0, format_str_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|O", &format_str, &format_str_len, &time_str, &time_str_len, &timezone_object, date_ce_timezone) == FAILURE) { + RETURN_FALSE; + } + + date_instantiate(date_ce_date, return_value TSRMLS_CC); + date_initialize(zend_object_store_get_object(return_value TSRMLS_CC), time_str, time_str_len, format_str, timezone_object TSRMLS_CC); } /* }}} */ @@ -1718,28 +1756,53 @@ php_set_error_handling(EH_THROW, NULL TSRMLS_CC); if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sO", &time_str, &time_str_len, &timezone_object, date_ce_timezone)) { - date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, timezone_object TSRMLS_CC); + date_initialize(zend_object_store_get_object(getThis() TSRMLS_CC), time_str, time_str_len, NULL, timezone_object TSRMLS_CC); } php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } /* }}} */ -/* {{{ proto array date_parse(string date) - Returns associative array with detailed info about given date +/* Helper function used to add an associative array of warnings and errors to a zval */ +void zval_from_error_container(zval *z, timelib_error_container *error) +{ + int i; + zval *element; + + add_assoc_long(z, "warning_count", error->warning_count); + MAKE_STD_ZVAL(element); + array_init(element); + for (i = 0; i < error->warning_count; i++) { + add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1); + } + add_assoc_zval(z, "warnings", element); + + add_assoc_long(z, "error_count", error->error_count); + MAKE_STD_ZVAL(element); + array_init(element); + for (i = 0; i < error->error_count; i++) { + add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1); + } + add_assoc_zval(z, "errors", element); +} + +/* {{{ proto array date_get_last_errorse() + Returns the warnings and errors found while parsing a date/time string. */ -PHP_FUNCTION(date_parse) +PHP_FUNCTION(date_get_last_errors) { - char *date; - int date_len, i; - struct timelib_error_container *error; - timelib_time *parsed_time; - zval *element; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) { + array_init(return_value); + if (DATEG(last_errors)) { + zval_from_error_container(return_value, DATEG(last_errors)); + } else { RETURN_FALSE; } +} +/* }}} */ + +void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *parsed_time, struct timelib_error_container *error) +{ + zval *element; - parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB); array_init(return_value); #define PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(name, elem) \ if (parsed_time->elem == -99999) { \ @@ -1760,21 +1823,8 @@ add_assoc_double(return_value, "fraction", parsed_time->f); } - add_assoc_long(return_value, "warning_count", error->warning_count); - MAKE_STD_ZVAL(element); - array_init(element); - for (i = 0; i < error->warning_count; i++) { - add_index_string(element, error->warning_messages[i].position, error->warning_messages[i].message, 1); - } - add_assoc_zval(return_value, "warnings", element); + zval_from_error_container(return_value, error); - add_assoc_long(return_value, "error_count", error->error_count); - MAKE_STD_ZVAL(element); - array_init(element); - for (i = 0; i < error->error_count; i++) { - add_index_string(element, error->error_messages[i].position, error->error_messages[i].message, 1); - } - add_assoc_zval(return_value, "errors", element); timelib_error_container_dtor(error); add_assoc_bool(return_value, "is_localtime", parsed_time->is_localtime); @@ -1821,8 +1871,44 @@ } timelib_time_dtor(parsed_time); } + +/* {{{ proto array date_parse(string date) + Returns associative array with detailed info about given date +*/ +PHP_FUNCTION(date_parse) +{ + char *date; + int date_len; + struct timelib_error_container *error; + timelib_time *parsed_time; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) { + RETURN_FALSE; + } + + parsed_time = timelib_strtotime(date, date_len, &error, DATE_TIMEZONEDB); + php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error); +} /* }}} */ +/* {{{ proto array date_parse(string date) + Returns associative array with detailed info about given date +*/ +PHP_FUNCTION(date_parse_from_format) +{ + char *date, *format; + int date_len, format_len; + struct timelib_error_container *error; + timelib_time *parsed_time; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, &format_len, &date, &date_len) == FAILURE) { + RETURN_FALSE; + } + + parsed_time = timelib_parse_from_format(format, date, date_len, &error, DATE_TIMEZONEDB); + php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAM_PASSTHRU, parsed_time, error); +} + /* {{{ proto string date_format(DateTime object, string format) Returns date formatted according to given format */ http://cvs.php.net/viewvc.cgi/php-src/ext/date/php_date.h?r1=1.17.2.11.2.3.2.2&r2=1.17.2.11.2.3.2.3&diff_format=u Index: php-src/ext/date/php_date.h diff -u php-src/ext/date/php_date.h:1.17.2.11.2.3.2.2 php-src/ext/date/php_date.h:1.17.2.11.2.3.2.3 --- php-src/ext/date/php_date.h:1.17.2.11.2.3.2.2 Mon Dec 31 07:17:07 2007 +++ php-src/ext/date/php_date.h Sun Jan 13 15:15:48 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_date.h,v 1.17.2.11.2.3.2.2 2007/12/31 07:17:07 sebastian Exp $ */ +/* $Id: php_date.h,v 1.17.2.11.2.3.2.3 2008/01/13 15:15:48 derick Exp $ */ #ifndef PHP_DATE_H #define PHP_DATE_H @@ -49,7 +49,10 @@ /* Advanced Interface */ PHP_METHOD(DateTime, __construct); PHP_FUNCTION(date_create); +PHP_FUNCTION(date_create_from_format); PHP_FUNCTION(date_parse); +PHP_FUNCTION(date_parse_from_format); +PHP_FUNCTION(date_get_last_errors); PHP_FUNCTION(date_format); PHP_FUNCTION(date_modify); PHP_FUNCTION(date_timezone_get); @@ -89,6 +92,7 @@ char *default_timezone; char *timezone; HashTable tzcache; + timelib_error_container *last_errors; ZEND_END_MODULE_GLOBALS(date) #ifdef ZTS http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_date.c?r1=1.29.2.30.2.14&r2=1.29.2.30.2.14.2.1&diff_format=u Index: php-src/ext/date/lib/parse_date.c diff -u php-src/ext/date/lib/parse_date.c:1.29.2.30.2.14 php-src/ext/date/lib/parse_date.c:1.29.2.30.2.14.2.1 --- php-src/ext/date/lib/parse_date.c:1.29.2.30.2.14 Thu Jul 12 18:59:55 2007 +++ php-src/ext/date/lib/parse_date.c Sun Jan 13 15:15:48 2008 @@ -1,4 +1,4 @@ -/* Generated by re2c 0.12.1 on Thu Jul 12 19:32:22 2007 */ +/* Generated by re2c 0.12.1 on Sun Jan 13 15:46:00 2008 */ #line 1 "ext/date/lib/parse_date.re" /* +----------------------------------------------------------------------+ @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: parse_date.c,v 1.29.2.30.2.14 2007/07/12 18:59:55 derick Exp $ */ +/* $Id: parse_date.c,v 1.29.2.30.2.14.2.1 2008/01/13 15:15:48 derick Exp $ */ #include "timelib.h" @@ -351,6 +351,24 @@ s->errors->error_messages[s->errors->error_count - 1].message = strdup(error); } +static void add_pbf_warning(Scanner *s, char *error, char *sptr, char *cptr) +{ + s->errors->warning_count++; + s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message)); + s->errors->warning_messages[s->errors->warning_count - 1].position = cptr - sptr; + s->errors->warning_messages[s->errors->warning_count - 1].character = *cptr; + s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error); +} + +static void add_pbf_error(Scanner *s, char *error, char *sptr, char *cptr) +{ + s->errors->error_count++; + s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message)); + s->errors->error_messages[s->errors->error_count - 1].position = cptr - sptr; + s->errors->error_messages[s->errors->error_count - 1].character = *cptr; + s->errors->error_messages[s->errors->error_count - 1].message = strdup(error); +} + static timelib_sll timelib_meridian(char **ptr, timelib_sll h) { timelib_sll retval = 0; @@ -374,6 +392,39 @@ return retval; } +static timelib_sll timelib_meridian_with_check(char **ptr, timelib_sll h) +{ + timelib_sll retval = 0; + + while (!strchr("AaPp", **ptr)) { + ++*ptr; + } + if (**ptr == 'a' || **ptr == 'A') { + if (h == 12) { + retval = -12; + } + } else if (h != 12) { + retval = 12; + } + ++*ptr; + if (**ptr == '.') { + ++*ptr; + if (**ptr != 'm' && **ptr != 'M') { + return TIMELIB_UNSET; + } + ++*ptr; + if (**ptr != '.' ) { + return TIMELIB_UNSET; + } + ++*ptr; + } else if (**ptr == 'm' || **ptr == 'M') { + ++*ptr; + } else { + return TIMELIB_UNSET; + } + return retval; +} + static char *timelib_string(Scanner *s) { char *tmp = calloc(1, s->cur - s->tok + 1); @@ -568,6 +619,13 @@ } } +static void timelib_eat_until_seperator(char **ptr) +{ + while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) { + ++*ptr; + } +} + static const timelib_relunit* timelib_lookup_relunit(char **ptr) { char *word; @@ -772,7 +830,7 @@ std: s->tok = cursor; s->len = 0; -#line 889 "ext/date/lib/parse_date.re" +#line 947 "ext/date/lib/parse_date.re" { @@ -811,7 +869,7 @@ 0, 0, 0, 0, 0, 0, 0, 0, }; -#line 815 "ext/date/lib/parse_date.c" +#line 873 "ext/date/lib/parse_date.c" { YYCTYPE yych; unsigned int yyaccept = 0; @@ -917,7 +975,7 @@ } yy3: YYDEBUG(3, *YYCURSOR); -#line 1443 "ext/date/lib/parse_date.re" +#line 1501 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("tzcorrection | tz"); @@ -930,7 +988,7 @@ TIMELIB_DEINIT; return TIMELIB_TIMEZONE; } -#line 934 "ext/date/lib/parse_date.c" +#line 992 "ext/date/lib/parse_date.c" yy4: YYDEBUG(4, *YYCURSOR); yych = *++YYCURSOR; @@ -1241,12 +1299,12 @@ if(yych <= '9') goto yy1274; yy12: YYDEBUG(12, *YYCURSOR); -#line 1538 "ext/date/lib/parse_date.re" +#line 1596 "ext/date/lib/parse_date.re" { add_error(s, "Unexpected character"); goto std; } -#line 1250 "ext/date/lib/parse_date.c" +#line 1308 "ext/date/lib/parse_date.c" yy13: YYDEBUG(13, *YYCURSOR); yyaccept = 1; @@ -2252,11 +2310,11 @@ if(yych <= '9') goto yy51; yy46: YYDEBUG(46, *YYCURSOR); -#line 1527 "ext/date/lib/parse_date.re" +#line 1585 "ext/date/lib/parse_date.re" { goto std; } -#line 2260 "ext/date/lib/parse_date.c" +#line 2318 "ext/date/lib/parse_date.c" yy47: YYDEBUG(47, *YYCURSOR); yych = *++YYCURSOR; @@ -2265,12 +2323,12 @@ YYDEBUG(48, *YYCURSOR); ++YYCURSOR; YYDEBUG(49, *YYCURSOR); -#line 1532 "ext/date/lib/parse_date.re" +#line 1590 "ext/date/lib/parse_date.re" { s->pos = cursor; s->line++; goto std; } -#line 2274 "ext/date/lib/parse_date.c" +#line 2332 "ext/date/lib/parse_date.c" yy50: YYDEBUG(50, *YYCURSOR); yych = *++YYCURSOR; @@ -2649,7 +2707,7 @@ if(yych == 's') goto yy70; yy69: YYDEBUG(69, *YYCURSOR); -#line 1511 "ext/date/lib/parse_date.re" +#line 1569 "ext/date/lib/parse_date.re" { timelib_ull i; DEBUG_OUTPUT("relative"); @@ -2664,7 +2722,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 2668 "ext/date/lib/parse_date.c" +#line 2726 "ext/date/lib/parse_date.c" yy70: YYDEBUG(70, *YYCURSOR); yych = *++YYCURSOR; @@ -3572,7 +3630,7 @@ if(yych == 's') goto yy175; yy174: YYDEBUG(174, *YYCURSOR); -#line 1416 "ext/date/lib/parse_date.re" +#line 1474 "ext/date/lib/parse_date.re" { timelib_sll i; int behavior = 0; @@ -3588,7 +3646,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 3592 "ext/date/lib/parse_date.c" +#line 3650 "ext/date/lib/parse_date.c" yy175: YYDEBUG(175, *YYCURSOR); yych = *++YYCURSOR; @@ -4763,7 +4821,7 @@ } yy276: YYDEBUG(276, *YYCURSOR); -#line 1400 "ext/date/lib/parse_date.re" +#line 1458 "ext/date/lib/parse_date.re" { const timelib_relunit* relunit; DEBUG_OUTPUT("daytext"); @@ -4778,7 +4836,7 @@ TIMELIB_DEINIT; return TIMELIB_WEEKDAY; } -#line 4782 "ext/date/lib/parse_date.c" +#line 4840 "ext/date/lib/parse_date.c" yy277: YYDEBUG(277, *YYCURSOR); yych = *++YYCURSOR; @@ -5255,7 +5313,7 @@ } yy303: YYDEBUG(303, *YYCURSOR); -#line 1433 "ext/date/lib/parse_date.re" +#line 1491 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("monthtext"); TIMELIB_INIT; @@ -5264,7 +5322,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 5268 "ext/date/lib/parse_date.c" +#line 5326 "ext/date/lib/parse_date.c" yy304: YYDEBUG(304, *YYCURSOR); ++YYCURSOR; @@ -5315,7 +5373,7 @@ } yy308: YYDEBUG(308, *YYCURSOR); -#line 1212 "ext/date/lib/parse_date.re" +#line 1270 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datetextual | datenoyear"); TIMELIB_INIT; @@ -5327,7 +5385,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 5331 "ext/date/lib/parse_date.c" +#line 5389 "ext/date/lib/parse_date.c" yy309: YYDEBUG(309, *YYCURSOR); yyaccept = 7; @@ -5600,7 +5658,7 @@ } yy332: YYDEBUG(332, *YYCURSOR); -#line 1481 "ext/date/lib/parse_date.re" +#line 1539 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz"); @@ -5629,7 +5687,7 @@ TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 5633 "ext/date/lib/parse_date.c" +#line 5691 "ext/date/lib/parse_date.c" yy333: YYDEBUG(333, *YYCURSOR); yyaccept = 8; @@ -6240,7 +6298,7 @@ YYDEBUG(385, *YYCURSOR); ++YYCURSOR; YYDEBUG(386, *YYCURSOR); -#line 1457 "ext/date/lib/parse_date.re" +#line 1515 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12"); TIMELIB_INIT; @@ -6263,7 +6321,7 @@ TIMELIB_DEINIT; return TIMELIB_SHORTDATE_WITH_TIME; } -#line 6267 "ext/date/lib/parse_date.c" +#line 6325 "ext/date/lib/parse_date.c" yy387: YYDEBUG(387, *YYCURSOR); yych = *++YYCURSOR; @@ -6439,7 +6497,7 @@ if(yych <= '9') goto yy397; yy402: YYDEBUG(402, *YYCURSOR); -#line 1186 "ext/date/lib/parse_date.re" +#line 1244 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoday"); TIMELIB_INIT; @@ -6451,7 +6509,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 6455 "ext/date/lib/parse_date.c" +#line 6513 "ext/date/lib/parse_date.c" yy403: YYDEBUG(403, *YYCURSOR); yyaccept = 7; @@ -7687,7 +7745,7 @@ if(yych <= '9') goto yy474; yy473: YYDEBUG(473, *YYCURSOR); -#line 1326 "ext/date/lib/parse_date.re" +#line 1384 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pgtextshort"); TIMELIB_INIT; @@ -7699,7 +7757,7 @@ TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 7703 "ext/date/lib/parse_date.c" +#line 7761 "ext/date/lib/parse_date.c" yy474: YYDEBUG(474, *YYCURSOR); yych = *++YYCURSOR; @@ -9580,7 +9638,7 @@ } yy558: YYDEBUG(558, *YYCURSOR); -#line 1382 "ext/date/lib/parse_date.re" +#line 1440 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("ago"); TIMELIB_INIT; @@ -9597,7 +9655,7 @@ TIMELIB_DEINIT; return TIMELIB_AGO; } -#line 9601 "ext/date/lib/parse_date.c" +#line 9659 "ext/date/lib/parse_date.c" yy559: YYDEBUG(559, *YYCURSOR); yyaccept = 6; @@ -12192,7 +12250,7 @@ ++YYCURSOR; yy660: YYDEBUG(660, *YYCURSOR); -#line 1097 "ext/date/lib/parse_date.re" +#line 1155 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash"); TIMELIB_INIT; @@ -12203,7 +12261,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 12207 "ext/date/lib/parse_date.c" +#line 12265 "ext/date/lib/parse_date.c" yy661: YYDEBUG(661, *YYCURSOR); yyaccept = 0; @@ -12763,7 +12821,7 @@ } yy681: YYDEBUG(681, *YYCURSOR); -#line 1225 "ext/date/lib/parse_date.re" +#line 1283 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenoyearrev"); TIMELIB_INIT; @@ -12774,7 +12832,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_TEXT; } -#line 12778 "ext/date/lib/parse_date.c" +#line 12836 "ext/date/lib/parse_date.c" yy682: YYDEBUG(682, *YYCURSOR); yyaccept = 11; @@ -12915,7 +12973,7 @@ YYDEBUG(693, *YYCURSOR); ++YYCURSOR; YYDEBUG(694, *YYCURSOR); -#line 973 "ext/date/lib/parse_date.re" +#line 1031 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12"); TIMELIB_INIT; @@ -12931,7 +12989,7 @@ TIMELIB_DEINIT; return TIMELIB_TIME12; } -#line 12935 "ext/date/lib/parse_date.c" +#line 12993 "ext/date/lib/parse_date.c" yy695: YYDEBUG(695, *YYCURSOR); yyaccept = 12; @@ -12944,7 +13002,7 @@ } yy696: YYDEBUG(696, *YYCURSOR); -#line 990 "ext/date/lib/parse_date.re" +#line 1048 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("timeshort24 | timelong24 | iso8601long"); @@ -12969,7 +13027,7 @@ TIMELIB_DEINIT; return TIMELIB_TIME24_WITH_ZONE; } -#line 12973 "ext/date/lib/parse_date.c" +#line 13031 "ext/date/lib/parse_date.c" yy697: YYDEBUG(697, *YYCURSOR); yyaccept = 12; @@ -13237,7 +13295,7 @@ if(yych <= '9') goto yy730; yy724: YYDEBUG(724, *YYCURSOR); -#line 1147 "ext/date/lib/parse_date.re" +#line 1205 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datefull"); TIMELIB_INIT; @@ -13250,7 +13308,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_FULL; } -#line 13254 "ext/date/lib/parse_date.c" +#line 13312 "ext/date/lib/parse_date.c" yy725: YYDEBUG(725, *YYCURSOR); yych = *++YYCURSOR; @@ -14006,7 +14064,7 @@ if(yych <= '9') goto yy797; yy796: YYDEBUG(796, *YYCURSOR); -#line 1173 "ext/date/lib/parse_date.re" +#line 1231 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YY"); TIMELIB_INIT; @@ -14018,7 +14076,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 14022 "ext/date/lib/parse_date.c" +#line 14080 "ext/date/lib/parse_date.c" yy797: YYDEBUG(797, *YYCURSOR); yych = *++YYCURSOR; @@ -14027,7 +14085,7 @@ YYDEBUG(798, *YYCURSOR); ++YYCURSOR; YYDEBUG(799, *YYCURSOR); -#line 1161 "ext/date/lib/parse_date.re" +#line 1219 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pointed date YYYY"); TIMELIB_INIT; @@ -14038,7 +14096,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_FULL_POINTED; } -#line 14042 "ext/date/lib/parse_date.c" +#line 14100 "ext/date/lib/parse_date.c" yy800: YYDEBUG(800, *YYCURSOR); yyaccept = 12; @@ -14656,7 +14714,7 @@ } yy844: YYDEBUG(844, *YYCURSOR); -#line 1134 "ext/date/lib/parse_date.re" +#line 1192 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnudateshort"); TIMELIB_INIT; @@ -14668,7 +14726,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 14672 "ext/date/lib/parse_date.c" +#line 14730 "ext/date/lib/parse_date.c" yy845: YYDEBUG(845, *YYCURSOR); yyaccept = 14; @@ -14774,7 +14832,7 @@ } yy854: YYDEBUG(854, *YYCURSOR); -#line 1082 "ext/date/lib/parse_date.re" +#line 1140 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("americanshort | american"); TIMELIB_INIT; @@ -14788,7 +14846,7 @@ TIMELIB_DEINIT; return TIMELIB_AMERICAN; } -#line 14792 "ext/date/lib/parse_date.c" +#line 14850 "ext/date/lib/parse_date.c" yy855: YYDEBUG(855, *YYCURSOR); yyaccept = 15; @@ -15011,7 +15069,7 @@ if(yych <= ':') goto yy890; yy887: YYDEBUG(887, *YYCURSOR); -#line 1352 "ext/date/lib/parse_date.re" +#line 1410 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("clf"); @@ -15031,7 +15089,7 @@ TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 15035 "ext/date/lib/parse_date.c" +#line 15093 "ext/date/lib/parse_date.c" yy888: YYDEBUG(888, *YYCURSOR); yych = *++YYCURSOR; @@ -15526,7 +15584,7 @@ } yy942: YYDEBUG(942, *YYCURSOR); -#line 1109 "ext/date/lib/parse_date.re" +#line 1167 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("iso8601date2"); TIMELIB_INIT; @@ -15538,7 +15596,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 15542 "ext/date/lib/parse_date.c" +#line 15600 "ext/date/lib/parse_date.c" yy943: YYDEBUG(943, *YYCURSOR); yych = *++YYCURSOR; @@ -15577,7 +15635,7 @@ YYDEBUG(949, *YYCURSOR); ++YYCURSOR; YYDEBUG(950, *YYCURSOR); -#line 1339 "ext/date/lib/parse_date.re" +#line 1397 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pgtextreverse"); TIMELIB_INIT; @@ -15589,7 +15647,7 @@ TIMELIB_DEINIT; return TIMELIB_PG_TEXT; } -#line 15593 "ext/date/lib/parse_date.c" +#line 15651 "ext/date/lib/parse_date.c" yy951: YYDEBUG(951, *YYCURSOR); yych = *++YYCURSOR; @@ -15727,7 +15785,7 @@ } yy962: YYDEBUG(962, *YYCURSOR); -#line 1373 "ext/date/lib/parse_date.re" +#line 1431 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("year4"); TIMELIB_INIT; @@ -15735,7 +15793,7 @@ TIMELIB_DEINIT; return TIMELIB_CLF; } -#line 15739 "ext/date/lib/parse_date.c" +#line 15797 "ext/date/lib/parse_date.c" yy963: YYDEBUG(963, *YYCURSOR); yych = *++YYCURSOR; @@ -15886,7 +15944,7 @@ } yy972: YYDEBUG(972, *YYCURSOR); -#line 1199 "ext/date/lib/parse_date.re" +#line 1257 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenodayrev"); TIMELIB_INIT; @@ -15898,7 +15956,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_NO_DAY; } -#line 15902 "ext/date/lib/parse_date.c" +#line 15960 "ext/date/lib/parse_date.c" yy973: YYDEBUG(973, *YYCURSOR); yych = *++YYCURSOR; @@ -16113,7 +16171,7 @@ if(yych <= '7') goto yy995; yy993: YYDEBUG(993, *YYCURSOR); -#line 1307 "ext/date/lib/parse_date.re" +#line 1365 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweek"); @@ -16131,7 +16189,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 16135 "ext/date/lib/parse_date.c" +#line 16193 "ext/date/lib/parse_date.c" yy994: YYDEBUG(994, *YYCURSOR); yych = *++YYCURSOR; @@ -16141,7 +16199,7 @@ YYDEBUG(995, *YYCURSOR); ++YYCURSOR; YYDEBUG(996, *YYCURSOR); -#line 1288 "ext/date/lib/parse_date.re" +#line 1346 "ext/date/lib/parse_date.re" { timelib_sll w, d; DEBUG_OUTPUT("isoweekday"); @@ -16159,7 +16217,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_WEEK; } -#line 16163 "ext/date/lib/parse_date.c" +#line 16221 "ext/date/lib/parse_date.c" yy997: YYDEBUG(997, *YYCURSOR); yych = *++YYCURSOR; @@ -16223,7 +16281,7 @@ } yy1000: YYDEBUG(1000, *YYCURSOR); -#line 1275 "ext/date/lib/parse_date.re" +#line 1333 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("pgydotd"); TIMELIB_INIT; @@ -16235,7 +16293,7 @@ TIMELIB_DEINIT; return TIMELIB_PG_YEARDAY; } -#line 16239 "ext/date/lib/parse_date.c" +#line 16297 "ext/date/lib/parse_date.c" yy1001: YYDEBUG(1001, *YYCURSOR); yych = *++YYCURSOR; @@ -16338,7 +16396,7 @@ ++YYCURSOR; yy1021: YYDEBUG(1021, *YYCURSOR); -#line 1249 "ext/date/lib/parse_date.re" +#line 1307 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif"); @@ -16363,7 +16421,7 @@ TIMELIB_DEINIT; return TIMELIB_XMLRPC_SOAP; } -#line 16367 "ext/date/lib/parse_date.c" +#line 16425 "ext/date/lib/parse_date.c" yy1022: YYDEBUG(1022, *YYCURSOR); yych = *++YYCURSOR; @@ -16625,7 +16683,7 @@ } yy1027: YYDEBUG(1027, *YYCURSOR); -#line 1237 "ext/date/lib/parse_date.re" +#line 1295 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("datenocolon"); TIMELIB_INIT; @@ -16636,7 +16694,7 @@ TIMELIB_DEINIT; return TIMELIB_DATE_NOCOLON; } -#line 16640 "ext/date/lib/parse_date.c" +#line 16698 "ext/date/lib/parse_date.c" yy1028: YYDEBUG(1028, *YYCURSOR); yych = *++YYCURSOR; @@ -17556,7 +17614,7 @@ if(yych <= '9') goto yy1174; yy1152: YYDEBUG(1152, *YYCURSOR); -#line 1122 "ext/date/lib/parse_date.re" +#line 1180 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnudateshorter"); TIMELIB_INIT; @@ -17567,7 +17625,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_DATE; } -#line 17571 "ext/date/lib/parse_date.c" +#line 17629 "ext/date/lib/parse_date.c" yy1153: YYDEBUG(1153, *YYCURSOR); yyaccept = 23; @@ -18558,7 +18616,7 @@ } yy1243: YYDEBUG(1243, *YYCURSOR); -#line 1016 "ext/date/lib/parse_date.re" +#line 1074 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("gnunocolon"); TIMELIB_INIT; @@ -18580,7 +18638,7 @@ TIMELIB_DEINIT; return TIMELIB_GNU_NOCOLON; } -#line 18584 "ext/date/lib/parse_date.c" +#line 18642 "ext/date/lib/parse_date.c" yy1244: YYDEBUG(1244, *YYCURSOR); yych = *++YYCURSOR; @@ -18672,7 +18730,7 @@ } yy1251: YYDEBUG(1251, *YYCURSOR); -#line 1062 "ext/date/lib/parse_date.re" +#line 1120 "ext/date/lib/parse_date.re" { int tz_not_found; DEBUG_OUTPUT("iso8601nocolon"); @@ -18691,7 +18749,7 @@ TIMELIB_DEINIT; return TIMELIB_ISO_NOCOLON; } -#line 18695 "ext/date/lib/parse_date.c" +#line 18753 "ext/date/lib/parse_date.c" yy1252: YYDEBUG(1252, *YYCURSOR); yyaccept = 26; @@ -19311,7 +19369,7 @@ if(yych <= '9') goto yy1274; yy1276: YYDEBUG(1276, *YYCURSOR); -#line 949 "ext/date/lib/parse_date.re" +#line 1007 "ext/date/lib/parse_date.re" { timelib_ull i; @@ -19334,7 +19392,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 19338 "ext/date/lib/parse_date.c" +#line 19396 "ext/date/lib/parse_date.c" yy1277: YYDEBUG(1277, *YYCURSOR); yych = *++YYCURSOR; @@ -19770,7 +19828,7 @@ ++YYCURSOR; yy1306: YYDEBUG(1306, *YYCURSOR); -#line 937 "ext/date/lib/parse_date.re" +#line 995 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("tomorrow"); TIMELIB_INIT; @@ -19781,7 +19839,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 19785 "ext/date/lib/parse_date.c" +#line 19843 "ext/date/lib/parse_date.c" yy1307: YYDEBUG(1307, *YYCURSOR); yych = *++YYCURSOR; @@ -19816,7 +19874,7 @@ } yy1309: YYDEBUG(1309, *YYCURSOR); -#line 927 "ext/date/lib/parse_date.re" +#line 985 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("midnight | today"); TIMELIB_INIT; @@ -19825,7 +19883,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 19829 "ext/date/lib/parse_date.c" +#line 19887 "ext/date/lib/parse_date.c" yy1310: YYDEBUG(1310, *YYCURSOR); yych = *++YYCURSOR; @@ -21598,7 +21656,7 @@ } yy1387: YYDEBUG(1387, *YYCURSOR); -#line 906 "ext/date/lib/parse_date.re" +#line 964 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("now"); TIMELIB_INIT; @@ -21606,7 +21664,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21610 "ext/date/lib/parse_date.c" +#line 21668 "ext/date/lib/parse_date.c" yy1388: YYDEBUG(1388, *YYCURSOR); yych = *++YYCURSOR; @@ -21745,7 +21803,7 @@ } yy1395: YYDEBUG(1395, *YYCURSOR); -#line 915 "ext/date/lib/parse_date.re" +#line 973 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("noon"); TIMELIB_INIT; @@ -21756,7 +21814,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 21760 "ext/date/lib/parse_date.c" +#line 21818 "ext/date/lib/parse_date.c" yy1396: YYDEBUG(1396, *YYCURSOR); yyaccept = 0; @@ -22236,7 +22294,7 @@ ++YYCURSOR; yy1418: YYDEBUG(1418, *YYCURSOR); -#line 894 "ext/date/lib/parse_date.re" +#line 952 "ext/date/lib/parse_date.re" { DEBUG_OUTPUT("yesterday"); TIMELIB_INIT; @@ -22247,7 +22305,7 @@ TIMELIB_DEINIT; return TIMELIB_RELATIVE; } -#line 22251 "ext/date/lib/parse_date.c" +#line 22309 "ext/date/lib/parse_date.c" yy1419: YYDEBUG(1419, *YYCURSOR); yyaccept = 0; @@ -22394,7 +22452,7 @@ } } } -#line 1542 "ext/date/lib/parse_date.re" +#line 1600 "ext/date/lib/parse_date.re" } @@ -22470,6 +22528,208 @@ return in.time; } +#define TIMELIB_CHECK_NUMBER \ + if (strchr("0123456789", *ptr) == NULL) \ + { \ + add_pbf_error(s, "Unexpected data found.", string, begin); \ + } + + +timelib_time *timelib_parse_from_format(char *format, char *string, int len, timelib_error_container **errors, const timelib_tzdb *tzdb) +{ + char *fptr = format; + char *ptr = string; + char *begin; + timelib_sll tmp; + Scanner in; + Scanner *s = ∈ + + memset(&in, 0, sizeof(in)); + in.errors = malloc(sizeof(struct timelib_error_container)); + in.errors->warning_count = 0; + in.errors->warning_messages = NULL; + in.errors->error_count = 0; + in.errors->error_messages = NULL; + + in.time = timelib_time_ctor(); + in.time->y = TIMELIB_UNSET; + in.time->d = TIMELIB_UNSET; + in.time->m = TIMELIB_UNSET; + in.time->h = TIMELIB_UNSET; + in.time->i = TIMELIB_UNSET; + in.time->s = TIMELIB_UNSET; + in.time->f = TIMELIB_UNSET; + in.time->z = TIMELIB_UNSET; + in.time->dst = TIMELIB_UNSET; + in.tzdb = tzdb; + in.time->is_localtime = 0; + in.time->zone_type = 0; + + /* Loop over the format string */ + while (*fptr && *ptr) { + begin = ptr; + switch (*fptr) { + case 'd': // two digit day, with leading zero + case 'j': // two digit day, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->d = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit day could not be found", string, begin); + } + break; + case 'S': // day suffix, ignored, nor checked + timelib_skip_day_suffix((char **) &ptr); + break; + case 'z': // day of year - resets month (0 based) + TIMELIB_CHECK_NUMBER; + if ((tmp = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET) { + add_pbf_error(s, "A three digit day-of-year could not be found", string, begin); + } else { + s->time->m = 1; + s->time->d = tmp + 1; + } + break; + + case 'm': // two digit month, with leading zero + case 'n': // two digit month, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->m = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit month could not be found", string, begin); + } + break; + case 'M': // three letter month + case 'F': // full month + tmp = timelib_lookup_month((char **) &ptr); + if (!tmp) { + add_pbf_error(s, "A textual month could not be found", string, begin); + } else { + s->time->m = tmp; + } + break; + case 'y': // two digit year + TIMELIB_CHECK_NUMBER; + if ((s->time->y = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit year could not be found", string, begin); + } + TIMELIB_PROCESS_YEAR(s->time->y); + break; + case 'Y': // four digit year + TIMELIB_CHECK_NUMBER; + if ((s->time->y = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) { + add_pbf_error(s, "A four digit year could not be found", string, begin); + } + break; + case 'g': // two digit hour, with leading zero + case 'h': // two digit hour, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit hour could not be found", string, begin); + } + if (s->time->h > 12) { + add_pbf_error(s, "Hour can not be higher than 12", string, begin); + } + break; + case 'G': // two digit hour, with leading zero + case 'H': // two digit hour, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit hour could not be found", string, begin); + } + break; + case 'a': // am/pm/a.m./p.m. + case 'A': // AM/PM/A.M./P.M. + if (s->time->h == TIMELIB_UNSET) { + add_pbf_error(s, "Meridian can only come after an hour has been found", string, begin); + } else if ((tmp = timelib_meridian_with_check((char **) &ptr, s->time->h)) == TIMELIB_UNSET) { + add_pbf_error(s, "A meridian could no tbe found", string, begin); + } else { + s->time->h += tmp; + } + break; + case 'i': // two digit minute, with leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->i = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit minute could not be found", string, begin); + } + break; + case 's': // two digit second, with leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->s = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit second could not be found", string, begin); + } + break; + case 'u': // five digit millisecond, with leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->f = timelib_get_nr((char **) &ptr, 5)) == TIMELIB_UNSET) { + add_pbf_error(s, "A five digit millisecond could not be found", string, begin); + } + break; + case ' ': // any sort of whitespace (' ' and \t) + timelib_eat_spaces((char **) &ptr); + break; + case 'U': // epoch seconds + TIMELIB_CHECK_NUMBER; + TIMELIB_HAVE_RELATIVE(); + tmp = timelib_get_unsigned_nr((char **) &ptr, 24); + s->time->y = 1970; + s->time->m = 1; + s->time->d = 1; + s->time->h = s->time->i = s->time->s = 0; + s->time->f = 0.0; + s->time->relative.s += tmp; + s->time->is_localtime = 1; + s->time->zone_type = TIMELIB_ZONETYPE_OFFSET; + s->time->z = 0; + break; + + case 'e': // timezone + { + int tz_not_found; + s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb); + if (tz_not_found) { + add_pbf_error(s, "The timezone could not be found in the database", string, begin); + } + } + break; + + case '#': // separation symbol + if (*ptr == ';' || *ptr == ':' || *ptr == '/' || *ptr == '.' || *ptr == ',' || *ptr == '-') { + ++ptr; + } else { + add_pbf_error(s, "The seperation symbol ([;:/.,-]) could not be found", string, begin); + } + break; + + case '?': // random char + ++ptr; + break; + + case '*': // random chars until a seperator or number ([ \t.,:;/-0123456789]) + timelib_eat_until_seperator((char **) &ptr); + break; + + default: + if (*fptr != *ptr) { + add_pbf_error(s, "The format seperator does not match", string, begin); + } + ptr++; + } + fptr++; + } + if (*ptr) { + add_pbf_error(s, "Trailing data", string, ptr); + } + if (*fptr) { + add_pbf_error(s, "Data missing", string, ptr); + } + + if (errors) { + *errors = in.errors; + } else { + timelib_error_container_dtor(in.errors); + } + return in.time; +} + void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options) { if (!(options && TIMELIB_OVERRIDE_TIME) && parsed->have_date && !parsed->have_time) { http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/parse_date.re?r1=1.26.2.27.2.12&r2=1.26.2.27.2.12.2.1&diff_format=u Index: php-src/ext/date/lib/parse_date.re diff -u php-src/ext/date/lib/parse_date.re:1.26.2.27.2.12 php-src/ext/date/lib/parse_date.re:1.26.2.27.2.12.2.1 --- php-src/ext/date/lib/parse_date.re:1.26.2.27.2.12 Thu Jul 12 18:58:00 2007 +++ php-src/ext/date/lib/parse_date.re Sun Jan 13 15:16:02 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: parse_date.re,v 1.26.2.27.2.12 2007/07/12 18:58:00 derick Exp $ */ +/* $Id: parse_date.re,v 1.26.2.27.2.12.2.1 2008/01/13 15:16:02 derick Exp $ */ #include "timelib.h" @@ -349,6 +349,24 @@ s->errors->error_messages[s->errors->error_count - 1].message = strdup(error); } +static void add_pbf_warning(Scanner *s, char *error, char *sptr, char *cptr) +{ + s->errors->warning_count++; + s->errors->warning_messages = realloc(s->errors->warning_messages, s->errors->warning_count * sizeof(timelib_error_message)); + s->errors->warning_messages[s->errors->warning_count - 1].position = cptr - sptr; + s->errors->warning_messages[s->errors->warning_count - 1].character = *cptr; + s->errors->warning_messages[s->errors->warning_count - 1].message = strdup(error); +} + +static void add_pbf_error(Scanner *s, char *error, char *sptr, char *cptr) +{ + s->errors->error_count++; + s->errors->error_messages = realloc(s->errors->error_messages, s->errors->error_count * sizeof(timelib_error_message)); + s->errors->error_messages[s->errors->error_count - 1].position = cptr - sptr; + s->errors->error_messages[s->errors->error_count - 1].character = *cptr; + s->errors->error_messages[s->errors->error_count - 1].message = strdup(error); +} + static timelib_sll timelib_meridian(char **ptr, timelib_sll h) { timelib_sll retval = 0; @@ -372,6 +390,39 @@ return retval; } +static timelib_sll timelib_meridian_with_check(char **ptr, timelib_sll h) +{ + timelib_sll retval = 0; + + while (!strchr("AaPp", **ptr)) { + ++*ptr; + } + if (**ptr == 'a' || **ptr == 'A') { + if (h == 12) { + retval = -12; + } + } else if (h != 12) { + retval = 12; + } + ++*ptr; + if (**ptr == '.') { + ++*ptr; + if (**ptr != 'm' && **ptr != 'M') { + return TIMELIB_UNSET; + } + ++*ptr; + if (**ptr != '.' ) { + return TIMELIB_UNSET; + } + ++*ptr; + } else if (**ptr == 'm' || **ptr == 'M') { + ++*ptr; + } else { + return TIMELIB_UNSET; + } + return retval; +} + static char *timelib_string(Scanner *s) { char *tmp = calloc(1, s->cur - s->tok + 1); @@ -566,6 +617,13 @@ } } +static void timelib_eat_until_seperator(char **ptr) +{ + while (strchr(" \t.,:;/-0123456789", **ptr) == NULL) { + ++*ptr; + } +} + static const timelib_relunit* timelib_lookup_relunit(char **ptr) { char *word; @@ -1614,6 +1672,208 @@ return in.time; } +#define TIMELIB_CHECK_NUMBER \ + if (strchr("0123456789", *ptr) == NULL) \ + { \ + add_pbf_error(s, "Unexpected data found.", string, begin); \ + } + + +timelib_time *timelib_parse_from_format(char *format, char *string, int len, timelib_error_container **errors, const timelib_tzdb *tzdb) +{ + char *fptr = format; + char *ptr = string; + char *begin; + timelib_sll tmp; + Scanner in; + Scanner *s = ∈ + + memset(&in, 0, sizeof(in)); + in.errors = malloc(sizeof(struct timelib_error_container)); + in.errors->warning_count = 0; + in.errors->warning_messages = NULL; + in.errors->error_count = 0; + in.errors->error_messages = NULL; + + in.time = timelib_time_ctor(); + in.time->y = TIMELIB_UNSET; + in.time->d = TIMELIB_UNSET; + in.time->m = TIMELIB_UNSET; + in.time->h = TIMELIB_UNSET; + in.time->i = TIMELIB_UNSET; + in.time->s = TIMELIB_UNSET; + in.time->f = TIMELIB_UNSET; + in.time->z = TIMELIB_UNSET; + in.time->dst = TIMELIB_UNSET; + in.tzdb = tzdb; + in.time->is_localtime = 0; + in.time->zone_type = 0; + + /* Loop over the format string */ + while (*fptr && *ptr) { + begin = ptr; + switch (*fptr) { + case 'd': // two digit day, with leading zero + case 'j': // two digit day, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->d = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit day could not be found", string, begin); + } + break; + case 'S': // day suffix, ignored, nor checked + timelib_skip_day_suffix((char **) &ptr); + break; + case 'z': // day of year - resets month (0 based) + TIMELIB_CHECK_NUMBER; + if ((tmp = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET) { + add_pbf_error(s, "A three digit day-of-year could not be found", string, begin); + } else { + s->time->m = 1; + s->time->d = tmp + 1; + } + break; + + case 'm': // two digit month, with leading zero + case 'n': // two digit month, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->m = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit month could not be found", string, begin); + } + break; + case 'M': // three letter month + case 'F': // full month + tmp = timelib_lookup_month((char **) &ptr); + if (!tmp) { + add_pbf_error(s, "A textual month could not be found", string, begin); + } else { + s->time->m = tmp; + } + break; + case 'y': // two digit year + TIMELIB_CHECK_NUMBER; + if ((s->time->y = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit year could not be found", string, begin); + } + TIMELIB_PROCESS_YEAR(s->time->y); + break; + case 'Y': // four digit year + TIMELIB_CHECK_NUMBER; + if ((s->time->y = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) { + add_pbf_error(s, "A four digit year could not be found", string, begin); + } + break; + case 'g': // two digit hour, with leading zero + case 'h': // two digit hour, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit hour could not be found", string, begin); + } + if (s->time->h > 12) { + add_pbf_error(s, "Hour can not be higher than 12", string, begin); + } + break; + case 'G': // two digit hour, with leading zero + case 'H': // two digit hour, without leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit hour could not be found", string, begin); + } + break; + case 'a': // am/pm/a.m./p.m. + case 'A': // AM/PM/A.M./P.M. + if (s->time->h == TIMELIB_UNSET) { + add_pbf_error(s, "Meridian can only come after an hour has been found", string, begin); + } else if ((tmp = timelib_meridian_with_check((char **) &ptr, s->time->h)) == TIMELIB_UNSET) { + add_pbf_error(s, "A meridian could no tbe found", string, begin); + } else { + s->time->h += tmp; + } + break; + case 'i': // two digit minute, with leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->i = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit minute could not be found", string, begin); + } + break; + case 's': // two digit second, with leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->s = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) { + add_pbf_error(s, "A two digit second could not be found", string, begin); + } + break; + case 'u': // five digit millisecond, with leading zero + TIMELIB_CHECK_NUMBER; + if ((s->time->f = timelib_get_nr((char **) &ptr, 5)) == TIMELIB_UNSET) { + add_pbf_error(s, "A five digit millisecond could not be found", string, begin); + } + break; + case ' ': // any sort of whitespace (' ' and \t) + timelib_eat_spaces((char **) &ptr); + break; + case 'U': // epoch seconds + TIMELIB_CHECK_NUMBER; + TIMELIB_HAVE_RELATIVE(); + tmp = timelib_get_unsigned_nr((char **) &ptr, 24); + s->time->y = 1970; + s->time->m = 1; + s->time->d = 1; + s->time->h = s->time->i = s->time->s = 0; + s->time->f = 0.0; + s->time->relative.s += tmp; + s->time->is_localtime = 1; + s->time->zone_type = TIMELIB_ZONETYPE_OFFSET; + s->time->z = 0; + break; + + case 'e': // timezone + { + int tz_not_found; + s->time->z = timelib_get_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb); + if (tz_not_found) { + add_pbf_error(s, "The timezone could not be found in the database", string, begin); + } + } + break; + + case '#': // separation symbol + if (*ptr == ';' || *ptr == ':' || *ptr == '/' || *ptr == '.' || *ptr == ',' || *ptr == '-') { + ++ptr; + } else { + add_pbf_error(s, "The seperation symbol ([;:/.,-]) could not be found", string, begin); + } + break; + + case '?': // random char + ++ptr; + break; + + case '*': // random chars until a seperator or number ([ \t.,:;/-0123456789]) + timelib_eat_until_seperator((char **) &ptr); + break; + + default: + if (*fptr != *ptr) { + add_pbf_error(s, "The format seperator does not match", string, begin); + } + ptr++; + } + fptr++; + } + if (*ptr) { + add_pbf_error(s, "Trailing data", string, ptr); + } + if (*fptr) { + add_pbf_error(s, "Data missing", string, ptr); + } + + if (errors) { + *errors = in.errors; + } else { + timelib_error_container_dtor(in.errors); + } + return in.time; +} + void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options) { if (!(options && TIMELIB_OVERRIDE_TIME) && parsed->have_date && !parsed->have_time) { http://cvs.php.net/viewvc.cgi/php-src/ext/date/lib/timelib.h?r1=1.10.2.11.2.3.2.1&r2=1.10.2.11.2.3.2.2&diff_format=u Index: php-src/ext/date/lib/timelib.h diff -u php-src/ext/date/lib/timelib.h:1.10.2.11.2.3.2.1 php-src/ext/date/lib/timelib.h:1.10.2.11.2.3.2.2 --- php-src/ext/date/lib/timelib.h:1.10.2.11.2.3.2.1 Mon Dec 31 07:17:07 2007 +++ php-src/ext/date/lib/timelib.h Sun Jan 13 15:16:02 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: timelib.h,v 1.10.2.11.2.3.2.1 2007/12/31 07:17:07 sebastian Exp $ */ +/* $Id: timelib.h,v 1.10.2.11.2.3.2.2 2008/01/13 15:16:02 derick Exp $ */ #ifndef __TIMELIB_H__ #define __TIMELIB_H__ @@ -54,6 +54,7 @@ /* From parse_date.re */ timelib_time *timelib_strtotime(char *s, int len, timelib_error_container **errors, const timelib_tzdb *tzdb); +timelib_time *timelib_parse_from_format(char *format, char *s, int len, timelib_error_container **errors, const timelib_tzdb *tzdb); void timelib_fill_holes(timelib_time *parsed, timelib_time *now, int options); char *timelib_timezone_id_from_abbr(const char *abbr, long gmtoffset, int isdst); const timelib_tz_lookup_table *timelib_timezone_abbreviations_list(void);
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php