Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/d93c426681df30eadb62904ca82807c5e0ba68e1
...commit
http://git.netsurf-browser.org/netsurf.git/commit/d93c426681df30eadb62904ca82807c5e0ba68e1
...tree
http://git.netsurf-browser.org/netsurf.git/tree/d93c426681df30eadb62904ca82807c5e0ba68e1
The branch, tlsa/date has been updated
discards d06c7eb34614f047bf52c97608301da52ede654b (commit)
discards 640fe591e8b66e5833404b7545df8a8b522e88c6 (commit)
discards 0637e4f5407bf431afdef346a846ddbec0262bf9 (commit)
via d93c426681df30eadb62904ca82807c5e0ba68e1 (commit)
via 69bd05a4e10815eba7bdc799650c02b03351b2a3 (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (d06c7eb34614f047bf52c97608301da52ede654b)
\
N -- N -- N (d93c426681df30eadb62904ca82807c5e0ba68e1)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=d93c426681df30eadb62904ca82807c5e0ba68e1
commit d93c426681df30eadb62904ca82807c5e0ba68e1
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Tests: Add some basic tests for date string parsing.
diff --git a/test/Makefile b/test/Makefile
index 0253f4d..d62e2fd 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,7 +1,16 @@
#
# NetSurf unit tests
-TESTS := nsurl urldbtest nsoption bloom hashtable urlescape utils messages
#llcache
+TESTS := \
+ nsurl \
+ urldbtest \
+ nsoption \
+ bloom \
+ hashtable \
+ urlescape \
+ utils \
+ messages \
+ time #llcache
# nsurl sources
nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
@@ -44,6 +53,9 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
test/log.c test/utils.c
+# time test sources
+time_SRCS := utils/time.c test/log.c test/time.c
+
# Coverage builds need additional flags
ifeq ($(MAKECMDGOALS),coverage)
COV_CFLAGS ?= -fprofile-arcs -ftest-coverage -O0
diff --git a/test/time.c b/test/time.c
new file mode 100644
index 0000000..b2d465c
--- /dev/null
+++ b/test/time.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2016 Michael Drake <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Test time operations.
+ */
+
+#include <stdlib.h>
+#include <check.h>
+
+#include "utils/errors.h"
+#include "utils/time.h"
+
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
+
+struct test_string_pair {
+ const char* test;
+ const char* expected;
+};
+
+struct test_bad_string {
+ const char* test;
+ nserror res;
+};
+
+static const struct test_string_pair date_string_tests[] = {
+ {
+ .test = "Thu, 01 Jan 1970 00:00:00 GMT",
+ .expected = "Thu, 01 Jan 1970 00:00:00 GMT"
+ },
+ {
+ .test = "Tue, 16 Feb 1999 19:45:12 GMT",
+ .expected = "Tue, 16 Feb 1999 19:45:12 GMT"
+ },
+ {
+ .test = "Sun, 16 Mar 1980 19:45:12 GMT",
+ .expected = "Sun, 16 Mar 1980 19:45:12 GMT"
+ },
+ {
+ .test = "Tue, 16 Apr 2013 19:45:12 GMT",
+ .expected = "Tue, 16 Apr 2013 19:45:12 GMT"
+ },
+ {
+ .test = "Tue, 16 May 2000 19:45:12 GMT",
+ .expected = "Tue, 16 May 2000 19:45:12 GMT"
+ },
+ {
+ .test = "Tue, 12 Jun 2001 12:12:12 GMT",
+ .expected = "Tue, 12 Jun 2001 12:12:12 GMT"
+ },
+ {
+ .test = "Thu, 16 Jul 2207 12:45:12 GMT",
+ .expected = "Thu, 16 Jul 2207 12:45:12 GMT"
+ },
+ {
+ .test = "Thu, 16 Aug 2007 19:45:12 GMT",
+ .expected = "Thu, 16 Aug 2007 19:45:12 GMT"
+ },
+ {
+ .test = "Tue, 16 Sep 3456 00:45:12 GMT",
+ .expected = "Tue, 16 Sep 3456 00:45:12 GMT"
+ },
+ {
+ .test = "Sun, 16 Oct 1988 19:45:59 GMT",
+ .expected = "Sun, 16 Oct 1988 19:45:59 GMT"
+ },
+ {
+ .test = "Tue, 16 Nov 1971 19:59:12 GMT",
+ .expected = "Tue, 16 Nov 1971 19:59:12 GMT"
+ },
+ {
+ .test = "Fri, 16 Dec 1977 23:45:12 GMT",
+ .expected = "Fri, 16 Dec 1977 23:45:12 GMT"
+ },
+ {
+ .test = " 16 Dec 1977 23:45:12 GMT",
+ .expected = "Fri, 16 Dec 1977 23:45:12 GMT"
+ },
+ {
+ .test = " 16 Dec 1977 23:45 GMT",
+ .expected = "Fri, 16 Dec 1977 23:45:00 GMT"
+ },
+ {
+ .test = "23:59 16 Dec 1977 GMT",
+ .expected = "Fri, 16 Dec 1977 23:59:00 GMT"
+ },
+ {
+ .test = "23:59 16 Dec 1977 UTC",
+ .expected = "Fri, 16 Dec 1977 23:59:00 GMT"
+ },
+ {
+ .test = "1977 GMT 23:59 16 Dec",
+ .expected = "Fri, 16 Dec 1977 23:59:00 GMT"
+ },
+ {
+ .test = "1977 Dec GMT 16",
+ .expected = "Fri, 16 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "1977 Dec 12",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "1977 12 Dec",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "Dec 1977 12",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "12 Dec 1977",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "12 Dec 77",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "12 77 Dec",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "77 12 Dec",
+ .expected = "Mon, 12 Dec 1977 00:00:00 GMT"
+ },
+ {
+ .test = "12 12 Dec",
+ .expected = "Wed, 12 Dec 2012 00:00:00 GMT"
+ },
+ {
+ .test = "5 12 Dec",
+ .expected = "Wed, 05 Dec 2012 00:00:00 GMT"
+ },
+ {
+ .test = "12 5 Dec",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "12/5/Dec",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "Dec-12/2005/",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "12-5-Dec",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "2005-12-Dec",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "2005-Dec-12",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "2005-dec-12",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "2005-dEC-12",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "20051212",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "20051212 GMT",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "20051212 +0000",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "20051212 UTC",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "20051212 00:00 UTC",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "00:00 20051212 UTC",
+ .expected = "Mon, 12 Dec 2005 00:00:00 GMT"
+ },
+ {
+ .test = "00:00:59 20051212 UTC",
+ .expected = "Mon, 12 Dec 2005 00:00:59 GMT"
+ },
+ {
+ .test = "00:00:60 20051212 UTC", /* leap second */
+ .expected = "Mon, 12 Dec 2005 00:01:00 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 GMT",
+ .expected = "Thu, 11 Aug 2016 08:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 UTC",
+ .expected = "Thu, 11 Aug 2016 08:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0000",
+ .expected = "Thu, 11 Aug 2016 08:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0000",
+ .expected = "Thu, 11 Aug 2016 08:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0001",
+ .expected = "Thu, 11 Aug 2016 08:46:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0001",
+ .expected = "Thu, 11 Aug 2016 08:48:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0030",
+ .expected = "Thu, 11 Aug 2016 08:17:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0030",
+ .expected = "Thu, 11 Aug 2016 09:17:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0059",
+ .expected = "Thu, 11 Aug 2016 07:48:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0059",
+ .expected = "Thu, 11 Aug 2016 09:46:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0100",
+ .expected = "Thu, 11 Aug 2016 07:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0100",
+ .expected = "Thu, 11 Aug 2016 09:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +1200",
+ .expected = "Wed, 10 Aug 2016 20:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -1200",
+ .expected = "Thu, 11 Aug 2016 20:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0060",
+ .expected = "Thu, 11 Aug 2016 07:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0060",
+ .expected = "Thu, 11 Aug 2016 09:47:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 +0070",
+ .expected = "Thu, 11 Aug 2016 07:37:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 -0070",
+ .expected = "Thu, 11 Aug 2016 09:57:30 GMT"
+ },
+ {
+ .test = "Thu, 11 Aug 2016 08:47:30 BST",
+ .expected = "Thu, 11 Aug 2016 07:47:30 GMT"
+ },
+};
+
+
+static const struct test_bad_string date_bad_string_tests[] = {
+ {
+ .test = NULL,
+ .res = NSERROR_BAD_PARAMETER
+ },
+ {
+ .test = "",
+ .res = NSERROR_INVALID
+ },
+ {
+ .test = "Th",
+ .res = NSERROR_INVALID
+ },
+ {
+ .test = "5",
+ .res = NSERROR_INVALID
+ },
+ {
+ .test = "5",
+ .res = NSERROR_INVALID
+ },
+ {
+ .test = "dsflihs9l84toswuhfsif74f",
+ .res = NSERROR_INVALID
+ },
+};
+
+/**
+ * Date string comparason test
+ */
+START_TEST(date_string_compare)
+{
+ nserror res;
+ time_t time_out;
+ const struct test_string_pair *t = &date_string_tests[_i];
+
+ res = nsc_strntimet(t->test, strlen(t->test), &time_out);
+ ck_assert(res == NSERROR_OK);
+ ck_assert_str_eq(rfc1123_date(time_out), t->expected);
+}
+END_TEST
+
+/**
+ * Date string conversion bad data test
+ */
+START_TEST(date_bad_string)
+{
+ nserror res;
+ time_t time_out;
+ const struct test_bad_string *t = &date_bad_string_tests[_i];
+
+ res = nsc_strntimet(t->test,
+ t->test != NULL ? strlen(t->test) : 0,
+ &time_out);
+ ck_assert(res != NSERROR_OK);
+ ck_assert(res == t->res);
+}
+END_TEST
+
+
+/* suite generation */
+static Suite *time_suite(void)
+{
+ Suite *s;
+ TCase *tc_date_string_compare;
+ TCase *tc_date_bad_string;
+
+ s = suite_create("time");
+
+ /* date parsing: string comparason */
+ tc_date_string_compare = tcase_create(
+ "date string to time_t");
+
+ /* date parsing: bad string handling */
+ tc_date_bad_string = tcase_create(
+ "date string to time_t (bad input)");
+
+ tcase_add_loop_test(tc_date_string_compare,
+ date_string_compare,
+ 0, NELEMS(date_string_tests));
+ suite_add_tcase(s, tc_date_string_compare);
+
+ tcase_add_loop_test(tc_date_bad_string,
+ date_bad_string,
+ 0, NELEMS(date_bad_string_tests));
+ suite_add_tcase(s, tc_date_bad_string);
+
+ return s;
+}
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ Suite *s;
+ SRunner *sr;
+
+ s = time_suite();
+
+ sr = srunner_create(s);
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=69bd05a4e10815eba7bdc799650c02b03351b2a3
commit 69bd05a4e10815eba7bdc799650c02b03351b2a3
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>
Time: Add date string to time_t parser.
diff --git a/utils/time.c b/utils/time.c
index dd67d8a..433b479 100644
--- a/utils/time.c
+++ b/utils/time.c
@@ -25,17 +25,21 @@
* \brief Implementation of time operations.
*/
+#include <ctype.h>
#include <errno.h>
#include <stdio.h>
-#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#ifdef USE_CURL
#include <curl/curl.h>
+#endif
+#include "utils/ascii.h"
#include "utils/errors.h"
#include "utils/time.h"
-
/**
* Weekdays
*
@@ -76,7 +80,7 @@ enum nsc_time_months {
/**
* Array of short weekday names.
*/
-const char * const weekdays_short[NSC_TIME_WEEKDAY__COUNT] = {
+static const char * const weekdays_short[NSC_TIME_WEEKDAY__COUNT] = {
[NSC_TIME_WEEKDAY_SUN] = "Sun",
[NSC_TIME_WEEKDAY_MON] = "Mon",
[NSC_TIME_WEEKDAY_TUE] = "Tue",
@@ -88,7 +92,7 @@ const char * const weekdays_short[NSC_TIME_WEEKDAY__COUNT] = {
/**
* Array of month names.
*/
-const char * const months[NSC_TIME_MONTH__COUNT] = {
+static const char * const months[NSC_TIME_MONTH__COUNT] = {
[NSC_TIME_MONTH_JAN] = "Jan",
[NSC_TIME_MONTH_FEB] = "Feb",
[NSC_TIME_MONTH_MAR] = "Mar",
@@ -181,6 +185,824 @@ nserror nsc_snptimet(const char *str, size_t size, time_t
*timep)
}
+#ifndef USE_CURL
+
+
+/**
+ * Array of long weekday names.
+ */
+static const char * const weekdays_long[NSC_TIME_WEEKDAY__COUNT] = {
+ [NSC_TIME_WEEKDAY_SUN] = "Sunday",
+ [NSC_TIME_WEEKDAY_MON] = "Monday",
+ [NSC_TIME_WEEKDAY_TUE] = "Tuesday",
+ [NSC_TIME_WEEKDAY_WED] = "Wednesday",
+ [NSC_TIME_WEEKDAY_THU] = "Thursday",
+ [NSC_TIME_WEEKDAY_FRI] = "Friday",
+ [NSC_TIME_WEEKDAY_SAT] = "Saturday"
+};
+
+/**
+ * Timezone offsets in mins
+ *
+ * Order doesn't matter.
+ */
+enum nsc_time_zone_offsets {
+ /* Timezones */
+ NSC_TIME_ZONE_OFFSET_IDLE = -12 * 60,
+ NSC_TIME_ZONE_OFFSET_NZST = -12 * 60,
+ NSC_TIME_ZONE_OFFSET_NZT = -12 * 60,
+ NSC_TIME_ZONE_OFFSET_EAST = -10 * 60,
+ NSC_TIME_ZONE_OFFSET_GST = -10 * 60,
+ NSC_TIME_ZONE_OFFSET_JST = - 9 * 60,
+ NSC_TIME_ZONE_OFFSET_CCT = - 8 * 60,
+ NSC_TIME_ZONE_OFFSET_WAST = - 7 * 60,
+ NSC_TIME_ZONE_OFFSET_EET = - 2 * 60,
+ NSC_TIME_ZONE_OFFSET_CET = - 1 * 60,
+ NSC_TIME_ZONE_OFFSET_FWT = - 1 * 60,
+ NSC_TIME_ZONE_OFFSET_MET = - 1 * 60,
+ NSC_TIME_ZONE_OFFSET_MEWT = - 1 * 60,
+ NSC_TIME_ZONE_OFFSET_GMT = 0,
+ NSC_TIME_ZONE_OFFSET_UTC = 0,
+ NSC_TIME_ZONE_OFFSET_WET = 0,
+ NSC_TIME_ZONE_OFFSET_WAT = 1 * 60,
+ NSC_TIME_ZONE_OFFSET_AST = 4 * 60,
+ NSC_TIME_ZONE_OFFSET_EST = 5 * 60,
+ NSC_TIME_ZONE_OFFSET_CST = 6 * 60,
+ NSC_TIME_ZONE_OFFSET_MST = 7 * 60,
+ NSC_TIME_ZONE_OFFSET_PST = 8 * 60,
+ NSC_TIME_ZONE_OFFSET_YST = 9 * 60,
+ NSC_TIME_ZONE_OFFSET_AHST = 10 * 60,
+ NSC_TIME_ZONE_OFFSET_CAT = 10 * 60,
+ NSC_TIME_ZONE_OFFSET_HST = 10 * 60,
+ NSC_TIME_ZONE_OFFSET_IDLW = 12 * 60,
+
+ /* Daylight saving modified timezones */
+ NSC_TIME_ZONE_OFFSET_NZDT = NSC_TIME_ZONE_OFFSET_NZT - 60,
+ NSC_TIME_ZONE_OFFSET_EADT = NSC_TIME_ZONE_OFFSET_EAST - 60,
+ NSC_TIME_ZONE_OFFSET_WADT = NSC_TIME_ZONE_OFFSET_WAST - 60,
+ NSC_TIME_ZONE_OFFSET_CEST = NSC_TIME_ZONE_OFFSET_CET - 60,
+ NSC_TIME_ZONE_OFFSET_FST = NSC_TIME_ZONE_OFFSET_FWT - 60,
+ NSC_TIME_ZONE_OFFSET_MEST = NSC_TIME_ZONE_OFFSET_MET - 60,
+ NSC_TIME_ZONE_OFFSET_MESZ = NSC_TIME_ZONE_OFFSET_MET - 60,
+ NSC_TIME_ZONE_OFFSET_BST = NSC_TIME_ZONE_OFFSET_GMT - 60,
+ NSC_TIME_ZONE_OFFSET_ADT = NSC_TIME_ZONE_OFFSET_AST - 60,
+ NSC_TIME_ZONE_OFFSET_EDT = NSC_TIME_ZONE_OFFSET_EST - 60,
+ NSC_TIME_ZONE_OFFSET_CDT = NSC_TIME_ZONE_OFFSET_CST - 60,
+ NSC_TIME_ZONE_OFFSET_MDT = NSC_TIME_ZONE_OFFSET_MST - 60,
+ NSC_TIME_ZONE_OFFSET_PDT = NSC_TIME_ZONE_OFFSET_PST - 60,
+ NSC_TIME_ZONE_OFFSET_YDT = NSC_TIME_ZONE_OFFSET_YST - 60,
+ NSC_TIME_ZONE_OFFSET_HDT = NSC_TIME_ZONE_OFFSET_HST - 60,
+
+ /* Military timezones */
+ NSC_TIME_ZONE_OFFSET_Y = -12 * 60,
+ NSC_TIME_ZONE_OFFSET_X = -11 * 60,
+ NSC_TIME_ZONE_OFFSET_W = -10 * 60,
+ NSC_TIME_ZONE_OFFSET_V = - 9 * 60,
+ NSC_TIME_ZONE_OFFSET_U = - 8 * 60,
+ NSC_TIME_ZONE_OFFSET_T = - 7 * 60,
+ NSC_TIME_ZONE_OFFSET_S = - 6 * 60,
+ NSC_TIME_ZONE_OFFSET_R = - 5 * 60,
+ NSC_TIME_ZONE_OFFSET_Q = - 4 * 60,
+ NSC_TIME_ZONE_OFFSET_P = - 3 * 60,
+ NSC_TIME_ZONE_OFFSET_O = - 2 * 60,
+ NSC_TIME_ZONE_OFFSET_N = - 1 * 60,
+ NSC_TIME_ZONE_OFFSET_Z = 0 * 60,
+ NSC_TIME_ZONE_OFFSET_A = 1 * 60,
+ NSC_TIME_ZONE_OFFSET_B = 2 * 60,
+ NSC_TIME_ZONE_OFFSET_C = 3 * 60,
+ NSC_TIME_ZONE_OFFSET_D = 4 * 60,
+ NSC_TIME_ZONE_OFFSET_E = 5 * 60,
+ NSC_TIME_ZONE_OFFSET_F = 6 * 60,
+ NSC_TIME_ZONE_OFFSET_G = 7 * 60,
+ NSC_TIME_ZONE_OFFSET_H = 8 * 60,
+ NSC_TIME_ZONE_OFFSET_I = 9 * 60,
+ NSC_TIME_ZONE_OFFSET_K = 10 * 60,
+ NSC_TIME_ZONE_OFFSET_L = 11 * 60,
+ NSC_TIME_ZONE_OFFSET_M = 12 * 60,
+};
+
+/**
+ * List of timezones.
+ *
+ * The order here is the order they appear in the `timezone_mins` array.
+ * So there is value in putting the most common timezones first.
+ */
+enum nsc_time_zones {
+ NSC_TIME_ZONE_IDLE,
+ NSC_TIME_ZONE_NZST,
+ NSC_TIME_ZONE_NZT,
+ NSC_TIME_ZONE_EAST,
+ NSC_TIME_ZONE_GST,
+ NSC_TIME_ZONE_JST,
+ NSC_TIME_ZONE_CCT,
+ NSC_TIME_ZONE_WAST,
+ NSC_TIME_ZONE_EET,
+ NSC_TIME_ZONE_CET,
+ NSC_TIME_ZONE_FWT,
+ NSC_TIME_ZONE_MET,
+ NSC_TIME_ZONE_MEWT,
+ NSC_TIME_ZONE_GMT,
+ NSC_TIME_ZONE_UTC,
+ NSC_TIME_ZONE_WET,
+ NSC_TIME_ZONE_WAT,
+ NSC_TIME_ZONE_AST,
+ NSC_TIME_ZONE_EST,
+ NSC_TIME_ZONE_CST,
+ NSC_TIME_ZONE_MST,
+ NSC_TIME_ZONE_PST,
+ NSC_TIME_ZONE_YST,
+ NSC_TIME_ZONE_AHST,
+ NSC_TIME_ZONE_CAT,
+ NSC_TIME_ZONE_HST,
+ NSC_TIME_ZONE_IDLW,
+ NSC_TIME_ZONE_NZDT,
+ NSC_TIME_ZONE_EADT,
+ NSC_TIME_ZONE_WADT,
+ NSC_TIME_ZONE_CEST,
+ NSC_TIME_ZONE_FST,
+ NSC_TIME_ZONE_MEST,
+ NSC_TIME_ZONE_MESZ,
+ NSC_TIME_ZONE_BST,
+ NSC_TIME_ZONE_ADT,
+ NSC_TIME_ZONE_EDT,
+ NSC_TIME_ZONE_CDT,
+ NSC_TIME_ZONE_MDT,
+ NSC_TIME_ZONE_PDT,
+ NSC_TIME_ZONE_YDT,
+ NSC_TIME_ZONE_HDT,
+ NSC_TIME_ZONE_Y,
+ NSC_TIME_ZONE_X,
+ NSC_TIME_ZONE_W,
+ NSC_TIME_ZONE_V,
+ NSC_TIME_ZONE_U,
+ NSC_TIME_ZONE_T,
+ NSC_TIME_ZONE_S,
+ NSC_TIME_ZONE_R,
+ NSC_TIME_ZONE_Q,
+ NSC_TIME_ZONE_P,
+ NSC_TIME_ZONE_O,
+ NSC_TIME_ZONE_N,
+ NSC_TIME_ZONE_Z,
+ NSC_TIME_ZONE_A,
+ NSC_TIME_ZONE_B,
+ NSC_TIME_ZONE_C,
+ NSC_TIME_ZONE_D,
+ NSC_TIME_ZONE_E,
+ NSC_TIME_ZONE_F,
+ NSC_TIME_ZONE_G,
+ NSC_TIME_ZONE_H,
+ NSC_TIME_ZONE_I,
+ NSC_TIME_ZONE_K,
+ NSC_TIME_ZONE_L,
+ NSC_TIME_ZONE_M,
+ NSC_TIME_ZONE__COUNT
+};
+
+/**
+ * Array of minute offsets for timezones.
+ */
+static const int16_t timezone_mins[NSC_TIME_ZONE__COUNT] = {
+ [NSC_TIME_ZONE_IDLE] = NSC_TIME_ZONE_OFFSET_IDLE,
+ [NSC_TIME_ZONE_NZST] = NSC_TIME_ZONE_OFFSET_NZST,
+ [NSC_TIME_ZONE_NZT] = NSC_TIME_ZONE_OFFSET_NZT,
+ [NSC_TIME_ZONE_EAST] = NSC_TIME_ZONE_OFFSET_EAST,
+ [NSC_TIME_ZONE_GST] = NSC_TIME_ZONE_OFFSET_GST,
+ [NSC_TIME_ZONE_JST] = NSC_TIME_ZONE_OFFSET_JST,
+ [NSC_TIME_ZONE_CCT] = NSC_TIME_ZONE_OFFSET_CCT,
+ [NSC_TIME_ZONE_WAST] = NSC_TIME_ZONE_OFFSET_WAST,
+ [NSC_TIME_ZONE_EET] = NSC_TIME_ZONE_OFFSET_EET,
+ [NSC_TIME_ZONE_CET] = NSC_TIME_ZONE_OFFSET_CET,
+ [NSC_TIME_ZONE_FWT] = NSC_TIME_ZONE_OFFSET_FWT,
+ [NSC_TIME_ZONE_MET] = NSC_TIME_ZONE_OFFSET_MET,
+ [NSC_TIME_ZONE_MEWT] = NSC_TIME_ZONE_OFFSET_MEWT,
+ [NSC_TIME_ZONE_GMT] = NSC_TIME_ZONE_OFFSET_GMT,
+ [NSC_TIME_ZONE_UTC] = NSC_TIME_ZONE_OFFSET_UTC,
+ [NSC_TIME_ZONE_WET] = NSC_TIME_ZONE_OFFSET_WET,
+ [NSC_TIME_ZONE_WAT] = NSC_TIME_ZONE_OFFSET_WAT,
+ [NSC_TIME_ZONE_AST] = NSC_TIME_ZONE_OFFSET_AST,
+ [NSC_TIME_ZONE_EST] = NSC_TIME_ZONE_OFFSET_EST,
+ [NSC_TIME_ZONE_CST] = NSC_TIME_ZONE_OFFSET_CST,
+ [NSC_TIME_ZONE_MST] = NSC_TIME_ZONE_OFFSET_MST,
+ [NSC_TIME_ZONE_PST] = NSC_TIME_ZONE_OFFSET_PST,
+ [NSC_TIME_ZONE_YST] = NSC_TIME_ZONE_OFFSET_YST,
+ [NSC_TIME_ZONE_AHST] = NSC_TIME_ZONE_OFFSET_AHST,
+ [NSC_TIME_ZONE_CAT] = NSC_TIME_ZONE_OFFSET_CAT,
+ [NSC_TIME_ZONE_HST] = NSC_TIME_ZONE_OFFSET_HST,
+ [NSC_TIME_ZONE_IDLW] = NSC_TIME_ZONE_OFFSET_IDLW,
+ [NSC_TIME_ZONE_NZDT] = NSC_TIME_ZONE_OFFSET_NZDT,
+ [NSC_TIME_ZONE_EADT] = NSC_TIME_ZONE_OFFSET_EADT,
+ [NSC_TIME_ZONE_WADT] = NSC_TIME_ZONE_OFFSET_WADT,
+ [NSC_TIME_ZONE_CEST] = NSC_TIME_ZONE_OFFSET_CEST,
+ [NSC_TIME_ZONE_FST] = NSC_TIME_ZONE_OFFSET_FST,
+ [NSC_TIME_ZONE_MEST] = NSC_TIME_ZONE_OFFSET_MEST,
+ [NSC_TIME_ZONE_MESZ] = NSC_TIME_ZONE_OFFSET_MESZ,
+ [NSC_TIME_ZONE_BST] = NSC_TIME_ZONE_OFFSET_BST,
+ [NSC_TIME_ZONE_ADT] = NSC_TIME_ZONE_OFFSET_ADT,
+ [NSC_TIME_ZONE_EDT] = NSC_TIME_ZONE_OFFSET_EDT,
+ [NSC_TIME_ZONE_CDT] = NSC_TIME_ZONE_OFFSET_CDT,
+ [NSC_TIME_ZONE_MDT] = NSC_TIME_ZONE_OFFSET_MDT,
+ [NSC_TIME_ZONE_PDT] = NSC_TIME_ZONE_OFFSET_PDT,
+ [NSC_TIME_ZONE_YDT] = NSC_TIME_ZONE_OFFSET_YDT,
+ [NSC_TIME_ZONE_HDT] = NSC_TIME_ZONE_OFFSET_HDT,
+ [NSC_TIME_ZONE_Y] = NSC_TIME_ZONE_OFFSET_Y,
+ [NSC_TIME_ZONE_X] = NSC_TIME_ZONE_OFFSET_X,
+ [NSC_TIME_ZONE_W] = NSC_TIME_ZONE_OFFSET_W,
+ [NSC_TIME_ZONE_V] = NSC_TIME_ZONE_OFFSET_V,
+ [NSC_TIME_ZONE_U] = NSC_TIME_ZONE_OFFSET_U,
+ [NSC_TIME_ZONE_T] = NSC_TIME_ZONE_OFFSET_T,
+ [NSC_TIME_ZONE_S] = NSC_TIME_ZONE_OFFSET_S,
+ [NSC_TIME_ZONE_R] = NSC_TIME_ZONE_OFFSET_R,
+ [NSC_TIME_ZONE_Q] = NSC_TIME_ZONE_OFFSET_Q,
+ [NSC_TIME_ZONE_P] = NSC_TIME_ZONE_OFFSET_P,
+ [NSC_TIME_ZONE_O] = NSC_TIME_ZONE_OFFSET_O,
+ [NSC_TIME_ZONE_N] = NSC_TIME_ZONE_OFFSET_N,
+ [NSC_TIME_ZONE_Z] = NSC_TIME_ZONE_OFFSET_Z,
+ [NSC_TIME_ZONE_A] = NSC_TIME_ZONE_OFFSET_A,
+ [NSC_TIME_ZONE_B] = NSC_TIME_ZONE_OFFSET_B,
+ [NSC_TIME_ZONE_C] = NSC_TIME_ZONE_OFFSET_C,
+ [NSC_TIME_ZONE_D] = NSC_TIME_ZONE_OFFSET_D,
+ [NSC_TIME_ZONE_E] = NSC_TIME_ZONE_OFFSET_E,
+ [NSC_TIME_ZONE_F] = NSC_TIME_ZONE_OFFSET_F,
+ [NSC_TIME_ZONE_G] = NSC_TIME_ZONE_OFFSET_G,
+ [NSC_TIME_ZONE_H] = NSC_TIME_ZONE_OFFSET_H,
+ [NSC_TIME_ZONE_I] = NSC_TIME_ZONE_OFFSET_I,
+ [NSC_TIME_ZONE_K] = NSC_TIME_ZONE_OFFSET_K,
+ [NSC_TIME_ZONE_L] = NSC_TIME_ZONE_OFFSET_L,
+ [NSC_TIME_ZONE_M] = NSC_TIME_ZONE_OFFSET_M
+};
+
+/**
+ * Array of timezone names. Order does not matter.
+ */
+static const char * const timezones[NSC_TIME_ZONE__COUNT] = {
+ [NSC_TIME_ZONE_IDLE] = "IDLE",
+ [NSC_TIME_ZONE_NZST] = "NZST",
+ [NSC_TIME_ZONE_NZT] = "NZT",
+ [NSC_TIME_ZONE_EAST] = "EAST",
+ [NSC_TIME_ZONE_GST] = "GST",
+ [NSC_TIME_ZONE_JST] = "JST",
+ [NSC_TIME_ZONE_CCT] = "CCT",
+ [NSC_TIME_ZONE_WAST] = "WAST",
+ [NSC_TIME_ZONE_EET] = "EET",
+ [NSC_TIME_ZONE_CET] = "CET",
+ [NSC_TIME_ZONE_FWT] = "FWT",
+ [NSC_TIME_ZONE_MET] = "MET",
+ [NSC_TIME_ZONE_MEWT] = "MEWT",
+ [NSC_TIME_ZONE_GMT] = "GMT",
+ [NSC_TIME_ZONE_UTC] = "UTC",
+ [NSC_TIME_ZONE_WET] = "WET",
+ [NSC_TIME_ZONE_WAT] = "WAT",
+ [NSC_TIME_ZONE_AST] = "AST",
+ [NSC_TIME_ZONE_EST] = "EST",
+ [NSC_TIME_ZONE_CST] = "CST",
+ [NSC_TIME_ZONE_MST] = "MST",
+ [NSC_TIME_ZONE_PST] = "PST",
+ [NSC_TIME_ZONE_YST] = "YST",
+ [NSC_TIME_ZONE_AHST] = "AHST",
+ [NSC_TIME_ZONE_CAT] = "CAT",
+ [NSC_TIME_ZONE_HST] = "HST",
+ [NSC_TIME_ZONE_IDLW] = "IDLW",
+ [NSC_TIME_ZONE_NZDT] = "NZDT",
+ [NSC_TIME_ZONE_EADT] = "EADT",
+ [NSC_TIME_ZONE_WADT] = "WADT",
+ [NSC_TIME_ZONE_CEST] = "CEST",
+ [NSC_TIME_ZONE_FST] = "FST",
+ [NSC_TIME_ZONE_MEST] = "MEST",
+ [NSC_TIME_ZONE_MESZ] = "MESZ",
+ [NSC_TIME_ZONE_BST] = "BST",
+ [NSC_TIME_ZONE_ADT] = "ADT",
+ [NSC_TIME_ZONE_EDT] = "EDT",
+ [NSC_TIME_ZONE_CDT] = "CDT",
+ [NSC_TIME_ZONE_MDT] = "MDT",
+ [NSC_TIME_ZONE_PDT] = "PDT",
+ [NSC_TIME_ZONE_YDT] = "YDT",
+ [NSC_TIME_ZONE_HDT] = "HDT",
+ [NSC_TIME_ZONE_Y] = "Y",
+ [NSC_TIME_ZONE_X] = "X",
+ [NSC_TIME_ZONE_W] = "W",
+ [NSC_TIME_ZONE_V] = "V",
+ [NSC_TIME_ZONE_U] = "U",
+ [NSC_TIME_ZONE_T] = "T",
+ [NSC_TIME_ZONE_S] = "S",
+ [NSC_TIME_ZONE_R] = "R",
+ [NSC_TIME_ZONE_Q] = "Q",
+ [NSC_TIME_ZONE_P] = "P",
+ [NSC_TIME_ZONE_O] = "O",
+ [NSC_TIME_ZONE_N] = "N",
+ [NSC_TIME_ZONE_Z] = "Z",
+ [NSC_TIME_ZONE_A] = "A",
+ [NSC_TIME_ZONE_B] = "B",
+ [NSC_TIME_ZONE_C] = "C",
+ [NSC_TIME_ZONE_D] = "D",
+ [NSC_TIME_ZONE_E] = "E",
+ [NSC_TIME_ZONE_F] = "F",
+ [NSC_TIME_ZONE_G] = "G",
+ [NSC_TIME_ZONE_H] = "H",
+ [NSC_TIME_ZONE_I] = "I",
+ [NSC_TIME_ZONE_K] = "K",
+ [NSC_TIME_ZONE_L] = "L",
+ [NSC_TIME_ZONE_M] = "M"
+};
+
+/**
+ * Flags for tracking the components of a date that have been parsed.
+ */
+enum nsc_date_component_flags {
+ NSC_COMPONENT_FLAGS_NONE = 0,
+ NSC_COMPONENT_FLAGS_HAVE_YEARS = (1 << 0),
+ NSC_COMPONENT_FLAGS_HAVE_MONTHS = (1 << 1),
+ NSC_COMPONENT_FLAGS_HAVE_DAYS = (1 << 2),
+ NSC_COMPONENT_FLAGS_HAVE_HOURS = (1 << 3),
+ NSC_COMPONENT_FLAGS_HAVE_MINS = (1 << 4),
+ NSC_COMPONENT_FLAGS_HAVE_SECS = (1 << 5),
+ NSC_COMPONENT_FLAGS_HAVE_TIMEZONE = (1 << 6),
+ NSC_COMPONENT_FLAGS_HAVE_WEEKDAY = (1 << 7),
+ NSC_COMPONENT_FLAGS__HAVE_YYYYMMDD =
+ NSC_COMPONENT_FLAGS_HAVE_YEARS |
+ NSC_COMPONENT_FLAGS_HAVE_MONTHS |
+ NSC_COMPONENT_FLAGS_HAVE_DAYS,
+ NSC_COMPONENT_FLAGS__HAVE_HHMMSS =
+ NSC_COMPONENT_FLAGS_HAVE_HOURS |
+ NSC_COMPONENT_FLAGS_HAVE_MINS |
+ NSC_COMPONENT_FLAGS_HAVE_SECS,
+ NSC_COMPONENT_FLAGS__HAVE_ALL =
+ NSC_COMPONENT_FLAGS_HAVE_YEARS |
+ NSC_COMPONENT_FLAGS_HAVE_MONTHS |
+ NSC_COMPONENT_FLAGS_HAVE_DAYS |
+ NSC_COMPONENT_FLAGS_HAVE_HOURS |
+ NSC_COMPONENT_FLAGS_HAVE_MINS |
+ NSC_COMPONENT_FLAGS_HAVE_SECS |
+ NSC_COMPONENT_FLAGS_HAVE_TIMEZONE
+};
+
+/**
+ * Context for date parsing.
+ */
+struct nsc_date_parse_ctx {
+ enum {
+ PARSE_STATE_NONE,
+ PARSE_STATE_HAD_PLUS,
+ PARSE_STATE_HAD_MINUS
+ } state; /**< Used for handling neumenrical timezone */
+ uint8_t secs;
+ uint8_t mins;
+ uint8_t hours;
+ uint8_t day;
+ uint8_t month;
+ uint16_t years;
+ int16_t timezone_offset_mins;
+};
+
+
+/**
+ * Helper for testing whether any of the flags in mask are set.
+ *
+ * \param[in] flags Flags to to check.
+ * \param[in] mask The set of flags to check for in `flags`.
+ * \return true iff any flags in `mask` are set in `flags`, else false.
+ */
+static bool flags_chk(
+ enum nsc_date_component_flags flags,
+ enum nsc_date_component_flags mask)
+{
+ return flags & mask;
+}
+
+/**
+ * Helper for testing whether all of the flags in mask are set.
+ *
+ * \param[in] flags Flags to to check.
+ * \param[in] mask The set of flags to check for in `flags`.
+ * \return true iff all flags in `mask` are set in `flags`, else false.
+ */
+static bool flags_chk_all(
+ enum nsc_date_component_flags flags,
+ enum nsc_date_component_flags mask)
+{
+ return (flags & mask) == mask;
+}
+
+
+/**
+ * Test for a weekday name in a string (case insensitive).
+ *
+ * \param[in] str String to parse a weekday name in.
+ * \param[in,out] flags Flags indicating which date components have been
+ * found in `str` already. If a weekday component
+ * is found, the weekday flag is set.
+ * \param[in] len Number of consecutive alphabetical characters.
+ * \return true iff weekday component is found, else false.
+ */
+static inline bool time__parse_weekday(
+ const char *str,
+ enum nsc_date_component_flags *flags,
+ size_t len)
+{
+ const char * const *names = (len == 3) ?
+ weekdays_short : weekdays_long;
+
+ if (flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_WEEKDAY)) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < NSC_TIME_WEEKDAY__COUNT; i++) {
+ if (ascii_strings_equal_caseless(names[i], str)) {
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_WEEKDAY;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * Attempt to parse a month name in a string (case insensitive).
+ *
+ * \param[in] str String to parse a month name in.
+ * \param[in,out] flags Flags indicating which date components have been
+ * found in `str` already. If a month component
+ * is found, the month flag is set.
+ * \param[in,out] ctx Current date parsing context. If month component
+ * is found, the context's month value is set.
+ * \return true iff month name component is found, else false.
+ */
+static inline bool time__parse_month(
+ const char *str,
+ enum nsc_date_component_flags *flags,
+ struct nsc_date_parse_ctx *ctx)
+{
+ if (flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_MONTHS)) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < NSC_TIME_MONTH__COUNT; i++) {
+ if (ascii_strings_equal_caseless(months[i], str)) {
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_MONTHS;
+ ctx->month = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * Attempt to parse a timezone name in a string (case insensitive).
+ *
+ * \param[in] str String to parse a timezone name in.
+ * \param[in,out] flags Flags indicating which date components have been
+ * found in `str` already. If a timezone component
+ * is found, the timezone flag is set.
+ * \param[in,out] ctx Current date parsing context. If timezone component
+ * is found, the context's timezone value is set.
+ * \return true iff timezone name component is found, else false.
+ */
+static inline bool time__parse_timezone(
+ const char *str,
+ enum nsc_date_component_flags *flags,
+ struct nsc_date_parse_ctx *ctx)
+{
+ if (flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_TIMEZONE)) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < NSC_TIME_ZONE__COUNT; i++) {
+ if (ascii_strings_equal_caseless(timezones[i], str)) {
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_TIMEZONE;
+ ctx->timezone_offset_mins = timezone_mins[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * Attempt to parse an "hh:mm:ss" time from a string.
+ *
+ * \param[in] str String to parse a time in.
+ * \param[in,out] flags Flags indicating which date components have been
+ * found in `str` already. If a time component
+ * is found, the hours, mins and secs flags are set.
+ * \param[in,out] ctx Current date parsing context. If time component
+ * is found, the context's time values are set.
+ * \param[in,out] len The number of characters until the first non-digit.
+ * Iff a time component is found, updated to the number
+ * of comsumend characters.
+ * \return true iff time component is found, else false.
+ */
+static inline bool time__parse_hh_mm_ss(
+ const char *str,
+ enum nsc_date_component_flags *flags,
+ struct nsc_date_parse_ctx *ctx,
+ size_t *len)
+{
+ size_t l;
+
+ if (*len != 2 || flags_chk(*flags, NSC_COMPONENT_FLAGS__HAVE_HHMMSS)) {
+ return false;
+ }
+
+ l = *len + ascii_count_digit_or_colon(str + *len);
+ if (l == 8) {
+ int h, m, s, count;
+ count = sscanf(str, "%02d:%02d:%02d", &h, &m, &s);
+ if (count == 3) {
+ ctx->hours = h;
+ ctx->mins = m;
+ ctx->secs = s;
+ *flags |= NSC_COMPONENT_FLAGS__HAVE_HHMMSS;
+ *len = l;
+ return true;
+ }
+ } else if (l == 5) {
+ int h, m, count;
+ count = sscanf(str, "%02d:%02d", &h, &m);
+ if (count == 2) {
+ ctx->hours = h;
+ ctx->mins = m;
+ ctx->secs = 0;
+ *flags |= NSC_COMPONENT_FLAGS__HAVE_HHMMSS;
+ *len = l;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * Attempt to parse a number from a date string.
+ *
+ * How the number is treated depends on various things:
+ *
+ * - its character length,
+ * - its value,
+ * - which date components have already been parsed
+ *
+ * \param[in] str String to parse a time in.
+ * \param[in,out] flags Flags indicating which date components have been
+ * found in `str` already. If any component is found,
+ * their flags are set.
+ * \param[in,out] ctx Current date parsing context. If any component
+ * is found, the appropriate context values are set.
+ * \param[in] len The number of characters until the first non-digit.
+ * \return true iff a component is found, else false.
+ */
+static inline bool time__parse_number(
+ const char *str,
+ enum nsc_date_component_flags *flags,
+ struct nsc_date_parse_ctx *ctx,
+ size_t len)
+{
+ int value;
+
+ if (len != ascii_string_to_int(str, &value)) {
+ return false;
+ }
+
+ switch (len) {
+ case 8:
+ if (!flags_chk(*flags, NSC_COMPONENT_FLAGS__HAVE_YYYYMMDD)) {
+ ctx->years = value / 10000;
+ ctx->month = (value % 10000) / 100 - 1;
+ ctx->day = value % 100 - 1;
+ *flags |= NSC_COMPONENT_FLAGS__HAVE_YYYYMMDD;
+ return true;
+ }
+ break;
+
+ case 4:
+ if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_TIMEZONE)) {
+ if (ctx->state != PARSE_STATE_NONE &&
+ value <= 1400) {
+ ctx->timezone_offset_mins =
+ value / 100 * 60 +
+ value % 100;
+ if (ctx->state == PARSE_STATE_HAD_PLUS) {
+ ctx->timezone_offset_mins *= -1;
+ }
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_TIMEZONE;
+ return true;
+ }
+ }
+ if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_YEARS)) {
+ ctx->years = value;
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_YEARS;
+ return true;
+ }
+ break;
+
+ case 2:
+ case 1:
+ if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_DAYS) &&
+ value > 0 && value <= 31) {
+ ctx->day = value - 1;
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_DAYS;
+ return true;
+ }
+ if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_YEARS)) {
+ ctx->years = (value > 70) ?
+ value + 1900 :
+ value + 2000;
+ *flags |= NSC_COMPONENT_FLAGS_HAVE_YEARS;
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/**
+ * Get number of leap days up until end of given year.
+ *
+ * \param[in] year Year to count leap years up to.
+ * \return Number of leap days up to end of `year`.
+ */
+static inline int time__get_leap_days(int year)
+{
+ return (year / 4) - (year / 100) + (year / 400);
+}
+
+
+/**
+ * Helper to convert a date string context to a time_t.
+ *
+ * \param[in] ctx Current date parsing context.
+ * \param[in] flags Flags indicating which date components have been set.
+ * \param[out] time Returns the number of seconds since 1 Jan 1970 00:00 UTC.
+ * \return NSERROR_OK on success, appropriate error otherwise.
+ */
+static nserror time__ctx_to_time_t(
+ const struct nsc_date_parse_ctx *ctx,
+ enum nsc_date_component_flags flags,
+ time_t *time)
+{
+ enum {
+ NSC_MONTH_DAYS_JAN = 31,
+ NSC_MONTH_DAYS_FEB = 28, /**< Leap years handled separatly */
+ NSC_MONTH_DAYS_MAR = 31,
+ NSC_MONTH_DAYS_APR = 30,
+ NSC_MONTH_DAYS_MAY = 31,
+ NSC_MONTH_DAYS_JUN = 30,
+ NSC_MONTH_DAYS_JUL = 31,
+ NSC_MONTH_DAYS_AUG = 31,
+ NSC_MONTH_DAYS_SEP = 30,
+ NSC_MONTH_DAYS_OCT = 31,
+ NSC_MONTH_DAYS_NOV = 30,
+ NSC_MONTH_DAYS_DEC = 31
+ };
+ enum {
+ NSC_MONTH_OFF_JAN = 0,
+ NSC_MONTH_OFF_FEB = NSC_MONTH_OFF_JAN + NSC_MONTH_DAYS_JAN,
+ NSC_MONTH_OFF_MAR = NSC_MONTH_OFF_FEB + NSC_MONTH_DAYS_FEB,
+ NSC_MONTH_OFF_APR = NSC_MONTH_OFF_MAR + NSC_MONTH_DAYS_MAR,
+ NSC_MONTH_OFF_MAY = NSC_MONTH_OFF_APR + NSC_MONTH_DAYS_APR,
+ NSC_MONTH_OFF_JUN = NSC_MONTH_OFF_MAY + NSC_MONTH_DAYS_MAY,
+ NSC_MONTH_OFF_JUL = NSC_MONTH_OFF_JUN + NSC_MONTH_DAYS_JUN,
+ NSC_MONTH_OFF_AUG = NSC_MONTH_OFF_JUL + NSC_MONTH_DAYS_JUL,
+ NSC_MONTH_OFF_SEP = NSC_MONTH_OFF_AUG + NSC_MONTH_DAYS_AUG,
+ NSC_MONTH_OFF_OCT = NSC_MONTH_OFF_SEP + NSC_MONTH_DAYS_SEP,
+ NSC_MONTH_OFF_NOV = NSC_MONTH_OFF_OCT + NSC_MONTH_DAYS_OCT,
+ NSC_MONTH_OFF_DEC = NSC_MONTH_OFF_NOV + NSC_MONTH_DAYS_NOV
+ };
+ static const uint16_t month_offsets[NSC_TIME_MONTH__COUNT] = {
+ [NSC_TIME_MONTH_JAN] = NSC_MONTH_OFF_JAN,
+ [NSC_TIME_MONTH_FEB] = NSC_MONTH_OFF_FEB,
+ [NSC_TIME_MONTH_MAR] = NSC_MONTH_OFF_MAR,
+ [NSC_TIME_MONTH_APR] = NSC_MONTH_OFF_APR,
+ [NSC_TIME_MONTH_MAY] = NSC_MONTH_OFF_MAY,
+ [NSC_TIME_MONTH_JUN] = NSC_MONTH_OFF_JUN,
+ [NSC_TIME_MONTH_JUL] = NSC_MONTH_OFF_JUL,
+ [NSC_TIME_MONTH_AUG] = NSC_MONTH_OFF_AUG,
+ [NSC_TIME_MONTH_SEP] = NSC_MONTH_OFF_SEP,
+ [NSC_TIME_MONTH_OCT] = NSC_MONTH_OFF_OCT,
+ [NSC_TIME_MONTH_NOV] = NSC_MONTH_OFF_NOV,
+ [NSC_TIME_MONTH_DEC] = NSC_MONTH_OFF_DEC
+ };
+ int year_days = (ctx->years - 1970) * 365;
+ int month_days = month_offsets[ctx->month];
+ int year = (ctx->month < NSC_TIME_MONTH_FEB) ?
+ ctx->years - 1 : ctx->years;
+ int leap_days = time__get_leap_days(year) - time__get_leap_days(1969);
+ int total_days = year_days + month_days + ctx->day + leap_days;
+
+ int mins = (int)ctx->mins + (int)ctx->timezone_offset_mins;
+
+ *time = (((((time_t)(total_days)) * 24) +
+ ctx->hours) * 60 +
+ mins) * 60 +
+ ctx->secs;
+ return NSERROR_OK;
+}
+
+
+/**
+ * Parse a date string to a `time_t`.
+ *
+ * \param[in] str String to parse.
+ * \param[out] time Returns the number of seconds since 1 Jan 1970 00:00 UTC.
+ * \return `NSERROR_OK` on success, else
+ * `NSERROR_INVALID` if the string parsing failed,
+ * appropriate error otherwise.
+ */
+static nserror time__get_date(const char *str, time_t *time)
+{
+ enum nsc_date_component_flags flags = NSC_COMPONENT_FLAGS_NONE;
+ struct nsc_date_parse_ctx ctx = {
+ .state = PARSE_STATE_NONE,
+ .secs = 0,
+ .mins = 0,
+ .hours = 0,
+ .day = 0,
+ .month = 0,
+ .years = 0,
+ .timezone_offset_mins = 0
+ };
+
+ if (str == NULL || time == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* Parse */
+ while (*str != '\0' &&
+ !flags_chk_all(flags, NSC_COMPONENT_FLAGS__HAVE_ALL)) {
+
+ if (isspace(*str)) {
+ str++;
+
+ } else if (ascii_is_alpha(*str)) {
+ size_t len = ascii_count_alpha(str + 1) + 1;
+
+ if (!time__parse_weekday(str, &flags, len) &&
+ !time__parse_month(str, &flags, &ctx) &&
+ !time__parse_timezone(str, &flags, &ctx)) {
+ return NSERROR_INVALID;
+ }
+
+ str += len;
+
+ } else if (ascii_is_digit(*str)) {
+ size_t len = ascii_count_digit(str + 1) + 1;
+
+ if (!time__parse_hh_mm_ss(str, &flags, &ctx, &len) &&
+ !time__parse_number(str, &flags, &ctx, len)) {
+ return NSERROR_INVALID;
+ }
+
+ str += len;
+
+ } else if (*str == '+') {
+ ctx.state = PARSE_STATE_HAD_PLUS;
+ str++;
+ continue;
+
+ } else if (*str == '-') {
+ ctx.state = PARSE_STATE_HAD_MINUS;
+ str++;
+ continue;
+
+ } else {
+ str++;
+ }
+
+ ctx.state = PARSE_STATE_NONE;
+ }
+
+ /* The initial values of 0 are used if hours, mins, secs, and timezone
+ * are not found */
+ flags |= NSC_COMPONENT_FLAGS__HAVE_HHMMSS;
+ flags |= NSC_COMPONENT_FLAGS_HAVE_TIMEZONE;
+
+ /* Validate */
+ if (!flags_chk_all(flags, NSC_COMPONENT_FLAGS__HAVE_ALL)) {
+ return NSERROR_INVALID;
+ }
+ if (ctx.secs > 60 || ctx.mins > 59 || ctx.hours > 23 ||
+ ctx.day > 31 || ctx.month > 11) {
+ return NSERROR_INVALID;
+ }
+
+ /* Convert */
+ return time__ctx_to_time_t(&ctx, flags, time);
+}
+
+/* exported function documented in utils/time.h */
+nserror nsc_strntimet(const char *str, size_t size, time_t *timep)
+{
+ return time__get_date(str, timep);
+}
+
+# else
+
/* exported function documented in utils/time.h */
nserror nsc_strntimet(const char *str, size_t size, time_t *timep)
{
@@ -196,3 +1018,5 @@ nserror nsc_strntimet(const char *str, size_t size, time_t
*timep)
return NSERROR_OK;
}
+
+#endif
-----------------------------------------------------------------------
Summary of changes:
--
NetSurf Browser
_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org