summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/date/lib/parse_date.c436
-rw-r--r--ext/date/lib/parse_date.re260
-rw-r--r--ext/date/lib/timelib.h1
-rw-r--r--ext/date/php_date.c160
-rw-r--r--ext/date/php_date.h4
5 files changed, 736 insertions, 125 deletions
diff --git a/ext/date/lib/parse_date.c b/ext/date/lib/parse_date.c
index 45c3df331a..244fe054d6 100644
--- a/ext/date/lib/parse_date.c
+++ b/ext/date/lib/parse_date.c
@@ -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"
/*
+----------------------------------------------------------------------+
@@ -351,6 +351,24 @@ static void add_error(Scanner *s, char *error)
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 @@ static timelib_sll timelib_meridian(char **ptr, timelib_sll h)
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_spaces(char **ptr)
}
}
+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 @@ static int scan(Scanner *s)
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 @@ std:
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 @@ yy2:
}
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 @@ yy3:
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 @@ yy11:
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 @@ yy45:
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 @@ yy48:
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 @@ yy68:
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 @@ yy69:
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 @@ yy173:
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 @@ yy174:
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 @@ yy275:
}
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 @@ yy276:
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 @@ yy302:
}
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 @@ yy303:
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 @@ yy307:
}
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 @@ yy308:
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 @@ yy331:
}
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 @@ yy332:
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 @@ yy385:
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 @@ yy385:
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 @@ yy401:
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 @@ yy402:
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 @@ yy471:
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 @@ yy473:
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 @@ yy557:
}
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 @@ yy558:
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 @@ yy659:
++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 @@ yy660:
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 @@ yy680:
}
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 @@ yy681:
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 @@ yy693:
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 @@ yy693:
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 @@ yy695:
}
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 @@ yy696:
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 @@ yy723:
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 @@ yy724:
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 @@ yy795:
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 @@ yy796:
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 @@ yy797:
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 @@ yy797:
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 @@ yy843:
}
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 @@ yy844:
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 @@ yy853:
}
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 @@ yy854:
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 @@ yy886:
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 @@ yy887:
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 @@ yy941:
}
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 @@ yy942:
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 @@ yy949:
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 @@ yy949:
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 @@ yy961:
}
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 @@ yy962:
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 @@ yy971:
}
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 @@ yy972:
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 @@ yy992:
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 @@ yy993:
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 @@ yy995:
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 @@ yy995:
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 @@ yy999:
}
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 @@ yy1000:
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 @@ yy1020:
++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 @@ yy1021:
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 @@ yy1026:
}
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 @@ yy1027:
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 @@ yy1151:
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 @@ yy1152:
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 @@ yy1241:
}
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 @@ yy1243:
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 @@ yy1250:
}
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 @@ yy1251:
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 @@ yy1274:
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 @@ yy1276:
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 @@ yy1305:
++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 @@ yy1306:
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 @@ yy1308:
}
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 @@ yy1309:
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 @@ yy1386:
}
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 @@ yy1387:
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 @@ yy1394:
}
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 @@ yy1395:
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 @@ yy1417:
++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 @@ yy1418:
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 @@ yy1424:
}
}
}
-#line 1542 "ext/date/lib/parse_date.re"
+#line 1600 "ext/date/lib/parse_date.re"
}
@@ -22470,6 +22528,208 @@ timelib_time* timelib_strtotime(char *s, int len, struct timelib_error_container
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 = &in;
+
+ 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) {
diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re
index 72816a955a..986fc9ce63 100644
--- a/ext/date/lib/parse_date.re
+++ b/ext/date/lib/parse_date.re
@@ -349,6 +349,24 @@ static void add_error(Scanner *s, char *error)
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 @@ static timelib_sll timelib_meridian(char **ptr, timelib_sll h)
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_spaces(char **ptr)
}
}
+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 @@ timelib_time* timelib_strtotime(char *s, int len, struct timelib_error_container
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 = &in;
+
+ 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) {
diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h
index da6fb58417..54612dc14d 100644
--- a/ext/date/lib/timelib.h
+++ b/ext/date/lib/timelib.h
@@ -54,6 +54,7 @@ void timelib_isoweek_from_date(timelib_sll y, timelib_sll m, timelib_sll d, time
/* 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);
diff --git a/ext/date/php_date.c b/ext/date/php_date.c
index 4ccad5b809..57f27bd3f7 100644
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@ -168,7 +168,10 @@ const zend_function_entry date_functions[] = {
/* 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_functions[] = {
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_MINIT_FUNCTION(date)
php_date_global_timezone_db = NULL;
php_date_global_timezone_db_enabled = 0;
-
+
+ DATEG(last_errors) = NULL;
return SUCCESS;
}
/* }}} */
@@ -520,6 +526,10 @@ PHP_MSHUTDOWN_FUNCTION(date)
{
UNREGISTER_INI_ENTRIES();
+ if (DATEG(last_errors)) {
+ timelib_error_container_dtor(DATEG(last_errors));
+ }
+
return SUCCESS;
}
/* }}} */
@@ -1634,7 +1644,18 @@ static zval * date_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
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 @@ static void date_initialize(php_date_obj *dateobj, /*const*/ char *time_str, int
}
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 @@ PHP_FUNCTION(date_create)
}
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_METHOD(DateTime, __construct)
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 @@ PHP_FUNCTION(date_parse)
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 @@ PHP_FUNCTION(date_parse)
}
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
*/
diff --git a/ext/date/php_date.h b/ext/date/php_date.h
index aff612f0db..ce2a44e90f 100644
--- a/ext/date/php_date.h
+++ b/ext/date/php_date.h
@@ -49,7 +49,10 @@ PHP_FUNCTION(getdate);
/* 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 @@ ZEND_BEGIN_MODULE_GLOBALS(date)
char *default_timezone;
char *timezone;
HashTable tzcache;
+ timelib_error_container *last_errors;
ZEND_END_MODULE_GLOBALS(date)
#ifdef ZTS