-/* Generated by re2c 0.15.3 on Wed Jan 31 11:51:51 2018 */
-#line 1 "ext/date/lib/parse_date.re"
+/* Generated by re2c 0.15.3 on Tue Oct 9 10:50:25 2018 */
+#line 1 "parse_date.re"
/*
* The MIT License (MIT)
*
* THE SOFTWARE.
*/
+/* $Id$ */
+
#include "timelib.h"
#include "timelib_private.h"
} Scanner;
typedef struct _timelib_lookup_table {
- const char *name;
- int type;
- int value;
+ const char *name;
+ int type;
+ int value;
} timelib_lookup_table;
typedef struct _timelib_relunit {
const timelib_relunit *tp, *value = NULL;
while (**ptr != '\0' && **ptr != ' ' && **ptr != ',' && **ptr != '\t' && **ptr != ';' && **ptr != ':' &&
- **ptr != '/' && **ptr != '.' && **ptr != '-' && **ptr != '(' && **ptr != ')' ) {
+ **ptr != '/' && **ptr != '.' && **ptr != '-' && **ptr != '(' && **ptr != ')' ) {
++*ptr;
}
end = *ptr;
return 0;
}
+static timelib_long timelib_parse_tz_minutes(char **ptr, timelib_time *t)
+{
+ timelib_long retval = TIMELIB_UNSET;
+ char *begin = *ptr;
+
+ /* First character must be +/- */
+ if (**ptr != '+' && **ptr != '-') {
+ return retval;
+ }
+
+ ++*ptr;
+ while (isdigit(**ptr)) {
+ ++*ptr;
+ }
+
+ if (*begin == '+') {
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ t->dst = 0;
+
+ retval = sMIN(strtol(begin + 1, NULL, 10));
+ } else if (*begin == '-') {
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ t->dst = 0;
+
+ retval = -1 * sMIN(strtol(begin + 1, NULL, 10));
+ }
+ return retval;
+}
+
timelib_long timelib_parse_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_wrapper)
{
timelib_tzinfo *res;
std:
s->tok = cursor;
s->len = 0;
-#line 981 "ext/date/lib/parse_date.re"
+#line 1012 "parse_date.re"
-#line 862 "<stdout>"
+#line 893 "<stdout>"
{
YYCTYPE yych;
unsigned int yyaccept = 0;
static const unsigned char yybm[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 100, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 100, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 128, 64, 160, 96, 0,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 0, 0, 0, 0, 0, 0,
- 0, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 0, 0, 0, 0, 0,
- 0, 24, 24, 24, 88, 24, 24, 24,
- 88, 24, 24, 24, 24, 24, 88, 24,
- 24, 24, 88, 88, 88, 24, 24, 24,
- 24, 24, 24, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 100, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 100, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 128, 64, 160, 96, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 0, 0, 0, 0, 0,
+ 0, 24, 24, 24, 88, 24, 24, 24,
+ 88, 24, 24, 24, 24, 24, 88, 24,
+ 24, 24, 88, 88, 88, 24, 24, 24,
+ 24, 24, 24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
YYDEBUG(0, *YYCURSOR);
if ((YYLIMIT - YYCURSOR) < 33) YYFILL(33);
}
yy3:
YYDEBUG(3, *YYCURSOR);
-#line 1689 "ext/date/lib/parse_date.re"
+#line 1720 "parse_date.re"
{
int tz_not_found;
DEBUG_OUTPUT("tzcorrection | tz");
TIMELIB_DEINIT;
return TIMELIB_TIMEZONE;
}
-#line 1013 "<stdout>"
+#line 1044 "<stdout>"
yy4:
YYDEBUG(4, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '9') goto yy1377;
yy12:
YYDEBUG(12, *YYCURSOR);
-#line 1784 "ext/date/lib/parse_date.re"
+#line 1815 "parse_date.re"
{
add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character");
goto std;
}
-#line 1327 "<stdout>"
+#line 1358 "<stdout>"
yy13:
YYDEBUG(13, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '9') goto yy54;
yy49:
YYDEBUG(49, *YYCURSOR);
-#line 1773 "ext/date/lib/parse_date.re"
+#line 1804 "parse_date.re"
{
goto std;
}
-#line 2575 "<stdout>"
+#line 2606 "<stdout>"
yy50:
YYDEBUG(50, *YYCURSOR);
yych = *++YYCURSOR;
YYDEBUG(51, *YYCURSOR);
++YYCURSOR;
YYDEBUG(52, *YYCURSOR);
-#line 1778 "ext/date/lib/parse_date.re"
+#line 1809 "parse_date.re"
{
s->pos = cursor; s->line++;
goto std;
}
-#line 2589 "<stdout>"
+#line 2620 "<stdout>"
yy53:
YYDEBUG(53, *YYCURSOR);
yych = *++YYCURSOR;
if (yych == 's') goto yy75;
yy74:
YYDEBUG(74, *YYCURSOR);
-#line 1757 "ext/date/lib/parse_date.re"
+#line 1788 "parse_date.re"
{
timelib_ull i;
DEBUG_OUTPUT("relative");
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 3040 "<stdout>"
+#line 3071 "<stdout>"
yy75:
YYDEBUG(75, *YYCURSOR);
yych = *++YYCURSOR;
}
yy191:
YYDEBUG(191, *YYCURSOR);
-#line 1620 "ext/date/lib/parse_date.re"
+#line 1651 "parse_date.re"
{
const timelib_relunit* relunit;
DEBUG_OUTPUT("daytext");
TIMELIB_DEINIT;
return TIMELIB_WEEKDAY;
}
-#line 3960 "<stdout>"
+#line 3991 "<stdout>"
yy192:
YYDEBUG(192, *YYCURSOR);
yych = *++YYCURSOR;
}
yy218:
YYDEBUG(218, *YYCURSOR);
-#line 1679 "ext/date/lib/parse_date.re"
+#line 1710 "parse_date.re"
{
DEBUG_OUTPUT("monthtext");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_DATE_TEXT;
}
-#line 4489 "<stdout>"
+#line 4520 "<stdout>"
yy219:
YYDEBUG(219, *YYCURSOR);
++YYCURSOR;
goto yy237;
yy232:
YYDEBUG(232, *YYCURSOR);
-#line 1425 "ext/date/lib/parse_date.re"
+#line 1456 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("datetextual | datenoyear");
TIMELIB_DEINIT;
return TIMELIB_DATE_TEXT;
}
-#line 4751 "<stdout>"
+#line 4782 "<stdout>"
yy233:
YYDEBUG(233, *YYCURSOR);
yyaccept = 6;
}
yy246:
YYDEBUG(246, *YYCURSOR);
-#line 1727 "ext/date/lib/parse_date.re"
+#line 1758 "parse_date.re"
{
int tz_not_found;
DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz");
TIMELIB_DEINIT;
return TIMELIB_SHORTDATE_WITH_TIME;
}
-#line 4907 "<stdout>"
+#line 4938 "<stdout>"
yy247:
YYDEBUG(247, *YYCURSOR);
yyaccept = 7;
YYDEBUG(270, *YYCURSOR);
++YYCURSOR;
YYDEBUG(271, *YYCURSOR);
-#line 1703 "ext/date/lib/parse_date.re"
+#line 1734 "parse_date.re"
{
DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_SHORTDATE_WITH_TIME;
}
-#line 5228 "<stdout>"
+#line 5259 "<stdout>"
yy272:
YYDEBUG(272, *YYCURSOR);
yych = *++YYCURSOR;
YYDEBUG(321, *YYCURSOR);
++YYCURSOR;
YYDEBUG(322, *YYCURSOR);
-#line 1397 "ext/date/lib/parse_date.re"
+#line 1428 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("datenoday");
TIMELIB_DEINIT;
return TIMELIB_DATE_NO_DAY;
}
-#line 5848 "<stdout>"
+#line 5879 "<stdout>"
yy323:
YYDEBUG(323, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '9') goto yy331;
yy330:
YYDEBUG(330, *YYCURSOR);
-#line 1541 "ext/date/lib/parse_date.re"
+#line 1572 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("pgtextshort");
TIMELIB_DEINIT;
return TIMELIB_PG_TEXT;
}
-#line 6092 "<stdout>"
+#line 6123 "<stdout>"
yy331:
YYDEBUG(331, *YYCURSOR);
yych = *++YYCURSOR;
}
yy357:
YYDEBUG(357, *YYCURSOR);
-#line 1599 "ext/date/lib/parse_date.re"
+#line 1630 "parse_date.re"
{
DEBUG_OUTPUT("ago");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_AGO;
}
-#line 6694 "<stdout>"
+#line 6725 "<stdout>"
yy358:
YYDEBUG(358, *YYCURSOR);
yyaccept = 5;
++YYCURSOR;
yy419:
YYDEBUG(419, *YYCURSOR);
-#line 1302 "ext/date/lib/parse_date.re"
+#line 1333 "parse_date.re"
{
DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_ISO_DATE;
}
-#line 8488 "<stdout>"
+#line 8519 "<stdout>"
yy420:
YYDEBUG(420, *YYCURSOR);
yyaccept = 0;
}
yy440:
YYDEBUG(440, *YYCURSOR);
-#line 1439 "ext/date/lib/parse_date.re"
+#line 1470 "parse_date.re"
{
DEBUG_OUTPUT("datenoyearrev");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_DATE_TEXT;
}
-#line 9143 "<stdout>"
+#line 9174 "<stdout>"
yy441:
YYDEBUG(441, *YYCURSOR);
yyaccept = 9;
YYDEBUG(452, *YYCURSOR);
++YYCURSOR;
YYDEBUG(453, *YYCURSOR);
-#line 1157 "ext/date/lib/parse_date.re"
+#line 1188 "parse_date.re"
{
DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_TIME12;
}
-#line 9300 "<stdout>"
+#line 9331 "<stdout>"
yy454:
YYDEBUG(454, *YYCURSOR);
yyaccept = 10;
}
yy455:
YYDEBUG(455, *YYCURSOR);
-#line 1194 "ext/date/lib/parse_date.re"
+#line 1225 "parse_date.re"
{
int tz_not_found;
DEBUG_OUTPUT("timeshort24 | timelong24 | iso8601long");
TIMELIB_DEINIT;
return TIMELIB_TIME24_WITH_ZONE;
}
-#line 9338 "<stdout>"
+#line 9369 "<stdout>"
yy456:
YYDEBUG(456, *YYCURSOR);
yyaccept = 10;
YYDEBUG(487, *YYCURSOR);
++YYCURSOR;
YYDEBUG(488, *YYCURSOR);
-#line 1174 "ext/date/lib/parse_date.re"
+#line 1205 "parse_date.re"
{
DEBUG_OUTPUT("mssqltime");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_TIME24_WITH_ZONE;
}
-#line 9667 "<stdout>"
+#line 9698 "<stdout>"
yy489:
YYDEBUG(489, *YYCURSOR);
yyaccept = 10;
if (yych <= '9') goto yy505;
yy499:
YYDEBUG(499, *YYCURSOR);
-#line 1356 "ext/date/lib/parse_date.re"
+#line 1387 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("datefull");
TIMELIB_DEINIT;
return TIMELIB_DATE_FULL;
}
-#line 9787 "<stdout>"
+#line 9818 "<stdout>"
yy500:
YYDEBUG(500, *YYCURSOR);
yych = *++YYCURSOR;
YYDEBUG(570, *YYCURSOR);
++YYCURSOR;
YYDEBUG(571, *YYCURSOR);
-#line 1371 "ext/date/lib/parse_date.re"
+#line 1402 "parse_date.re"
{
DEBUG_OUTPUT("pointed date YYYY");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_DATE_FULL_POINTED;
}
-#line 10534 "<stdout>"
+#line 10565 "<stdout>"
yy572:
YYDEBUG(572, *YYCURSOR);
yyaccept = 10;
if (yych <= '9') goto yy569;
yy576:
YYDEBUG(576, *YYCURSOR);
-#line 1383 "ext/date/lib/parse_date.re"
+#line 1414 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("pointed date YY");
TIMELIB_DEINIT;
return TIMELIB_DATE_FULL_POINTED;
}
-#line 10583 "<stdout>"
+#line 10614 "<stdout>"
yy577:
YYDEBUG(577, *YYCURSOR);
yyaccept = 10;
}
yy621:
YYDEBUG(621, *YYCURSOR);
-#line 1342 "ext/date/lib/parse_date.re"
+#line 1373 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("gnudateshort");
TIMELIB_DEINIT;
return TIMELIB_ISO_DATE;
}
-#line 11237 "<stdout>"
+#line 11268 "<stdout>"
yy622:
YYDEBUG(622, *YYCURSOR);
yyaccept = 12;
}
yy631:
YYDEBUG(631, *YYCURSOR);
-#line 1286 "ext/date/lib/parse_date.re"
+#line 1317 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("americanshort | american");
TIMELIB_DEINIT;
return TIMELIB_AMERICAN;
}
-#line 11358 "<stdout>"
+#line 11389 "<stdout>"
yy632:
YYDEBUG(632, *YYCURSOR);
yyaccept = 13;
if (yych <= ':') goto yy668;
yy665:
YYDEBUG(665, *YYCURSOR);
-#line 1569 "ext/date/lib/parse_date.re"
+#line 1600 "parse_date.re"
{
int tz_not_found;
DEBUG_OUTPUT("clf");
TIMELIB_DEINIT;
return TIMELIB_CLF;
}
-#line 11611 "<stdout>"
+#line 11642 "<stdout>"
yy666:
YYDEBUG(666, *YYCURSOR);
yych = *++YYCURSOR;
}
yy728:
YYDEBUG(728, *YYCURSOR);
-#line 1314 "ext/date/lib/parse_date.re"
+#line 1345 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("iso8601date2");
TIMELIB_DEINIT;
return TIMELIB_ISO_DATE;
}
-#line 12174 "<stdout>"
+#line 12205 "<stdout>"
yy729:
YYDEBUG(729, *YYCURSOR);
yych = *++YYCURSOR;
YYDEBUG(735, *YYCURSOR);
++YYCURSOR;
YYDEBUG(736, *YYCURSOR);
-#line 1555 "ext/date/lib/parse_date.re"
+#line 1586 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("pgtextreverse");
TIMELIB_DEINIT;
return TIMELIB_PG_TEXT;
}
-#line 12226 "<stdout>"
+#line 12257 "<stdout>"
yy737:
YYDEBUG(737, *YYCURSOR);
yych = *++YYCURSOR;
}
yy748:
YYDEBUG(748, *YYCURSOR);
-#line 1590 "ext/date/lib/parse_date.re"
+#line 1621 "parse_date.re"
{
DEBUG_OUTPUT("year4");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_CLF;
}
-#line 12399 "<stdout>"
+#line 12430 "<stdout>"
yy749:
YYDEBUG(749, *YYCURSOR);
yych = *++YYCURSOR;
}
yy758:
YYDEBUG(758, *YYCURSOR);
-#line 1411 "ext/date/lib/parse_date.re"
+#line 1442 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("datenodayrev");
TIMELIB_DEINIT;
return TIMELIB_DATE_NO_DAY;
}
-#line 12617 "<stdout>"
+#line 12648 "<stdout>"
yy759:
YYDEBUG(759, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '7') goto yy781;
yy779:
YYDEBUG(779, *YYCURSOR);
-#line 1522 "ext/date/lib/parse_date.re"
+#line 1553 "parse_date.re"
{
timelib_sll w, d;
DEBUG_OUTPUT("isoweek");
TIMELIB_DEINIT;
return TIMELIB_ISO_WEEK;
}
-#line 12856 "<stdout>"
+#line 12887 "<stdout>"
yy780:
YYDEBUG(780, *YYCURSOR);
yych = *++YYCURSOR;
YYDEBUG(781, *YYCURSOR);
++YYCURSOR;
YYDEBUG(782, *YYCURSOR);
-#line 1503 "ext/date/lib/parse_date.re"
+#line 1534 "parse_date.re"
{
timelib_sll w, d;
DEBUG_OUTPUT("isoweekday");
TIMELIB_DEINIT;
return TIMELIB_ISO_WEEK;
}
-#line 12884 "<stdout>"
+#line 12915 "<stdout>"
yy783:
YYDEBUG(783, *YYCURSOR);
yych = *++YYCURSOR;
}
yy786:
YYDEBUG(786, *YYCURSOR);
-#line 1489 "ext/date/lib/parse_date.re"
+#line 1520 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("pgydotd");
TIMELIB_DEINIT;
return TIMELIB_PG_YEARDAY;
}
-#line 12967 "<stdout>"
+#line 12998 "<stdout>"
yy787:
YYDEBUG(787, *YYCURSOR);
yych = *++YYCURSOR;
++YYCURSOR;
yy807:
YYDEBUG(807, *YYCURSOR);
-#line 1463 "ext/date/lib/parse_date.re"
+#line 1494 "parse_date.re"
{
int tz_not_found;
DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif");
TIMELIB_DEINIT;
return TIMELIB_XMLRPC_SOAP;
}
-#line 13095 "<stdout>"
+#line 13126 "<stdout>"
yy808:
YYDEBUG(808, *YYCURSOR);
yych = *++YYCURSOR;
}
yy813:
YYDEBUG(813, *YYCURSOR);
-#line 1451 "ext/date/lib/parse_date.re"
+#line 1482 "parse_date.re"
{
DEBUG_OUTPUT("datenocolon");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_DATE_NOCOLON;
}
-#line 13401 "<stdout>"
+#line 13432 "<stdout>"
yy814:
YYDEBUG(814, *YYCURSOR);
yych = *++YYCURSOR;
if (yych <= '9') goto yy960;
yy938:
YYDEBUG(938, *YYCURSOR);
-#line 1328 "ext/date/lib/parse_date.re"
+#line 1359 "parse_date.re"
{
int length = 0;
DEBUG_OUTPUT("gnudateshorter");
TIMELIB_DEINIT;
return TIMELIB_ISO_DATE;
}
-#line 14333 "<stdout>"
+#line 14364 "<stdout>"
yy939:
YYDEBUG(939, *YYCURSOR);
yyaccept = 21;
}
yy1032:
YYDEBUG(1032, *YYCURSOR);
-#line 1220 "ext/date/lib/parse_date.re"
+#line 1251 "parse_date.re"
{
DEBUG_OUTPUT("gnunocolon");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_GNU_NOCOLON;
}
-#line 15448 "<stdout>"
+#line 15479 "<stdout>"
yy1033:
YYDEBUG(1033, *YYCURSOR);
yych = *++YYCURSOR;
}
yy1040:
YYDEBUG(1040, *YYCURSOR);
-#line 1266 "ext/date/lib/parse_date.re"
+#line 1297 "parse_date.re"
{
int tz_not_found;
DEBUG_OUTPUT("iso8601nocolon");
TIMELIB_DEINIT;
return TIMELIB_ISO_NOCOLON;
}
-#line 15565 "<stdout>"
+#line 15596 "<stdout>"
yy1041:
YYDEBUG(1041, *YYCURSOR);
yyaccept = 24;
}
yy1084:
YYDEBUG(1084, *YYCURSOR);
-#line 1662 "ext/date/lib/parse_date.re"
+#line 1693 "parse_date.re"
{
timelib_sll i;
int behavior = 0;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 16557 "<stdout>"
+#line 16588 "<stdout>"
yy1085:
YYDEBUG(1085, *YYCURSOR);
++YYCURSOR;
YYDEBUG(1092, *YYCURSOR);
++YYCURSOR;
YYDEBUG(1093, *YYCURSOR);
-#line 1135 "ext/date/lib/parse_date.re"
+#line 1166 "parse_date.re"
{
timelib_sll i;
int behavior = 0;
TIMELIB_DEINIT;
return TIMELIB_WEEK_DAY_OF_MONTH;
}
-#line 16629 "<stdout>"
+#line 16660 "<stdout>"
yy1094:
YYDEBUG(1094, *YYCURSOR);
yyaccept = 25;
}
yy1108:
YYDEBUG(1108, *YYCURSOR);
-#line 1638 "ext/date/lib/parse_date.re"
+#line 1669 "parse_date.re"
{
timelib_sll i;
int behavior = 0;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 16760 "<stdout>"
+#line 16791 "<stdout>"
yy1109:
YYDEBUG(1109, *YYCURSOR);
yych = *++YYCURSOR;
}
yy1284:
YYDEBUG(1284, *YYCURSOR);
-#line 1112 "ext/date/lib/parse_date.re"
+#line 1143 "parse_date.re"
{
DEBUG_OUTPUT("backof | frontof");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_LF_DAY_OF_MONTH;
}
-#line 19631 "<stdout>"
+#line 19662 "<stdout>"
yy1285:
YYDEBUG(1285, *YYCURSOR);
yyaccept = 27;
YYDEBUG(1306, *YYCURSOR);
++YYCURSOR;
YYDEBUG(1307, *YYCURSOR);
-#line 1095 "ext/date/lib/parse_date.re"
+#line 1126 "parse_date.re"
{
DEBUG_OUTPUT("firstdayof | lastdayof");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_LF_DAY_OF_MONTH;
}
-#line 19946 "<stdout>"
+#line 19977 "<stdout>"
yy1308:
YYDEBUG(1308, *YYCURSOR);
yyaccept = 0;
if (yych <= '9') goto yy1377;
yy1379:
YYDEBUG(1379, *YYCURSOR);
-#line 1041 "ext/date/lib/parse_date.re"
+#line 1072 "parse_date.re"
{
timelib_ull i;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 21460 "<stdout>"
+#line 21491 "<stdout>"
yy1380:
YYDEBUG(1380, *YYCURSOR);
yych = *++YYCURSOR;
YYDEBUG(1386, *YYCURSOR);
++YYCURSOR;
YYDEBUG(1387, *YYCURSOR);
-#line 1067 "ext/date/lib/parse_date.re"
+#line 1098 "parse_date.re"
{
timelib_ull i, us;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 21516 "<stdout>"
+#line 21547 "<stdout>"
yy1388:
YYDEBUG(1388, *YYCURSOR);
yych = *++YYCURSOR;
++YYCURSOR;
yy1417:
YYDEBUG(1417, *YYCURSOR);
-#line 1029 "ext/date/lib/parse_date.re"
+#line 1060 "parse_date.re"
{
DEBUG_OUTPUT("tomorrow");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 21963 "<stdout>"
+#line 21994 "<stdout>"
yy1418:
YYDEBUG(1418, *YYCURSOR);
yych = *++YYCURSOR;
}
yy1420:
YYDEBUG(1420, *YYCURSOR);
-#line 1019 "ext/date/lib/parse_date.re"
+#line 1050 "parse_date.re"
{
DEBUG_OUTPUT("midnight | today");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 22007 "<stdout>"
+#line 22038 "<stdout>"
yy1421:
YYDEBUG(1421, *YYCURSOR);
yych = *++YYCURSOR;
}
yy1500:
YYDEBUG(1500, *YYCURSOR);
-#line 998 "ext/date/lib/parse_date.re"
+#line 1029 "parse_date.re"
{
DEBUG_OUTPUT("now");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 24027 "<stdout>"
+#line 24058 "<stdout>"
yy1501:
YYDEBUG(1501, *YYCURSOR);
yych = *++YYCURSOR;
}
yy1508:
YYDEBUG(1508, *YYCURSOR);
-#line 1007 "ext/date/lib/parse_date.re"
+#line 1038 "parse_date.re"
{
DEBUG_OUTPUT("noon");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 24177 "<stdout>"
+#line 24208 "<stdout>"
yy1509:
YYDEBUG(1509, *YYCURSOR);
yyaccept = 0;
++YYCURSOR;
yy1531:
YYDEBUG(1531, *YYCURSOR);
-#line 986 "ext/date/lib/parse_date.re"
+#line 1017 "parse_date.re"
{
DEBUG_OUTPUT("yesterday");
TIMELIB_INIT;
TIMELIB_DEINIT;
return TIMELIB_RELATIVE;
}
-#line 24721 "<stdout>"
+#line 24752 "<stdout>"
yy1532:
YYDEBUG(1532, *YYCURSOR);
yyaccept = 0;
goto yy1531;
}
}
-#line 1788 "ext/date/lib/parse_date.re"
+#line 1819 "parse_date.re"
}
if (time->us == TIMELIB_UNSET ) time->us = 0;
}
+static const timelib_format_specifier default_format_map[] = {
+ {'+', TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS},
+ {'#', TIMELIB_FORMAT_ANY_SEPARATOR},
+ {'j', TIMELIB_FORMAT_DAY_TWO_DIGIT},
+ {'d', TIMELIB_FORMAT_DAY_TWO_DIGIT_PADDED},
+ {'z', TIMELIB_FORMAT_DAY_OF_YEAR},
+ {'S', TIMELIB_FORMAT_DAY_SUFFIX},
+ {'U', TIMELIB_FORMAT_EPOCH_SECONDS},
+ {'\\', TIMELIB_FORMAT_ESCAPE},
+ {'h', TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX},
+ {'g', TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX_PADDED},
+ {'H', TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX},
+ {'G', TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX_PADDED},
+ {'a', TIMELIB_FORMAT_MERIDIAN},
+ {'A', TIMELIB_FORMAT_MERIDIAN},
+ {'u', TIMELIB_FORMAT_MICROSECOND_SIX_DIGIT},
+ {'v', TIMELIB_FORMAT_MILLISECOND_THREE_DIGIT},
+ {'i', TIMELIB_FORMAT_MINUTE_TWO_DIGIT},
+ {'n', TIMELIB_FORMAT_MONTH_TWO_DIGIT},
+ {'m', TIMELIB_FORMAT_MONTH_TWO_DIGIT_PADDED},
+ {'?', TIMELIB_FORMAT_RANDOM_CHAR},
+ {'!', TIMELIB_FORMAT_RESET_ALL},
+ {'|', TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET},
+ {'s', TIMELIB_FORMAT_SECOND_TWO_DIGIT},
+ {';', TIMELIB_FORMAT_SEPARATOR},
+ {':', TIMELIB_FORMAT_SEPARATOR},
+ {'/', TIMELIB_FORMAT_SEPARATOR},
+ {'.', TIMELIB_FORMAT_SEPARATOR},
+ {',', TIMELIB_FORMAT_SEPARATOR},
+ {'-', TIMELIB_FORMAT_SEPARATOR},
+ {'(', TIMELIB_FORMAT_SEPARATOR},
+ {')', TIMELIB_FORMAT_SEPARATOR},
+ {'*', TIMELIB_FORMAT_SKIP_TO_SEPARATOR},
+ {'D', TIMELIB_FORMAT_TEXTUAL_DAY_3_LETTER},
+ {'l', TIMELIB_FORMAT_TEXTUAL_DAY_FULL},
+ {'M', TIMELIB_FORMAT_TEXTUAL_MONTH_3_LETTER},
+ {'F', TIMELIB_FORMAT_TEXTUAL_MONTH_FULL},
+ {'e', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {'P', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {'T', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {'O', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {' ', TIMELIB_FORMAT_WHITESPACE},
+ {'y', TIMELIB_FORMAT_YEAR_TWO_DIGIT},
+ {'Y', TIMELIB_FORMAT_YEAR_FOUR_DIGIT},
+ {'\0', TIMELIB_FORMAT_END}
+};
+
+static const timelib_format_config default_format_config = {
+ default_format_map,
+ // No prefix required by default.
+ '\0'
+};
+
+static timelib_format_specifier_code timelib_lookup_format(char input, const timelib_format_specifier* format_map)
+{
+ while (format_map && format_map->specifier != '\0') {
+ if (format_map->specifier == input) {
+ return format_map->code;
+ }
+ format_map++;
+ }
+ return TIMELIB_FORMAT_LITERAL;
+}
+
timelib_time *timelib_parse_from_format(char *format, char *string, size_t len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper)
{
- char *fptr = format;
- char *ptr = string;
- char *begin;
- timelib_sll tmp;
- Scanner in;
- Scanner *s = ∈
- int allow_extra = 0;
+ return timelib_parse_from_format_with_map(format, string, len, errors, tzdb, tz_get_wrapper, &default_format_config);
+}
+
+timelib_time *timelib_parse_from_format_with_map(char *format, char *string, size_t len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper, const timelib_format_config* format_config)
+{
+ char *fptr = format;
+ char *ptr = string;
+ char *begin;
+ timelib_sll tmp;
+ Scanner in;
+ Scanner *s = ∈
+ bool allow_extra = false;
+ bool prefix_found = false;
+ int iso_year = TIMELIB_UNSET;
+ int iso_week_of_year = TIMELIB_UNSET;
+ int iso_day_of_week = TIMELIB_UNSET;
+ char prefix_char = format_config->prefix_char;
+ const timelib_format_specifier *format_map = format_config->format_map;
memset(&in, 0, sizeof(in));
in.errors = timelib_malloc(sizeof(timelib_error_container));
/* Loop over the format string */
while (*fptr && *ptr) {
begin = ptr;
- switch (*fptr) {
- case 'D': /* three letter day */
- case 'l': /* full day */
+
+ if (prefix_char) {
+ /* There are 2 cases where the input string and format string
+ * should match the next literal:
+ *
+ * 1. No prefix has been specified yet in the format, so expect 1:1
+ * match.
+ * 2. Sequential prefix characters indicating that the second
+ * prefix is escaped. (e.g. "%%" is expecting literal "%")
+ */
+ if ((!prefix_found && *fptr != prefix_char) ||
+ (prefix_found && *fptr == prefix_char)) {
+ if (*fptr != *ptr) {
+ add_pbf_error(s, TIMELIB_ERR_FORMAT_LITERAL_MISMATCH, "Format literal not found", string, begin);
+ }
+ ptr++;
+ fptr++;
+ prefix_found = false;
+ continue;
+ }
+
+ if (*fptr == prefix_char) {
+ fptr++;
+ prefix_found = true;
+ continue;
+ }
+
+ /* Fall through case is that the prefix has been found and the next
+ * character is the format specifier. */
+ prefix_found = false;
+ }
+
+ switch (timelib_lookup_format(*fptr, format_map)) {
+ case TIMELIB_FORMAT_TEXTUAL_DAY_3_LETTER: /* three letter day */
+ case TIMELIB_FORMAT_TEXTUAL_DAY_FULL: /* full day */
{
const timelib_relunit* tmprel = 0;
}
}
break;
- case 'd': /* two digit day, with leading zero */
- case 'j': /* two digit day, without leading zero */
+ case TIMELIB_FORMAT_DAY_TWO_DIGIT: /* two digit day, without leading zero */
+ case TIMELIB_FORMAT_DAY_TWO_DIGIT_PADDED: /* two digit day, with leading zero */
TIMELIB_CHECK_NUMBER;
if ((s->time->d = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_DAY, "A two digit day could not be found", string, begin);
}
break;
- case 'S': /* day suffix, ignored, nor checked */
+ case TIMELIB_FORMAT_DAY_SUFFIX: /* day suffix, ignored, nor checked */
timelib_skip_day_suffix((char **) &ptr);
break;
- case 'z': /* day of year - resets month (0 based) - also initializes everything else to !TIMELIB_UNSET */
+ case TIMELIB_FORMAT_DAY_OF_YEAR: /* day of year - resets month (0 based) - also initializes everything else to !TIMELIB_UNSET */
TIMELIB_CHECK_NUMBER;
if ((tmp = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_THREE_DIGIT_DAY_OF_YEAR, "A three digit day-of-year could not be found", string, begin);
}
break;
- case 'm': /* two digit month, with leading zero */
- case 'n': /* two digit month, without leading zero */
+ case TIMELIB_FORMAT_MONTH_TWO_DIGIT: /* two digit month, without leading zero */
+ case TIMELIB_FORMAT_MONTH_TWO_DIGIT_PADDED: /* two digit month, with leading zero */
TIMELIB_CHECK_NUMBER;
if ((s->time->m = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_MONTH, "A two digit month could not be found", string, begin);
}
break;
- case 'M': /* three letter month */
- case 'F': /* full month */
+ case TIMELIB_FORMAT_TEXTUAL_MONTH_3_LETTER: /* three letter month */
+ case TIMELIB_FORMAT_TEXTUAL_MONTH_FULL: /* full month */
tmp = timelib_lookup_month((char **) &ptr);
if (!tmp) {
add_pbf_error(s, TIMELIB_ERR_NO_TEXTUAL_MONTH, "A textual month could not be found", string, begin);
s->time->m = tmp;
}
break;
- case 'y': /* two digit year */
+ case TIMELIB_FORMAT_YEAR_TWO_DIGIT: /* two digit year */
{
int length = 0;
TIMELIB_CHECK_NUMBER;
TIMELIB_PROCESS_YEAR(s->time->y, length);
}
break;
- case 'Y': /* four digit year */
+ case TIMELIB_FORMAT_YEAR_FOUR_DIGIT: /* four digit year */
TIMELIB_CHECK_NUMBER;
if ((s->time->y = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_FOUR_DIGIT_YEAR, "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 */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX: /* two digit hour, without leading zero */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX_PADDED: /* two digit hour, with leading zero */
TIMELIB_CHECK_NUMBER;
if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_HOUR, "A two digit hour could not be found", string, begin);
add_pbf_error(s, TIMELIB_ERR_HOUR_LARGER_THAN_12, "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 */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX_PADDED: /* two digit hour, with leading zero */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX: /* 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, TIMELIB_ERR_NO_TWO_DIGIT_HOUR, "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. */
+ case TIMELIB_FORMAT_MERIDIAN: /* am/pm/a.m./p.m. AM/PM/A.M./P.M. */
if (s->time->h == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_MERIDIAN_BEFORE_HOUR, "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) {
s->time->h += tmp;
}
break;
- case 'i': /* two digit minute, with leading zero */
+ case TIMELIB_FORMAT_MINUTE_TWO_DIGIT: /* two digit minute, with leading zero */
{
int length;
timelib_sll min;
}
}
break;
- case 's': /* two digit second, with leading zero */
+ case TIMELIB_FORMAT_SECOND_TWO_DIGIT: /* two digit second, with leading zero */
{
int length;
timelib_sll sec;
}
}
break;
- case 'u': /* up to six digit microsecond */
+ case TIMELIB_FORMAT_MICROSECOND_SIX_DIGIT: /* up to six digit microsecond */
{
double f;
char *tptr;
}
}
break;
- case ' ': /* any sort of whitespace (' ' and \t) */
+ case TIMELIB_FORMAT_MILLISECOND_THREE_DIGIT: /* up to three digit millisecond */
+ {
+ double f;
+ char *tptr;
+
+ TIMELIB_CHECK_NUMBER;
+ tptr = ptr;
+ if ((f = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET || (ptr - tptr < 1)) {
+ add_pbf_error(s, TIMELIB_ERR_NO_THREE_DIGIT_MILLISECOND, "A three digit millisecond could not be found", string, begin);
+ } else {
+ s->time->us = (f * pow(10, 3 - (ptr - tptr)) * 1000);
+ }
+ }
+ break;
+ case TIMELIB_FORMAT_WHITESPACE: /* any sort of whitespace (' ' and \t) */
timelib_eat_spaces((char **) &ptr);
break;
- case 'U': /* epoch seconds */
+ case TIMELIB_FORMAT_EPOCH_SECONDS: /* epoch seconds */
TIMELIB_CHECK_SIGNED_NUMBER;
TIMELIB_HAVE_RELATIVE();
tmp = timelib_get_unsigned_nr((char **) &ptr, 24);
s->time->z = 0;
s->time->dst = 0;
break;
-
- case 'e': /* timezone */
- case 'P': /* timezone */
- case 'T': /* timezone */
- case 'O': /* timezone */
- {
- int tz_not_found;
- s->time->z = timelib_parse_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
- if (tz_not_found) {
- add_pbf_error(s, TIMELIB_ERR_TZID_NOT_FOUND, "The timezone could not be found in the database", string, begin);
- }
- }
- break;
-
- case '#': /* separation symbol */
- if (*ptr == ';' || *ptr == ':' || *ptr == '/' || *ptr == '.' || *ptr == ',' || *ptr == '-' || *ptr == '(' || *ptr == ')') {
+ case TIMELIB_FORMAT_ANY_SEPARATOR: /* separation symbol */
+ if (timelib_lookup_format(*ptr, format_map) == TIMELIB_FORMAT_SEPARATOR) {
++ptr;
} else {
add_pbf_error(s, TIMELIB_ERR_NO_SEP_SYMBOL, "The separation symbol ([;:/.,-]) could not be found", string, begin);
}
break;
- case ';':
- case ':':
- case '/':
- case '.':
- case ',':
- case '-':
- case '(':
- case ')':
+ case TIMELIB_FORMAT_SEPARATOR:
if (*ptr == *fptr) {
++ptr;
} else {
}
break;
- case '!': /* reset all fields to default */
+ case TIMELIB_FORMAT_RESET_ALL: /* reset all fields to default */
timelib_time_reset_fields(s->time);
break; /* break intentionally not missing */
- case '|': /* reset all fields to default when not set */
+ case TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET: /* reset all fields to default when not set */
timelib_time_reset_unset_fields(s->time);
break; /* break intentionally not missing */
- case '?': /* random char */
+ case TIMELIB_FORMAT_RANDOM_CHAR: /* random char */
++ptr;
break;
- case '\\': /* escaped char */
+ case TIMELIB_FORMAT_ESCAPE: /* escaped char */
if(!fptr[1]) {
add_pbf_error(s, TIMELIB_ERR_EXPECTED_ESCAPE_CHAR, "Escaped character expected", string, begin);
break;
}
break;
- case '*': /* random chars until a separator or number ([ \t.,:;/-0123456789]) */
+ case TIMELIB_FORMAT_SKIP_TO_SEPARATOR: /* random chars until a separator or number ([ \t.,:;/-0123456789]) */
timelib_eat_until_separator((char **) &ptr);
break;
- case '+': /* allow extra chars in the format */
- allow_extra = 1;
+ case TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS: /* allow extra chars in the format */
+ allow_extra = true;
+ break;
+ case TIMELIB_FORMAT_YEAR_ISO:
+ if ((iso_year = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_NO_FOUR_DIGIT_YEAR_ISO, "A four digit ISO year could not be found", string, begin);
+ }
+ break;
+ case TIMELIB_FORMAT_WEEK_OF_YEAR_ISO:
+ if ((iso_week_of_year = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_WEEK, "A two digit ISO week could not be found", string, begin);
+ }
+ /* Range is 1 - 53 for ISO week of year */
+ if (iso_week_of_year < 1 || iso_week_of_year > 53) {
+ add_pbf_error(s, TIMELIB_ERR_INVALID_WEEK, "ISO Week must be between 1 and 53", string, begin);
+ }
break;
+ case TIMELIB_FORMAT_DAY_OF_WEEK_ISO:
+ if ((iso_day_of_week = timelib_get_nr((char **) &ptr, 1)) == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_NO_DAY_OF_WEEK, "A single digit day of week could not be found", string, begin);
+ }
+ if (iso_day_of_week < 1 || iso_day_of_week > 7) {
+ add_pbf_error(s, TIMELIB_ERR_INVALID_DAY_OF_WEEK, "Day of week must be between 1 and 7", string, begin);
+ }
+ break;
+ case TIMELIB_FORMAT_TIMEZONE_OFFSET: /* timezone */
+ {
+ int tz_not_found;
+ s->time->z = timelib_parse_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
+ if (tz_not_found) {
+ add_pbf_error(s, TIMELIB_ERR_TZID_NOT_FOUND, "The timezone could not be found in the database", string, begin);
+ }
+ }
+ break;
+ case TIMELIB_FORMAT_TIMEZONE_OFFSET_MINUTES: /* timezone format +/-mmm */
+ s->time->z = timelib_parse_tz_minutes((char **) &ptr, s->time);
+ if (s->time->z == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_INVALID_TZ_OFFSET, "Invalid timezone offset in minutes", string, begin);
+ }
+ break;
+ case TIMELIB_FORMAT_LITERAL:
default:
if (*fptr != *ptr) {
add_pbf_error(s, TIMELIB_ERR_WRONG_FORMAT_SEP, "The format separator does not match", string, begin);
add_pbf_error(s, TIMELIB_ERR_TRAILING_DATA, "Trailing data", string, ptr);
}
}
- /* ignore trailing +'s */
- while (*fptr == '+') {
- fptr++;
- }
+
if (*fptr) {
- /* Trailing | and ! specifiers are valid. */
+ /* Trailing reset specifiers are valid. */
int done = 0;
while (*fptr && !done) {
- switch (*fptr++) {
- case '!': /* reset all fields to default */
+ switch (timelib_lookup_format(*fptr, format_map)) {
+ case TIMELIB_FORMAT_RESET_ALL: /* reset all fields to default */
timelib_time_reset_fields(s->time);
break;
- case '|': /* reset all fields to default when not set */
+ case TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET: /* reset all fields to default when not set */
timelib_time_reset_unset_fields(s->time);
break;
+ case TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS:
+ break;
default:
add_pbf_error(s, TIMELIB_ERR_DATA_MISSING, "Data missing", string, ptr);
done = 1;
}
+ fptr++;
}
}
/* clean up a bit */
- if (s->time->h != TIMELIB_UNSET || s->time->i != TIMELIB_UNSET || s->time->s != TIMELIB_UNSET) {
+ if (s->time->h != TIMELIB_UNSET || s->time->i != TIMELIB_UNSET || s->time->s != TIMELIB_UNSET || s->time->us != TIMELIB_UNSET) {
if (s->time->h == TIMELIB_UNSET ) {
s->time->h = 0;
}
if (s->time->s == TIMELIB_UNSET ) {
s->time->s = 0;
}
+ if (s->time->us == TIMELIB_UNSET ) {
+ s->time->us = 0;
+ }
+ }
+
+ /* Check for mixing of ISO dates with natural dates. */
+ if (s->time->y != TIMELIB_UNSET && (iso_week_of_year != TIMELIB_UNSET || iso_year != TIMELIB_UNSET || iso_day_of_week != TIMELIB_UNSET)) {
+ add_pbf_error(s, TIMELIB_ERR_MIX_ISO_WITH_NATURAL, "Mixing of ISO dates with natural dates is not allowed", string, ptr);
+ }
+ if (iso_year != TIMELIB_UNSET && (s->time->y != TIMELIB_UNSET || s->time->m != TIMELIB_UNSET || s->time->d != TIMELIB_UNSET)) {
+ add_pbf_error(s, TIMELIB_ERR_MIX_ISO_WITH_NATURAL, "Mixing of ISO dates with natural dates is not allowed", string, ptr);
+ }
+
+ /* Convert ISO values */
+ if (iso_year != TIMELIB_UNSET) {
+ /* Default week of year and day of week to 1. */
+ if (iso_week_of_year == TIMELIB_UNSET) {
+ iso_week_of_year = 1;
+ }
+ if (iso_day_of_week == TIMELIB_UNSET) {
+ iso_day_of_week = 1;
+ }
+ timelib_date_from_isodate(iso_year, iso_week_of_year, iso_day_of_week, &s->time->y, &s->time->m, &s->time->d);
+ } else if (iso_week_of_year != TIMELIB_UNSET || iso_day_of_week != TIMELIB_UNSET) {
+ add_pbf_warning(s, TIMELIB_WARN_INVALID_DATE, "The parsed date was invalid", string, ptr);
}
/* do funky checking whether the parsed time was valid time */
} Scanner;
typedef struct _timelib_lookup_table {
- const char *name;
- int type;
- int value;
+ const char *name;
+ int type;
+ int value;
} timelib_lookup_table;
typedef struct _timelib_relunit {
const timelib_relunit *tp, *value = NULL;
while (**ptr != '\0' && **ptr != ' ' && **ptr != ',' && **ptr != '\t' && **ptr != ';' && **ptr != ':' &&
- **ptr != '/' && **ptr != '.' && **ptr != '-' && **ptr != '(' && **ptr != ')' ) {
+ **ptr != '/' && **ptr != '.' && **ptr != '-' && **ptr != '(' && **ptr != ')' ) {
++*ptr;
}
end = *ptr;
return 0;
}
+static timelib_long timelib_parse_tz_minutes(char **ptr, timelib_time *t)
+{
+ timelib_long retval = TIMELIB_UNSET;
+ char *begin = *ptr;
+
+ /* First character must be +/- */
+ if (**ptr != '+' && **ptr != '-') {
+ return retval;
+ }
+
+ ++*ptr;
+ while (isdigit(**ptr)) {
+ ++*ptr;
+ }
+
+ if (*begin == '+') {
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ t->dst = 0;
+
+ retval = sMIN(strtol(begin + 1, NULL, 10));
+ } else if (*begin == '-') {
+ t->is_localtime = 1;
+ t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+ t->dst = 0;
+
+ retval = -1 * sMIN(strtol(begin + 1, NULL, 10));
+ }
+ return retval;
+}
+
timelib_long timelib_parse_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_wrapper)
{
timelib_tzinfo *res;
if (time->us == TIMELIB_UNSET ) time->us = 0;
}
+static const timelib_format_specifier default_format_map[] = {
+ {'+', TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS},
+ {'#', TIMELIB_FORMAT_ANY_SEPARATOR},
+ {'j', TIMELIB_FORMAT_DAY_TWO_DIGIT},
+ {'d', TIMELIB_FORMAT_DAY_TWO_DIGIT_PADDED},
+ {'z', TIMELIB_FORMAT_DAY_OF_YEAR},
+ {'S', TIMELIB_FORMAT_DAY_SUFFIX},
+ {'U', TIMELIB_FORMAT_EPOCH_SECONDS},
+ {'\\', TIMELIB_FORMAT_ESCAPE},
+ {'h', TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX},
+ {'g', TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX_PADDED},
+ {'H', TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX},
+ {'G', TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX_PADDED},
+ {'a', TIMELIB_FORMAT_MERIDIAN},
+ {'A', TIMELIB_FORMAT_MERIDIAN},
+ {'u', TIMELIB_FORMAT_MICROSECOND_SIX_DIGIT},
+ {'v', TIMELIB_FORMAT_MILLISECOND_THREE_DIGIT},
+ {'i', TIMELIB_FORMAT_MINUTE_TWO_DIGIT},
+ {'n', TIMELIB_FORMAT_MONTH_TWO_DIGIT},
+ {'m', TIMELIB_FORMAT_MONTH_TWO_DIGIT_PADDED},
+ {'?', TIMELIB_FORMAT_RANDOM_CHAR},
+ {'!', TIMELIB_FORMAT_RESET_ALL},
+ {'|', TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET},
+ {'s', TIMELIB_FORMAT_SECOND_TWO_DIGIT},
+ {';', TIMELIB_FORMAT_SEPARATOR},
+ {':', TIMELIB_FORMAT_SEPARATOR},
+ {'/', TIMELIB_FORMAT_SEPARATOR},
+ {'.', TIMELIB_FORMAT_SEPARATOR},
+ {',', TIMELIB_FORMAT_SEPARATOR},
+ {'-', TIMELIB_FORMAT_SEPARATOR},
+ {'(', TIMELIB_FORMAT_SEPARATOR},
+ {')', TIMELIB_FORMAT_SEPARATOR},
+ {'*', TIMELIB_FORMAT_SKIP_TO_SEPARATOR},
+ {'D', TIMELIB_FORMAT_TEXTUAL_DAY_3_LETTER},
+ {'l', TIMELIB_FORMAT_TEXTUAL_DAY_FULL},
+ {'M', TIMELIB_FORMAT_TEXTUAL_MONTH_3_LETTER},
+ {'F', TIMELIB_FORMAT_TEXTUAL_MONTH_FULL},
+ {'e', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {'P', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {'T', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {'O', TIMELIB_FORMAT_TIMEZONE_OFFSET},
+ {' ', TIMELIB_FORMAT_WHITESPACE},
+ {'y', TIMELIB_FORMAT_YEAR_TWO_DIGIT},
+ {'Y', TIMELIB_FORMAT_YEAR_FOUR_DIGIT},
+ {'\0', TIMELIB_FORMAT_END}
+};
+
+static const timelib_format_config default_format_config = {
+ default_format_map,
+ // No prefix required by default.
+ '\0'
+};
+
+static timelib_format_specifier_code timelib_lookup_format(char input, const timelib_format_specifier* format_map)
+{
+ while (format_map && format_map->specifier != '\0') {
+ if (format_map->specifier == input) {
+ return format_map->code;
+ }
+ format_map++;
+ }
+ return TIMELIB_FORMAT_LITERAL;
+}
+
timelib_time *timelib_parse_from_format(char *format, char *string, size_t len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper)
{
- char *fptr = format;
- char *ptr = string;
- char *begin;
- timelib_sll tmp;
- Scanner in;
- Scanner *s = ∈
- int allow_extra = 0;
+ return timelib_parse_from_format_with_map(format, string, len, errors, tzdb, tz_get_wrapper, &default_format_config);
+}
+
+timelib_time *timelib_parse_from_format_with_map(char *format, char *string, size_t len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper, const timelib_format_config* format_config)
+{
+ char *fptr = format;
+ char *ptr = string;
+ char *begin;
+ timelib_sll tmp;
+ Scanner in;
+ Scanner *s = ∈
+ bool allow_extra = false;
+ bool prefix_found = false;
+ int iso_year = TIMELIB_UNSET;
+ int iso_week_of_year = TIMELIB_UNSET;
+ int iso_day_of_week = TIMELIB_UNSET;
+ char prefix_char = format_config->prefix_char;
+ const timelib_format_specifier *format_map = format_config->format_map;
memset(&in, 0, sizeof(in));
in.errors = timelib_malloc(sizeof(timelib_error_container));
/* Loop over the format string */
while (*fptr && *ptr) {
begin = ptr;
- switch (*fptr) {
- case 'D': /* three letter day */
- case 'l': /* full day */
+
+ if (prefix_char) {
+ /* There are 2 cases where the input string and format string
+ * should match the next literal:
+ *
+ * 1. No prefix has been specified yet in the format, so expect 1:1
+ * match.
+ * 2. Sequential prefix characters indicating that the second
+ * prefix is escaped. (e.g. "%%" is expecting literal "%")
+ */
+ if ((!prefix_found && *fptr != prefix_char) ||
+ (prefix_found && *fptr == prefix_char)) {
+ if (*fptr != *ptr) {
+ add_pbf_error(s, TIMELIB_ERR_FORMAT_LITERAL_MISMATCH, "Format literal not found", string, begin);
+ }
+ ptr++;
+ fptr++;
+ prefix_found = false;
+ continue;
+ }
+
+ if (*fptr == prefix_char) {
+ fptr++;
+ prefix_found = true;
+ continue;
+ }
+
+ /* Fall through case is that the prefix has been found and the next
+ * character is the format specifier. */
+ prefix_found = false;
+ }
+
+ switch (timelib_lookup_format(*fptr, format_map)) {
+ case TIMELIB_FORMAT_TEXTUAL_DAY_3_LETTER: /* three letter day */
+ case TIMELIB_FORMAT_TEXTUAL_DAY_FULL: /* full day */
{
const timelib_relunit* tmprel = 0;
}
}
break;
- case 'd': /* two digit day, with leading zero */
- case 'j': /* two digit day, without leading zero */
+ case TIMELIB_FORMAT_DAY_TWO_DIGIT: /* two digit day, without leading zero */
+ case TIMELIB_FORMAT_DAY_TWO_DIGIT_PADDED: /* two digit day, with leading zero */
TIMELIB_CHECK_NUMBER;
if ((s->time->d = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_DAY, "A two digit day could not be found", string, begin);
}
break;
- case 'S': /* day suffix, ignored, nor checked */
+ case TIMELIB_FORMAT_DAY_SUFFIX: /* day suffix, ignored, nor checked */
timelib_skip_day_suffix((char **) &ptr);
break;
- case 'z': /* day of year - resets month (0 based) - also initializes everything else to !TIMELIB_UNSET */
+ case TIMELIB_FORMAT_DAY_OF_YEAR: /* day of year - resets month (0 based) - also initializes everything else to !TIMELIB_UNSET */
TIMELIB_CHECK_NUMBER;
if ((tmp = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_THREE_DIGIT_DAY_OF_YEAR, "A three digit day-of-year could not be found", string, begin);
}
break;
- case 'm': /* two digit month, with leading zero */
- case 'n': /* two digit month, without leading zero */
+ case TIMELIB_FORMAT_MONTH_TWO_DIGIT: /* two digit month, without leading zero */
+ case TIMELIB_FORMAT_MONTH_TWO_DIGIT_PADDED: /* two digit month, with leading zero */
TIMELIB_CHECK_NUMBER;
if ((s->time->m = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_MONTH, "A two digit month could not be found", string, begin);
}
break;
- case 'M': /* three letter month */
- case 'F': /* full month */
+ case TIMELIB_FORMAT_TEXTUAL_MONTH_3_LETTER: /* three letter month */
+ case TIMELIB_FORMAT_TEXTUAL_MONTH_FULL: /* full month */
tmp = timelib_lookup_month((char **) &ptr);
if (!tmp) {
add_pbf_error(s, TIMELIB_ERR_NO_TEXTUAL_MONTH, "A textual month could not be found", string, begin);
s->time->m = tmp;
}
break;
- case 'y': /* two digit year */
+ case TIMELIB_FORMAT_YEAR_TWO_DIGIT: /* two digit year */
{
int length = 0;
TIMELIB_CHECK_NUMBER;
TIMELIB_PROCESS_YEAR(s->time->y, length);
}
break;
- case 'Y': /* four digit year */
+ case TIMELIB_FORMAT_YEAR_FOUR_DIGIT: /* four digit year */
TIMELIB_CHECK_NUMBER;
if ((s->time->y = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_FOUR_DIGIT_YEAR, "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 */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX: /* two digit hour, without leading zero */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX_PADDED: /* two digit hour, with leading zero */
TIMELIB_CHECK_NUMBER;
if ((s->time->h = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_HOUR, "A two digit hour could not be found", string, begin);
add_pbf_error(s, TIMELIB_ERR_HOUR_LARGER_THAN_12, "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 */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX_PADDED: /* two digit hour, with leading zero */
+ case TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX: /* 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, TIMELIB_ERR_NO_TWO_DIGIT_HOUR, "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. */
+ case TIMELIB_FORMAT_MERIDIAN: /* am/pm/a.m./p.m. AM/PM/A.M./P.M. */
if (s->time->h == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_MERIDIAN_BEFORE_HOUR, "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) {
s->time->h += tmp;
}
break;
- case 'i': /* two digit minute, with leading zero */
+ case TIMELIB_FORMAT_MINUTE_TWO_DIGIT: /* two digit minute, with leading zero */
{
int length;
timelib_sll min;
}
}
break;
- case 's': /* two digit second, with leading zero */
+ case TIMELIB_FORMAT_SECOND_TWO_DIGIT: /* two digit second, with leading zero */
{
int length;
timelib_sll sec;
}
}
break;
- case 'u': /* up to six digit microsecond */
+ case TIMELIB_FORMAT_MICROSECOND_SIX_DIGIT: /* up to six digit microsecond */
{
double f;
char *tptr;
}
}
break;
- case ' ': /* any sort of whitespace (' ' and \t) */
+ case TIMELIB_FORMAT_MILLISECOND_THREE_DIGIT: /* up to three digit millisecond */
+ {
+ double f;
+ char *tptr;
+
+ TIMELIB_CHECK_NUMBER;
+ tptr = ptr;
+ if ((f = timelib_get_nr((char **) &ptr, 3)) == TIMELIB_UNSET || (ptr - tptr < 1)) {
+ add_pbf_error(s, TIMELIB_ERR_NO_THREE_DIGIT_MILLISECOND, "A three digit millisecond could not be found", string, begin);
+ } else {
+ s->time->us = (f * pow(10, 3 - (ptr - tptr)) * 1000);
+ }
+ }
+ break;
+ case TIMELIB_FORMAT_WHITESPACE: /* any sort of whitespace (' ' and \t) */
timelib_eat_spaces((char **) &ptr);
break;
- case 'U': /* epoch seconds */
+ case TIMELIB_FORMAT_EPOCH_SECONDS: /* epoch seconds */
TIMELIB_CHECK_SIGNED_NUMBER;
TIMELIB_HAVE_RELATIVE();
tmp = timelib_get_unsigned_nr((char **) &ptr, 24);
s->time->z = 0;
s->time->dst = 0;
break;
-
- case 'e': /* timezone */
- case 'P': /* timezone */
- case 'T': /* timezone */
- case 'O': /* timezone */
- {
- int tz_not_found;
- s->time->z = timelib_parse_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
- if (tz_not_found) {
- add_pbf_error(s, TIMELIB_ERR_TZID_NOT_FOUND, "The timezone could not be found in the database", string, begin);
- }
- }
- break;
-
- case '#': /* separation symbol */
- if (*ptr == ';' || *ptr == ':' || *ptr == '/' || *ptr == '.' || *ptr == ',' || *ptr == '-' || *ptr == '(' || *ptr == ')') {
+ case TIMELIB_FORMAT_ANY_SEPARATOR: /* separation symbol */
+ if (timelib_lookup_format(*ptr, format_map) == TIMELIB_FORMAT_SEPARATOR) {
++ptr;
} else {
add_pbf_error(s, TIMELIB_ERR_NO_SEP_SYMBOL, "The separation symbol ([;:/.,-]) could not be found", string, begin);
}
break;
- case ';':
- case ':':
- case '/':
- case '.':
- case ',':
- case '-':
- case '(':
- case ')':
+ case TIMELIB_FORMAT_SEPARATOR:
if (*ptr == *fptr) {
++ptr;
} else {
}
break;
- case '!': /* reset all fields to default */
+ case TIMELIB_FORMAT_RESET_ALL: /* reset all fields to default */
timelib_time_reset_fields(s->time);
break; /* break intentionally not missing */
- case '|': /* reset all fields to default when not set */
+ case TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET: /* reset all fields to default when not set */
timelib_time_reset_unset_fields(s->time);
break; /* break intentionally not missing */
- case '?': /* random char */
+ case TIMELIB_FORMAT_RANDOM_CHAR: /* random char */
++ptr;
break;
- case '\\': /* escaped char */
+ case TIMELIB_FORMAT_ESCAPE: /* escaped char */
if(!fptr[1]) {
add_pbf_error(s, TIMELIB_ERR_EXPECTED_ESCAPE_CHAR, "Escaped character expected", string, begin);
break;
}
break;
- case '*': /* random chars until a separator or number ([ \t.,:;/-0123456789]) */
+ case TIMELIB_FORMAT_SKIP_TO_SEPARATOR: /* random chars until a separator or number ([ \t.,:;/-0123456789]) */
timelib_eat_until_separator((char **) &ptr);
break;
- case '+': /* allow extra chars in the format */
- allow_extra = 1;
+ case TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS: /* allow extra chars in the format */
+ allow_extra = true;
+ break;
+ case TIMELIB_FORMAT_YEAR_ISO:
+ if ((iso_year = timelib_get_nr((char **) &ptr, 4)) == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_NO_FOUR_DIGIT_YEAR_ISO, "A four digit ISO year could not be found", string, begin);
+ }
+ break;
+ case TIMELIB_FORMAT_WEEK_OF_YEAR_ISO:
+ if ((iso_week_of_year = timelib_get_nr((char **) &ptr, 2)) == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_NO_TWO_DIGIT_WEEK, "A two digit ISO week could not be found", string, begin);
+ }
+ /* Range is 1 - 53 for ISO week of year */
+ if (iso_week_of_year < 1 || iso_week_of_year > 53) {
+ add_pbf_error(s, TIMELIB_ERR_INVALID_WEEK, "ISO Week must be between 1 and 53", string, begin);
+ }
+ break;
+ case TIMELIB_FORMAT_DAY_OF_WEEK_ISO:
+ if ((iso_day_of_week = timelib_get_nr((char **) &ptr, 1)) == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_NO_DAY_OF_WEEK, "A single digit day of week could not be found", string, begin);
+ }
+ if (iso_day_of_week < 1 || iso_day_of_week > 7) {
+ add_pbf_error(s, TIMELIB_ERR_INVALID_DAY_OF_WEEK, "Day of week must be between 1 and 7", string, begin);
+ }
break;
+ case TIMELIB_FORMAT_TIMEZONE_OFFSET: /* timezone */
+ {
+ int tz_not_found;
+ s->time->z = timelib_parse_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
+ if (tz_not_found) {
+ add_pbf_error(s, TIMELIB_ERR_TZID_NOT_FOUND, "The timezone could not be found in the database", string, begin);
+ }
+ }
+ break;
+ case TIMELIB_FORMAT_TIMEZONE_OFFSET_MINUTES: /* timezone format +/-mmm */
+ s->time->z = timelib_parse_tz_minutes((char **) &ptr, s->time);
+ if (s->time->z == TIMELIB_UNSET) {
+ add_pbf_error(s, TIMELIB_ERR_INVALID_TZ_OFFSET, "Invalid timezone offset in minutes", string, begin);
+ }
+ break;
+ case TIMELIB_FORMAT_LITERAL:
default:
if (*fptr != *ptr) {
add_pbf_error(s, TIMELIB_ERR_WRONG_FORMAT_SEP, "The format separator does not match", string, begin);
add_pbf_error(s, TIMELIB_ERR_TRAILING_DATA, "Trailing data", string, ptr);
}
}
- /* ignore trailing +'s */
- while (*fptr == '+') {
- fptr++;
- }
+
if (*fptr) {
- /* Trailing | and ! specifiers are valid. */
+ /* Trailing reset specifiers are valid. */
int done = 0;
while (*fptr && !done) {
- switch (*fptr++) {
- case '!': /* reset all fields to default */
+ switch (timelib_lookup_format(*fptr, format_map)) {
+ case TIMELIB_FORMAT_RESET_ALL: /* reset all fields to default */
timelib_time_reset_fields(s->time);
break;
- case '|': /* reset all fields to default when not set */
+ case TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET: /* reset all fields to default when not set */
timelib_time_reset_unset_fields(s->time);
break;
+ case TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS:
+ break;
default:
add_pbf_error(s, TIMELIB_ERR_DATA_MISSING, "Data missing", string, ptr);
done = 1;
}
+ fptr++;
}
}
/* clean up a bit */
- if (s->time->h != TIMELIB_UNSET || s->time->i != TIMELIB_UNSET || s->time->s != TIMELIB_UNSET) {
+ if (s->time->h != TIMELIB_UNSET || s->time->i != TIMELIB_UNSET || s->time->s != TIMELIB_UNSET || s->time->us != TIMELIB_UNSET) {
if (s->time->h == TIMELIB_UNSET ) {
s->time->h = 0;
}
if (s->time->s == TIMELIB_UNSET ) {
s->time->s = 0;
}
+ if (s->time->us == TIMELIB_UNSET ) {
+ s->time->us = 0;
+ }
+ }
+
+ /* Check for mixing of ISO dates with natural dates. */
+ if (s->time->y != TIMELIB_UNSET && (iso_week_of_year != TIMELIB_UNSET || iso_year != TIMELIB_UNSET || iso_day_of_week != TIMELIB_UNSET)) {
+ add_pbf_error(s, TIMELIB_ERR_MIX_ISO_WITH_NATURAL, "Mixing of ISO dates with natural dates is not allowed", string, ptr);
+ }
+ if (iso_year != TIMELIB_UNSET && (s->time->y != TIMELIB_UNSET || s->time->m != TIMELIB_UNSET || s->time->d != TIMELIB_UNSET)) {
+ add_pbf_error(s, TIMELIB_ERR_MIX_ISO_WITH_NATURAL, "Mixing of ISO dates with natural dates is not allowed", string, ptr);
+ }
+
+ /* Convert ISO values */
+ if (iso_year != TIMELIB_UNSET) {
+ /* Default week of year and day of week to 1. */
+ if (iso_week_of_year == TIMELIB_UNSET) {
+ iso_week_of_year = 1;
+ }
+ if (iso_day_of_week == TIMELIB_UNSET) {
+ iso_day_of_week = 1;
+ }
+ timelib_date_from_isodate(iso_year, iso_week_of_year, iso_day_of_week, &s->time->y, &s->time->m, &s->time->d);
+ } else if (iso_week_of_year != TIMELIB_UNSET || iso_day_of_week != TIMELIB_UNSET) {
+ add_pbf_warning(s, TIMELIB_WARN_INVALID_DATE, "The parsed date was invalid", string, ptr);
}
/* do funky checking whether the parsed time was valid time */
-/* Generated by re2c 0.15.3 on Wed Jan 31 11:51:44 2018 */
-#line 1 "ext/date/lib/parse_iso_intervals.re"
+/* Generated by re2c 0.15.3 on Tue Oct 9 10:50:29 2018 */
+#line 1 "parse_iso_intervals.re"
/*
* The MIT License (MIT)
*
std:
s->tok = cursor;
s->len = 0;
-#line 204 "ext/date/lib/parse_iso_intervals.re"
+#line 204 "parse_iso_intervals.re"
YYCTYPE yych;
unsigned int yyaccept = 0;
static const unsigned char yybm[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
YYDEBUG(0, *YYCURSOR);
if ((YYLIMIT - YYCURSOR) < 20) YYFILL(20);
if (yych <= '9') goto yy98;
yy3:
YYDEBUG(3, *YYCURSOR);
-#line 317 "ext/date/lib/parse_iso_intervals.re"
+#line 317 "parse_iso_intervals.re"
{
add_error(s, "Unexpected character");
goto std;
if (yych == 'T') goto yy14;
yy6:
YYDEBUG(6, *YYCURSOR);
-#line 244 "ext/date/lib/parse_iso_intervals.re"
+#line 244 "parse_iso_intervals.re"
{
timelib_sll nr;
int in_time = 0;
YYDEBUG(7, *YYCURSOR);
++YYCURSOR;
YYDEBUG(8, *YYCURSOR);
-#line 306 "ext/date/lib/parse_iso_intervals.re"
+#line 306 "parse_iso_intervals.re"
{
goto std;
}
YYDEBUG(9, *YYCURSOR);
++YYCURSOR;
YYDEBUG(10, *YYCURSOR);
-#line 311 "ext/date/lib/parse_iso_intervals.re"
+#line 311 "parse_iso_intervals.re"
{
s->pos = cursor; s->line++;
goto std;
YYDEBUG(57, *YYCURSOR);
++YYCURSOR;
YYDEBUG(58, *YYCURSOR);
-#line 286 "ext/date/lib/parse_iso_intervals.re"
+#line 286 "parse_iso_intervals.re"
{
DEBUG_OUTPUT("combinedrep");
TIMELIB_INIT;
YYDEBUG(83, *YYCURSOR);
++YYCURSOR;
YYDEBUG(84, *YYCURSOR);
-#line 220 "ext/date/lib/parse_iso_intervals.re"
+#line 220 "parse_iso_intervals.re"
{
timelib_time *current;
if (yych <= '9') goto yy98;
yy100:
YYDEBUG(100, *YYCURSOR);
-#line 209 "ext/date/lib/parse_iso_intervals.re"
+#line 209 "parse_iso_intervals.re"
{
DEBUG_OUTPUT("recurrences");
TIMELIB_INIT;
}
#line 924 "<stdout>"
}
-#line 321 "ext/date/lib/parse_iso_intervals.re"
+#line 321 "parse_iso_intervals.re"
}
#ifdef PHP_WIN32
return &(tz->type[tz->trans_idx[j]]);
}
- /* In all other cases we loop through the available transtion times to find
+ /* In all other cases we loop through the available transition times to find
* the correct entry */
for (i = 0; i < tz->bit32.timecnt; i++) {
if (ts < tz->trans[i]) {
#endif
#include <stdlib.h>
+#include <stdbool.h>
#include <limits.h>
#include <inttypes.h>
#define TIMELIB_ERR_WRONG_FORMAT_SEP 0x219
#define TIMELIB_ERR_TRAILING_DATA 0x21a
#define TIMELIB_ERR_DATA_MISSING 0x21b
+#define TIMELIB_ERR_NO_THREE_DIGIT_MILLISECOND 0x21c
+#define TIMELIB_ERR_NO_FOUR_DIGIT_YEAR_ISO 0x21d
+#define TIMELIB_ERR_NO_TWO_DIGIT_WEEK 0x21e
+#define TIMELIB_ERR_INVALID_WEEK 0x21f
+#define TIMELIB_ERR_NO_DAY_OF_WEEK 0x220
+#define TIMELIB_ERR_INVALID_DAY_OF_WEEK 0x221
+#define TIMELIB_ERR_INVALID_SPECIFIER 0x222
+#define TIMELIB_ERR_INVALID_TZ_OFFSET 0x223
+#define TIMELIB_ERR_FORMAT_LITERAL_MISMATCH 0x224
+#define TIMELIB_ERR_MIX_ISO_WITH_NATURAL 0x225
#define TIMELIB_ZONETYPE_OFFSET 1
#define TIMELIB_ZONETYPE_ABBR 2
# define timelib_free free
#endif
-#define TIMELIB_VERSION 201706
-#define TIMELIB_EXTENDED_VERSION 20170600
-#define TIMELIB_ASCII_VERSION "2017.06"
+#define TIMELIB_VERSION 201801
+#define TIMELIB_EXTENDED_VERSION 20180002
+#define TIMELIB_ASCII_VERSION "2018.01alpha2"
#define TIMELIB_NONE 0x00
#define TIMELIB_OVERRIDE_TIME 0x01
extern "C" {
#endif
+typedef enum _timelib_format_specifier_code {
+ TIMELIB_FORMAT_ALLOW_EXTRA_CHARACTERS = 0,
+ TIMELIB_FORMAT_ANY_SEPARATOR,
+ TIMELIB_FORMAT_DAY_TWO_DIGIT,
+ TIMELIB_FORMAT_DAY_TWO_DIGIT_PADDED,
+ TIMELIB_FORMAT_DAY_OF_WEEK_ISO,
+ TIMELIB_FORMAT_DAY_OF_WEEK,
+ TIMELIB_FORMAT_DAY_OF_YEAR,
+ TIMELIB_FORMAT_DAY_SUFFIX,
+ TIMELIB_FORMAT_END,
+ TIMELIB_FORMAT_EPOCH_SECONDS,
+ TIMELIB_FORMAT_ESCAPE,
+ TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX,
+ TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX_PADDED,
+ TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX,
+ TIMELIB_FORMAT_HOUR_TWO_DIGIT_24_MAX_PADDED,
+ TIMELIB_FORMAT_LITERAL,
+ TIMELIB_FORMAT_MERIDIAN,
+ TIMELIB_FORMAT_MICROSECOND_SIX_DIGIT,
+ TIMELIB_FORMAT_MILLISECOND_THREE_DIGIT,
+ TIMELIB_FORMAT_MINUTE_TWO_DIGIT,
+ TIMELIB_FORMAT_MONTH_TWO_DIGIT,
+ TIMELIB_FORMAT_MONTH_TWO_DIGIT_PADDED,
+ TIMELIB_FORMAT_RANDOM_CHAR,
+ TIMELIB_FORMAT_RESET_ALL,
+ TIMELIB_FORMAT_RESET_ALL_WHEN_NOT_SET,
+ TIMELIB_FORMAT_SECOND_TWO_DIGIT,
+ TIMELIB_FORMAT_SEPARATOR,
+ TIMELIB_FORMAT_SKIP_TO_SEPARATOR,
+ TIMELIB_FORMAT_TEXTUAL_DAY_3_LETTER,
+ TIMELIB_FORMAT_TEXTUAL_DAY_FULL,
+ TIMELIB_FORMAT_TEXTUAL_MONTH_3_LETTER,
+ TIMELIB_FORMAT_TEXTUAL_MONTH_FULL,
+ TIMELIB_FORMAT_TIMEZONE_OFFSET,
+ TIMELIB_FORMAT_TIMEZONE_OFFSET_MINUTES,
+ TIMELIB_FORMAT_WEEK_OF_YEAR_ISO,
+ TIMELIB_FORMAT_WEEK_OF_YEAR,
+ TIMELIB_FORMAT_WHITESPACE,
+ TIMELIB_FORMAT_YEAR_TWO_DIGIT,
+ TIMELIB_FORMAT_YEAR_FOUR_DIGIT,
+ TIMELIB_FORMAT_YEAR_ISO
+} timelib_format_specifier_code;
+
+typedef struct _timelib_format_specifier {
+ char specifier;
+ timelib_format_specifier_code code;
+} timelib_format_specifier;
+
+typedef struct _timelib_format_config {
+ const timelib_format_specifier *format_map;
+ /* Format speciifiers must be preceded by 'prefix_char' if not '\0'. */
+ char prefix_char;
+} timelib_format_config;
+
/* Function pointers */
typedef timelib_tzinfo* (*timelib_tz_get_wrapper)(char *tzname, const timelib_tzdb *tzdb, int *error_code);
*/
timelib_time *timelib_parse_from_format(char *format, char *s, size_t len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper);
+/* Parses the date/time string in 's' with length 'len' into the constituent
+ * parts of timelib_time* according to the format in 'format' with format
+ * specifier configuration 'format_config'.
+ *
+ * 'format_map' is an array of pairs, with the first element being the format
+ * specifier as a character and the second element corresponds to the
+ * representation of the specifier from the enum list
+ * 'timelib_format_specifier_code'.
+ *
+ * Note: 'format_map' must be terminated with specifier '\0' to indicate to the
+ * parser that there are no more format specifiers in the list.
+ */
+timelib_time *timelib_parse_from_format_with_map(char *format, char *s, size_t len, timelib_error_container **errors, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_get_wrapper, const timelib_format_config* format_config);
+
/* Fills the gaps in the parsed timelib_time with information from the reference date/time in 'now'
*
* If any of the 'parsed' y, m, d, h, i or s parameters is unset (TIMELIB_UNSET):
*/
void timelib_strtointerval(char *s, size_t len,
timelib_time **begin, timelib_time **end,
- timelib_rel_time **period, int *recurrences,
- timelib_error_container **errors);
+ timelib_rel_time **period, int *recurrences,
+ timelib_error_container **errors);
/* From tm2unixtime.c */
* The returned information contains: the offset in seconds East of UTC (in
* 'offset'), whether DST is active ('is_dst'), what the current time zone
* abbreviation is ('abbr') and the transition time that got to this state (in
- * 'transistion_time');
+ * 'transition_time');
*/
timelib_time_offset *timelib_get_time_zone_info(timelib_sll ts, timelib_tzinfo *tz);
{ "bmt", 0, 25632, "Asia/Jakarta" },
{ "bmt", 0, 6264, "Europe/Bucharest" },
{ "bmt", 0, 6264, "Europe/Chisinau" },
- { "bost", 1, -12756, "America/La_Paz" },
{ "bst", 1, 3600, "Europe/London" },
{ "bst", 0, 3600, "Europe/London" },
+ { "bst", 1, -12756, "America/La_Paz" },
{ "bst", 0, -39600, "America/Adak" },
{ "bst", 0, -39600, "America/Atka" },
{ "bst", 0, -39600, "America/Nome" },
{ "gmt", 0, 0, "Europe/Jersey" },
{ "gmt", 0, 0, "Europe/London" },
{ "gmt", 0, 0, "GB" },
+ { "gmt", 1, 0, "Europe/Bratislava" },
+ { "gmt", 1, 0, "Europe/Dublin" },
+ { "gmt", 1, 0, "Europe/Prague" },
{ "gst", 0, 36000, "Pacific/Guam" },
{ "gst", 0, 36000, "Pacific/Saipan" },
{ "hdt", 1, -34200, "Pacific/Honolulu" },
{ "kdt", 1, 34200, "ROK" },
{ "kdt", 1, 36000, "ROK" },
{ "kmt", 0, 5736, "Europe/Vilnius" },
- { "kmt", 0, -18431, "America/Grand_Turk" },
- { "kmt", 0, -18431, "America/Jamaica" },
+ { "kmt", 0, -18430, "America/Grand_Turk" },
+ { "kmt", 0, -18430, "America/Jamaica" },
{ "kmt", 0, 7324, "Europe/Kiev" },
{ "kst", 0, 30600, "Asia/Seoul" },
{ "kst", 0, 32400, "Asia/Pyongyang" },
{ "mdt", 1, -21600, "Mexico/BajaSur" },
{ "mmt", 0, 9017, "Europe/Moscow" },
{ "mmt", 0, 9079, "Europe/Moscow" },
- { "mmt", 0, -13484, "America/Montevideo" },
+ { "mmt", 0, -13491, "America/Montevideo" },
{ "mmt", 0, -20712, "America/Managua" },
{ "mmt", 0, -2588, "Africa/Monrovia" },
{ "mmt", 0, -2670, "Africa/Monrovia" },
{ "wat", 0, 3600, "Africa/Ndjamena" },
{ "wat", 0, 3600, "Africa/Niamey" },
{ "wat", 0, 3600, "Africa/Porto-Novo" },
- { "wat", 0, 3600, "Africa/Windhoek" },
+ { "wat", 0, 3600, "Africa/Sao_Tome" },
+ { "wat", 1, 3600, "Africa/Windhoek" },
{ "wemt", 1, 7200, "Europe/Lisbon" },
{ "wemt", 1, 7200, "Europe/Madrid" },
{ "wemt", 1, 7200, "Europe/Monaco" },
*fraction += 1000000;
*seconds -= 1;
}
- if (*fraction > 1000000) {
+ if (*fraction >= 1000000) {
*fraction -= 1000000;
*seconds += 1;
}
}
TIMELIB_DEBUG(printf("A: ts=%lld, year=%lld, month=%lld, day=%lld,", ts, cur_year, i + 1, tmp_days - months[i]););
- /* That was the date, now we do the tiiiime */
+ /* That was the date, now we do the time */
hours = remainder / 3600;
minutes = (remainder - hours * 3600) / 60;
seconds = remainder % 60;
/* Converts the time stored in the struct to localtime if localtime = true,
* otherwise it converts it to gmttime. This is only done when necessary
- * ofcourse. */
+ * of course. */
int timelib_apply_localtime(timelib_time *t, unsigned int localtime)
{
if (localtime) {