Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/947275176ff93d48621343e608ba522917f258c0
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/947275176ff93d48621343e608ba522917f258c0
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/947275176ff93d48621343e608ba522917f258c0

The branch, tlsa/date has been updated
  discards  ccab37655bbac21c0d9d76ae2ca354f616c7ed4d (commit)
  discards  1fa22b8718332edb110c72bb4373ffa992bfde8d (commit)
  discards  756f9727c67cc9fe26c865e4632ab1247c199d93 (commit)
       via  947275176ff93d48621343e608ba522917f258c0 (commit)
       via  415678aa14eb4c15e8f6a41f528929b43d887576 (commit)
       via  a84965be1c25d39cc8891d3c446e063dfc95ed67 (commit)
       via  206b258bd1ead216f5274af14a85290c3af950c5 (commit)
       via  1158536bffb35ebaeca1b6bc7d4f39e49725a660 (commit)
       via  4b90528d3c1871118ed55c76b105805c8a63d539 (commit)
       via  655b619fd4fe3c1f09973b51f67e579c2bd89c00 (commit)
       via  c1aec1cfa0d5fa64dff2d177800797d7e3d8c15c (commit)
       via  05d2b9a92cd718a38aed647400159c6c40a743d2 (commit)
       via  aa10f2f1efd9e910b675381c7be3d363c019e06a (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 (ccab37655bbac21c0d9d76ae2ca354f616c7ed4d)
            \
             N -- N -- N (947275176ff93d48621343e608ba522917f258c0)

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=947275176ff93d48621343e608ba522917f258c0
commit 947275176ff93d48621343e608ba522917f258c0
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Work in progress: Add date parsing tests.

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..8598646
--- /dev/null
+++ b/test/time.c
@@ -0,0 +1,108 @@
+/*
+ * 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 <curl/curl.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;
+};
+
+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     = "Thu, 16 Aug 2007 19:45:12 GMT",
+               .expected = "Thu, 16 Aug 2007 19:45:12 GMT"
+       },
+};
+
+/**
+ * url creation 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);
+       if (time_out < 0) {
+               /* result must be invalid */
+               ck_assert(res != NSERROR_OK);
+
+       } else {
+               /* result must be valid */
+               ck_assert(res == NSERROR_OK);
+
+               ck_assert_str_eq(rfc1123_date(time_out), t->expected);
+       }
+}
+END_TEST
+
+
+/* suite generation */
+static Suite *time_suite(void)
+{
+       Suite *s;
+       TCase *tc_date_string_compare;
+
+       s = suite_create("time");
+
+       /* date parsing: string comparason */
+       tc_date_string_compare = tcase_create("date string to time_t");
+
+       tcase_add_loop_test(tc_date_string_compare,
+                           date_string_compare,
+                           0, NELEMS(date_string_tests));
+       suite_add_tcase(s, tc_date_string_compare);
+
+       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=415678aa14eb4c15e8f6a41f528929b43d887576
commit 415678aa14eb4c15e8f6a41f528929b43d887576
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..667e836 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
  *
@@ -181,6 +185,829 @@ nserror nsc_snptimet(const char *str, size_t size, time_t 
*timep)
 }
 
 
+#ifndef USE_CURL
+
+
+/**
+ * Array of long weekday names.
+ */
+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.
+ */
+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.
+ */
+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_MINUS) {
+                                       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:
+               if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_DAYS) &&
+                               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;
+
+       case 1:
+               if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_DAYS)) {
+                       ctx->day = value - 1;
+                       *flags |= NSC_COMPONENT_FLAGS_HAVE_DAYS;
+                       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 || *str == '\0' || 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 not found */
+       flags |= NSC_COMPONENT_FLAGS__HAVE_HHMMSS;
+
+       /* 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 +1023,5 @@ nserror nsc_strntimet(const char *str, size_t size, time_t 
*timep)
 
        return NSERROR_OK;
 }
+
+#endif


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=a84965be1c25d39cc8891d3c446e063dfc95ed67
commit a84965be1c25d39cc8891d3c446e063dfc95ed67
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Utils: Add a set of ASCII string parsing helpers.
    
    These are not affected by the current locale.

diff --git a/utils/ascii.h b/utils/ascii.h
new file mode 100644
index 0000000..ca26999
--- /dev/null
+++ b/utils/ascii.h
@@ -0,0 +1,239 @@
+/*
+ * 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 utils/ascii.h
+ * \brief Helpers for ASCII string handling.
+ *
+ * These helpers for string parsing will have the correct effect for parsing
+ * ASCII text (as used by most web specs), regardless of system locale.
+ */
+
+#ifndef _NETSURF_UTILS_ASCII_H_
+#define _NETSURF_UTILS_ASCII_H_
+
+#include <stdlib.h>
+#include <limits.h>
+
+/**
+ * Test whether a character is lower-case alphabetical.
+ *
+ * \param[in] c  Character to test.
+ * \return true iff `c` is lower-case alphabetical, else false.
+ */
+static inline bool ascii_is_alpha_lower(char c)
+{
+       return (c >= 'a' && c <= 'z');
+}
+
+/**
+ * Test whether a character is upper-case alphabetical.
+ *
+ * \param[in] c  Character to test.
+ * \return true iff `c` is upper-case alphabetical, else false.
+ */
+static inline bool ascii_is_alpha_upper(char c)
+{
+       return (c >= 'A' && c <= 'Z');
+}
+
+/**
+ * Test whether a character is alphabetical (upper or lower case).
+ *
+ * \param[in] c  Character to test.
+ * \return true iff `c` is alphabetical, else false.
+ */
+static inline bool ascii_is_alpha(char c)
+{
+       return (ascii_is_alpha_lower(c) || ascii_is_alpha_upper(c));
+}
+
+/**
+ * Test whether a character is a decimal digit.
+ *
+ * \param[in] c  Character to test.
+ * \return true iff `c` is a decimal digit, else false.
+ */
+static inline bool ascii_is_digit(char c)
+{
+       return (c >= '0' && c <= '9');
+}
+
+/**
+ * Convert an upper case character to lower case.
+ *
+ * If the given character is not upper case alphabetical, it is returned
+ * unchanged.
+ *
+ * \param[in] c  Character to convert.
+ * \return lower case conversion of `c` else `c`.
+ */
+static inline char ascii_to_lower(char c)
+{
+       return (ascii_is_alpha_upper(c)) ? (c + 'a' - 'A') : c;
+}
+
+/**
+ * Convert a lower case character to upper case.
+ *
+ * If the given character is not lower case alphabetical, it is returned
+ * unchanged.
+ *
+ * \param[in] c  Character to convert.
+ * \return upper case conversion of `c` else `c`.
+ */
+static inline char ascii_to_upper(char c)
+{
+       return (ascii_is_alpha_lower(c)) ? (c + 'A' - 'a') : c;
+}
+
+/**
+ * Count consecutive lower case alphabetical characters in string.
+ *
+ * \param[in] str  String to count characters in.
+ * \return number of consecutive lower case characters at start of `str`.
+ */
+static inline size_t ascii_count_alpha_lower(const char *str)
+{
+       size_t count = 0;
+       while (ascii_is_alpha_lower(*(str++))) {
+               count++;
+       }
+       return count;
+}
+
+/**
+ * Count consecutive upper case alphabetical characters in string.
+ *
+ * \param[in] str  String to count characters in.
+ * \return number of consecutive upper case characters at start of `str`.
+ */
+static inline size_t ascii_count_alpha_upper(const char *str)
+{
+       size_t count = 0;
+       while (ascii_is_alpha_upper(*(str++))) {
+               count++;
+       }
+       return count;
+}
+
+/**
+ * Count consecutive alphabetical characters in string (upper or lower case).
+ *
+ * \param[in] str  String to count characters in.
+ * \return number of consecutive alphabetical characters at start of `str`.
+ */
+static inline size_t ascii_count_alpha(const char *str)
+{
+       size_t count = 0;
+       while (ascii_is_alpha(*(str++))) {
+               count++;
+       }
+       return count;
+}
+
+/**
+ * Count consecutive decial digit characters in string.
+ *
+ * \param[in] str  String to count characters in.
+ * \return number of consecutive decimal digit characters at start of `str`.
+ */
+static inline size_t ascii_count_digit(const char *str)
+{
+       size_t count = 0;
+       while (ascii_is_digit(*(str++))) {
+               count++;
+       }
+       return count;
+}
+
+/**
+ * Count consecutive characters either decimal digit or colon in string.
+ *
+ * \param[in] str  String to count characters in.
+ * \return number of consecutive decimal or ':' characters at start of `str`.
+ */
+static inline size_t ascii_count_digit_or_colon(const char *str)
+{
+       size_t count = 0;
+       while (ascii_is_digit(*str) || *str == ':') {
+               count++;
+               str++;
+       }
+       return count;
+}
+
+/**
+ * Test for string equality (case insensitive).
+ *
+ * \param[in] s1  First string to compare.
+ * \param[in] s2  Second string to compare.
+ * \return true iff strings are equivalent, else false.
+ */
+static inline bool ascii_strings_equal_caseless(
+               const char *s1, const char *s2)
+{
+       while (*s1 != '\0') {
+               if (ascii_to_lower(*(s1++)) != ascii_to_lower(*(s2++))) {
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
+ * Test for string equality (case sensitive).
+ *
+ * \param[in] s1  First string to compare.
+ * \param[in] s2  Second string to compare.
+ * \return true iff strings are equal, else false.
+ */
+static inline bool ascii_strings_equal(
+               const char *s1, const char *s2)
+{
+       while (*s1 != '\0') {
+               if (*(s1++) != *(s2++)) {
+                       return false;
+               }
+       }
+       return true;
+}
+
+/**
+ * Parse an int out of a string.
+ *
+ * \param[in]  str  String to parse integer out of.
+ * \param[out] res  Returns parsed integer.
+ * \return The number of characters consumed in `str`.
+ *         Returning 0 indicates failure to parse an integer out of the string.
+ */
+static inline size_t ascii_string_to_int(const char *str, int *res)
+{
+       char *end = NULL;
+       long long temp = strtoll(str, &end, 10);
+
+       if (end == str || errno == ERANGE ||
+                       temp < INT_MIN || temp > INT_MAX) {
+               return 0;
+       }
+
+       *res = temp;
+       return end - str;
+}
+
+#endif


commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=206b258bd1ead216f5274af14a85290c3af950c5
commit 206b258bd1ead216f5274af14a85290c3af950c5
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    Time: Expose arrays of weekday and month names.

diff --git a/utils/time.c b/utils/time.c
index cf8acc0..dd67d8a 100644
--- a/utils/time.c
+++ b/utils/time.c
@@ -35,20 +35,86 @@
 #include "utils/time.h"
 
 
+
+/**
+ * Weekdays
+ *
+ * Must be calender order.
+ */
+enum nsc_time_weekdays {
+       NSC_TIME_WEEKDAY_SUN,
+       NSC_TIME_WEEKDAY_MON,
+       NSC_TIME_WEEKDAY_TUE,
+       NSC_TIME_WEEKDAY_WED,
+       NSC_TIME_WEEKDAY_THU,
+       NSC_TIME_WEEKDAY_FRI,
+       NSC_TIME_WEEKDAY_SAT,
+       NSC_TIME_WEEKDAY__COUNT
+};
+/**
+ * Months
+ *
+ * Must be calender order.
+ */
+enum nsc_time_months {
+       NSC_TIME_MONTH_JAN,
+       NSC_TIME_MONTH_FEB,
+       NSC_TIME_MONTH_MAR,
+       NSC_TIME_MONTH_APR,
+       NSC_TIME_MONTH_MAY,
+       NSC_TIME_MONTH_JUN,
+       NSC_TIME_MONTH_JUL,
+       NSC_TIME_MONTH_AUG,
+       NSC_TIME_MONTH_SEP,
+       NSC_TIME_MONTH_OCT,
+       NSC_TIME_MONTH_NOV,
+       NSC_TIME_MONTH_DEC,
+       NSC_TIME_MONTH__COUNT,
+};
+
+
+/**
+ * Array of short weekday names.
+ */
+const char * const weekdays_short[NSC_TIME_WEEKDAY__COUNT] = {
+       [NSC_TIME_WEEKDAY_SUN] = "Sun",
+       [NSC_TIME_WEEKDAY_MON] = "Mon",
+       [NSC_TIME_WEEKDAY_TUE] = "Tue",
+       [NSC_TIME_WEEKDAY_WED] = "Wed",
+       [NSC_TIME_WEEKDAY_THU] = "Thu",
+       [NSC_TIME_WEEKDAY_FRI] = "Fri",
+       [NSC_TIME_WEEKDAY_SAT] = "Sat"
+};
+/**
+ * Array of month names.
+ */
+const char * const months[NSC_TIME_MONTH__COUNT] = {
+       [NSC_TIME_MONTH_JAN] = "Jan",
+       [NSC_TIME_MONTH_FEB] = "Feb",
+       [NSC_TIME_MONTH_MAR] = "Mar",
+       [NSC_TIME_MONTH_APR] = "Apr",
+       [NSC_TIME_MONTH_MAY] = "May",
+       [NSC_TIME_MONTH_JUN] = "Jun",
+       [NSC_TIME_MONTH_JUL] = "Jul",
+       [NSC_TIME_MONTH_AUG] = "Aug",
+       [NSC_TIME_MONTH_SEP] = "Sep",
+       [NSC_TIME_MONTH_OCT] = "Oct",
+       [NSC_TIME_MONTH_NOV] = "Nov",
+       [NSC_TIME_MONTH_DEC] = "Dec"
+};
+
+
 /* exported interface documented in utils/time.h */
 const char *rfc1123_date(time_t t)
 {
        static char ret[30];
 
        struct tm *tm = gmtime(&t);
-       const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 
},
-               *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
 
        snprintf(ret, sizeof ret, "%s, %02d %s %d %02d:%02d:%02d GMT",
-                       days[tm->tm_wday], tm->tm_mday, months[tm->tm_mon],
-                       tm->tm_year + 1900, tm->tm_hour, tm->tm_min,
-                       tm->tm_sec);
+                       weekdays_short[tm->tm_wday], tm->tm_mday,
+                       months[tm->tm_mon], tm->tm_year + 1900,
+                       tm->tm_hour, tm->tm_min, tm->tm_sec);
 
        return ret;
 }


-----------------------------------------------------------------------

Summary of changes:
 content/urldb.c  |   30 +++++---
 test/Makefile    |   25 ++++++-
 test/data/urldb  |  101 ++++++++++++++++++++++++++
 test/nsurl.c     |    2 +-
 test/time.c      |  108 ++++++++++++++++++++++++++++
 test/urldbtest.c |  210 ++++++++++++++++++++++++++++++++++++++----------------
 test/utils.c     |    6 +-
 utils/ascii.h    |    2 +-
 utils/time.c     |   26 +++----
 utils/utils.c    |    1 +
 10 files changed, 421 insertions(+), 90 deletions(-)
 create mode 100644 test/data/urldb
 create mode 100644 test/time.c

diff --git a/content/urldb.c b/content/urldb.c
index 2f7b4a7..3525492 100644
--- a/content/urldb.c
+++ b/content/urldb.c
@@ -1343,25 +1343,37 @@ static void urldb_dump_hosts(struct host_part *parent)
 static void urldb_dump_search(struct search_node *parent, int depth)
 {
        const struct host_part *h;
-       int i;
-
+       int i; /* index into string */
+       char s[1024];
+       int r;
+       int sl = sizeof(s) - 2;
+       
        if (parent == &empty)
                return;
 
        urldb_dump_search(parent->left, depth + 1);
 
-       for (i = 0; i != depth; i++)
-                       fputc(' ', stderr);
+       for (i = 0; i != depth; i++) {
+               s[i] = ' ';
+       }
 
        for (h = parent->data; h; h = h->parent) {
-               if (h->part)
-                       fprintf(stderr, "%s", h->part);
+               if (h->part) {
+                       r = snprintf(&s[i], sl - i, "%s", h->part);
+                       if ((i + r) > sl) {
+                               break;
+                       }
+                       i += r;
+               }
 
-               if (h->parent && h->parent->parent)
-                       fputc('.', stderr);
+               if (h->parent && h->parent->parent) {
+                       s[i]='.';
+                       i++;
+               }
        }
+       s[i]= 0;
 
-       fputc('\n', stderr);
+       LOG("%s", s);
 
        urldb_dump_search(parent->right, depth + 1);
 }
diff --git a/test/Makefile b/test/Makefile
index 6bc037c..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 \
@@ -11,7 +20,7 @@ nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c \
 urldbtest_SRCS := content/urldb.c \
                utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \
                utils/corestrings.c \
-               utils/hashtable.c utils/messages.c utils/utils.c \
+               utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
                test/log.c test/urldbtest.c
 
 # low level cache sources
@@ -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
@@ -85,8 +97,15 @@ endef
 
 $(eval $(call pkg_cfg_detect_lib,check,Check))
 
+COMMON_WARNFLAGS = -W -Wall -Wundef -Wpointer-arith -Wcast-align \
+       -Wwrite-strings -Wmissing-declarations -Wuninitialized
+
+ifneq ($(CC_MAJOR),2)
+  COMMON_WARNFLAGS += -Wno-unused-parameter
+endif
 
-TESTCFLAGS := -std=c99 -g -Wall \
+TESTCFLAGS := -std=c99 -g \
+               $(COMMON_WARNFLAGS) \
                -D_BSD_SOURCE \
                -D_POSIX_C_SOURCE=200809L \
                -D_XOPEN_SOURCE=600 \
diff --git a/test/data/urldb b/test/data/urldb
new file mode 100644
index 0000000..62e0da8
--- /dev/null
+++ b/test/data/urldb
@@ -0,0 +1,101 @@
+106
+en.wikipedia.org
+2
+http
+
+/wiki/Main_Page
+1
+1470493303
+0
+
+
+https
+
+/wiki/Main_Page
+1
+1470493304
+1
+
+Wikipedia, the free encyclopedia
+localhost
+1
+file
+
+/home/vince/dev-netsurf/workspace/netsurf/%21NetSurf/Resources/en/welcome.html%2Cfaf
+0
+0
+0
+
+
+news.bbc.co.uk
+1
+http
+
+/
+0
+0
+0
+
+
+slashdot.org
+2
+http
+
+/
+2
+1469961837
+0
+
+
+https
+
+/
+3
+1470350373
+1
+
+Slashdot: News for nerds, stuff that matters
+www.bbc.co.uk
+1
+http
+
+/news/science_and_environment
+1
+1470493359
+1
+
+Science & Environment - BBC News
+www.netsurf-browser.org
+4
+http
+
+/
+0
+0
+0
+
+
+http
+
+/contact
+0
+0
+0
+
+
+http
+
+/documentation
+0
+0
+0
+
+
+http
+
+/downloads/
+0
+0
+0
+
+
diff --git a/test/nsurl.c b/test/nsurl.c
index d7faab3..04c5234 100644
--- a/test/nsurl.c
+++ b/test/nsurl.c
@@ -1166,7 +1166,7 @@ static void corestring_teardown(void)
 
 /* suite generation */
 
-Suite *nsurl_suite(void)
+static Suite *nsurl_suite(void)
 {
        Suite *s;
        TCase *tc_api_assert;
diff --git a/test/time.c b/test/time.c
new file mode 100644
index 0000000..8598646
--- /dev/null
+++ b/test/time.c
@@ -0,0 +1,108 @@
+/*
+ * 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 <curl/curl.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;
+};
+
+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     = "Thu, 16 Aug 2007 19:45:12 GMT",
+               .expected = "Thu, 16 Aug 2007 19:45:12 GMT"
+       },
+};
+
+/**
+ * url creation 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);
+       if (time_out < 0) {
+               /* result must be invalid */
+               ck_assert(res != NSERROR_OK);
+
+       } else {
+               /* result must be valid */
+               ck_assert(res == NSERROR_OK);
+
+               ck_assert_str_eq(rfc1123_date(time_out), t->expected);
+       }
+}
+END_TEST
+
+
+/* suite generation */
+static Suite *time_suite(void)
+{
+       Suite *s;
+       TCase *tc_date_string_compare;
+
+       s = suite_create("time");
+
+       /* date parsing: string comparason */
+       tc_date_string_compare = tcase_create("date string to time_t");
+
+       tcase_add_loop_test(tc_date_string_compare,
+                           date_string_compare,
+                           0, NELEMS(date_string_tests));
+       suite_add_tcase(s, tc_date_string_compare);
+
+       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;
+}
diff --git a/test/urldbtest.c b/test/urldbtest.c
index 338ce1f..e5e5573 100644
--- a/test/urldbtest.c
+++ b/test/urldbtest.c
@@ -1,6 +1,6 @@
 /*
- * Copyright 2006 John M Bell <[email protected]>
- * Copyright 2009 John Tytgat <[email protected]>
+ * Copyright 2015 Vincent Sanders <[email protected]>
+ * Copyright 2011 John Mark Bell <[email protected]>
  *
  * This file is part of NetSurf, http://www.netsurf-browser.org/
  *
@@ -17,40 +17,31 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/**
+ * \file
+ * Test nsurl operations.
+ */
 
 #include <assert.h>
-#include <ctype.h>
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
-#include <time.h>
+#include <check.h>
 
-#include "utils/errors.h"
-#include "utils/nsurl.h"
-#include "netsurf/bitmap.h"
-#include "content/content.h"
-#include "content/urldb.h"
-#include "desktop/cookie_manager.h"
-#include "utils/nsoption.h"
-#ifdef riscos
-/** \todo lose this */
-#include "riscos/bitmap.h"
-#endif
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "utils/corestrings.h"
 #include "utils/log.h"
 #include "utils/corestrings.h"
-#include "utils/filename.h"
-#include "utils/url.h"
-#include "utils/utils.h"
+#include "utils/nsurl.h"
+#include "netsurf/url_db.h"
+#include "content/urldb.h"
+
+const char *test_urldb_path = "test/data/urldb";
 
-int option_expire_url = 0;
 struct netsurf_table *guit = NULL;
 
-static void netsurf_lwc_iterator(lwc_string *str, void *pw)
-{
-       LOG("[%3u] %.*s", str->refcnt, (int)lwc_string_length(str), 
lwc_string_data(str));
-}
+/*************** original test helpers ************/
 
 bool cookie_manager_add(const struct cookie_data *data)
 {
@@ -61,22 +52,7 @@ void cookie_manager_remove(const struct cookie_data *data)
 {
 }
 
-
-void bitmap_destroy(void *bitmap)
-{
-}
-
-char *path_to_url(const char *path)
-{
-       char *r = malloc(strlen(path) + 7 + 1);
-
-       strcpy(r, "file://");
-       strcat(r, path);
-
-       return r;
-}
-
-nsurl *make_url(const char *url)
+static nsurl *make_url(const char *url)
 {
        nsurl *nsurl;
        if (nsurl_create(url, &nsurl) != NSERROR_OK) {
@@ -86,7 +62,7 @@ nsurl *make_url(const char *url)
        return nsurl;
 }
 
-char *make_path_query(nsurl *url)
+static char *make_path_query(nsurl *url)
 {
        size_t len;
        char *path_query;
@@ -98,7 +74,7 @@ char *make_path_query(nsurl *url)
        return path_query;
 }
 
-lwc_string *make_lwc(const char *str)
+static lwc_string *make_lwc(const char *str)
 {
        lwc_string *lwc;
        if (lwc_intern_string(str, strlen(str), &lwc) != lwc_error_ok) {
@@ -108,8 +84,7 @@ lwc_string *make_lwc(const char *str)
        return lwc;
 }
 
-
-bool test_urldb_set_cookie(const char *header, const char *url,
+static bool test_urldb_set_cookie(const char *header, const char *url,
                const char *referer)
 {
        nsurl *r = NULL;
@@ -128,7 +103,7 @@ bool test_urldb_set_cookie(const char *header, const char 
*url,
        return ret;
 }
 
-char *test_urldb_get_cookie(const char *url)
+static char *test_urldb_get_cookie(const char *url)
 {
        nsurl *nsurl = make_url(url);
        char *ret;
@@ -139,7 +114,40 @@ char *test_urldb_get_cookie(const char *url)
        return ret;
 }
 
-int main(void)
+
+/*************************************************/
+
+/** urldb create fixture */
+static void urldb_create(void)
+{
+       nserror res;
+       res = corestrings_init();
+       ck_assert_int_eq(res, NSERROR_OK);
+}
+
+static void urldb_lwc_iterator(lwc_string *str, void *pw)
+{
+       int *scount = pw;
+
+       LOG("[%3u] %.*s", str->refcnt,
+           (int)lwc_string_length(str),
+           lwc_string_data(str));
+       (*scount)++;
+}
+
+/** urldb teardown fixture */
+static void urldb_teardown(void)
+{
+       int scount = 0;
+
+       corestrings_fini();
+
+       LOG("Remaining lwc strings:");
+       lwc_iterate_strings(urldb_lwc_iterator, &scount);
+       ck_assert_int_eq(scount, 0);
+}
+
+START_TEST(urldb_original_test)
 {
        struct host_part *h;
        struct path_data *p;
@@ -150,9 +158,6 @@ int main(void)
        nsurl *urlr;
        char *path_query;
 
-
-       corestrings_init();
-
        h = urldb_add_host("127.0.0.1");
        if (!h) {
                LOG("failed adding host");
@@ -254,19 +259,19 @@ int main(void)
        urldb_get_cookie(url, true);
        nsurl_unref(url);
 
-       /* 1563546 */
+       /* Mantis bug #993 */
        url = make_url("http:moodle.org");
        assert(urldb_add_url(url) == true);
        assert(urldb_get_url(url) != NULL);
        nsurl_unref(url);
 
-       /* also 1563546 */
+       /* Mantis bug #993 */
        url = make_url("http://a_a/";);
        assert(urldb_add_url(url));
        assert(urldb_get_url(url));
        nsurl_unref(url);
 
-       /* 1597646 */
+       /* Mantis bug #996 */
        url = make_url("http://[email protected]/";);
        if (urldb_add_url(url)) {
                LOG("added %s", nsurl_access(url));
@@ -274,7 +279,7 @@ int main(void)
        }
        nsurl_unref(url);
 
-       /* 1535120 */
+       /* Mantis bug #913 */
        url = make_url("http://www2.2checkout.com/";);
        assert(urldb_add_url(url));
        assert(urldb_get_url(url));
@@ -312,7 +317,7 @@ int main(void)
 
        /* Invalid path (contains different leafname) */
        assert(test_urldb_set_cookie("name=value;Path=/index.html\r\n", 
"http://example.org/index.htm";, NULL) == false);
-       
+
        /* Invalid path (contains leafname in different directory) */
        assert(test_urldb_set_cookie("name=value;Path=/foo/index.html\r\n", 
"http://www.example.org/bar/index.html";, NULL) == false);
 
@@ -361,13 +366,98 @@ int main(void)
 
        urldb_dump();
        urldb_destroy();
+}
+END_TEST
 
-       printf("PASS\n");
+TCase *urldb_original_case_create(void)
+{
+       TCase *tc;
+       tc = tcase_create("Original urldb tests");
 
-       corestrings_fini();
-       LOG("Remaining lwc strings:");
-       lwc_iterate_strings(netsurf_lwc_iterator, NULL);
+       /* ensure corestrings are initialised and finalised for every test */
+       tcase_add_checked_fixture(tc,
+                                 urldb_create,
+                                 urldb_teardown);
+
+       tcase_add_test(tc, urldb_original_test);
+
+       return tc;
+}
+
+START_TEST(urldb_session_test)
+{
+       nserror res;
+
+       res = urldb_load(test_urldb_path);
+       ck_assert_int_eq(res, NSERROR_OK);
 
-       return 0;
+       urldb_destroy();
+}
+END_TEST
+
+TCase *urldb_session_case_create(void)
+{
+       TCase *tc;
+       tc = tcase_create("Full session");
+
+       /* ensure corestrings are initialised and finalised for every test */
+       tcase_add_checked_fixture(tc,
+                                 urldb_create,
+                                 urldb_teardown);
+
+       tcase_add_test(tc, urldb_session_test);
+
+       return tc;
 }
 
+/**
+ * Test urldb_add_host asserting on NULL.
+ */
+START_TEST(urldb_api_add_host_assert_test)
+{
+       struct host_part *res;
+       res = urldb_add_host(NULL);
+       ck_assert(res == NULL);
+}
+END_TEST
+
+
+TCase *urldb_api_case_create(void)
+{
+       TCase *tc;
+       tc = tcase_create("API checks");
+
+       tcase_add_test_raise_signal(tc,
+                                   urldb_api_add_host_assert_test,
+                                   6);
+
+       return tc;
+}
+
+
+Suite *urldb_suite_create(void)
+{
+       Suite *s;
+       s = suite_create("URLDB");
+
+       suite_add_tcase(s, urldb_api_case_create());
+       suite_add_tcase(s, urldb_session_case_create());
+       suite_add_tcase(s, urldb_original_case_create());
+
+       return s;
+}
+
+int main(int argc, char **argv)
+{
+       int number_failed;
+       SRunner *sr;
+
+       sr = srunner_create(urldb_suite_create());
+
+       srunner_run_all(sr, CK_ENV);
+
+       number_failed = srunner_ntests_failed(sr);
+       srunner_free(sr);
+
+       return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test/utils.c b/test/utils.c
index 02951e9..e00ab3d 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -64,7 +64,7 @@ START_TEST(human_friendly_bytesize_test)
 }
 END_TEST
 
-TCase *human_friendly_bytesize_case_create(void)
+static TCase *human_friendly_bytesize_case_create(void)
 {
        TCase *tc;
        tc = tcase_create("Human friendly bytesize");
@@ -115,7 +115,7 @@ START_TEST(squash_whitespace_api_test)
 }
 END_TEST
 
-TCase *squash_whitespace_case_create(void)
+static TCase *squash_whitespace_case_create(void)
 {
        TCase *tc;
        tc = tcase_create("Squash whitespace");
@@ -128,7 +128,7 @@ TCase *squash_whitespace_case_create(void)
        return tc;
 }
 
-Suite *utils_suite_create(void)
+static Suite *utils_suite_create(void)
 {
        Suite *s;
        s = suite_create("String utils");
diff --git a/utils/ascii.h b/utils/ascii.h
index 9d60368..ca26999 100644
--- a/utils/ascii.h
+++ b/utils/ascii.h
@@ -60,7 +60,7 @@ static inline bool ascii_is_alpha_upper(char c)
  */
 static inline bool ascii_is_alpha(char c)
 {
-       return (c >= 'A' && c <= 'Z');
+       return (ascii_is_alpha_lower(c) || ascii_is_alpha_upper(c));
 }
 
 /**
diff --git a/utils/time.c b/utils/time.c
index a8c2c48..667e836 100644
--- a/utils/time.c
+++ b/utils/time.c
@@ -547,8 +547,8 @@ struct nsc_date_parse_ctx {
        uint8_t secs;
        uint8_t mins;
        uint8_t hours;
-       uint8_t days;
-       uint8_t months;
+       uint8_t day;
+       uint8_t month;
        uint16_t years;
        int16_t timezone_offset_mins;
 };
@@ -639,7 +639,7 @@ static inline bool time__parse_month(
        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->months = i;
+                       ctx->month = i;
                        return true;
                }
        }
@@ -769,8 +769,8 @@ static inline bool time__parse_number(
        case 8:
                if (!flags_chk(*flags, NSC_COMPONENT_FLAGS__HAVE_YYYYMMDD)) {
                        ctx->years  =  value / 10000;
-                       ctx->months = (value % 10000) / 100 - 1;
-                       ctx->days   =  value % 100;
+                       ctx->month = (value % 10000) / 100 - 1;
+                       ctx->day   =  value % 100 - 1;
                        *flags |= NSC_COMPONENT_FLAGS__HAVE_YYYYMMDD;
                        return true;
                }
@@ -800,7 +800,7 @@ static inline bool time__parse_number(
        case 2:
                if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_DAYS) &&
                                value <= 31) {
-                       ctx->days = value;
+                       ctx->day = value - 1;
                        *flags |= NSC_COMPONENT_FLAGS_HAVE_DAYS;
                        return true;
                }
@@ -815,7 +815,7 @@ static inline bool time__parse_number(
 
        case 1:
                if (!flags_chk(*flags, NSC_COMPONENT_FLAGS_HAVE_DAYS)) {
-                       ctx->days = value;
+                       ctx->day = value - 1;
                        *flags |= NSC_COMPONENT_FLAGS_HAVE_DAYS;
                        return true;
                }
@@ -896,11 +896,11 @@ static nserror time__ctx_to_time_t(
                [NSC_TIME_MONTH_DEC] = NSC_MONTH_OFF_DEC
        };
        int year_days = (ctx->years - 1970) * 365;
-       int month_days = month_offsets[ctx->months];
-       int year = (ctx->months < NSC_TIME_MONTH_FEB) ?
+       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->days + leap_days;
+       int total_days = year_days + month_days + ctx->day + leap_days;
 
        int mins = (int)ctx->mins + (int)ctx->timezone_offset_mins;
 
@@ -929,8 +929,8 @@ static nserror time__get_date(const char *str, time_t *time)
                .secs   = 0,
                .mins   = 0,
                .hours  = 0,
-               .days   = 0,
-               .months = 0,
+               .day    = 0,
+               .month  = 0,
                .years  = 0,
                .timezone_offset_mins = 0
        };
@@ -992,7 +992,7 @@ static nserror time__get_date(const char *str, time_t *time)
                return NSERROR_INVALID;
        }
        if (ctx.secs > 60 || ctx.mins > 59 || ctx.hours > 23 ||
-                       ctx.days > 31 || ctx.months > 11) {
+                       ctx.day > 31 || ctx.month > 11) {
                return NSERROR_INVALID;
        }
 
diff --git a/utils/utils.c b/utils/utils.c
index 2a83e85..15c91c6 100644
--- a/utils/utils.c
+++ b/utils/utils.c
@@ -28,6 +28,7 @@
 
 #include "utils/messages.h"
 #include "utils/dirent.h"
+#include "utils/inet.h"
 #include "utils/string.h"
 #include "utils/utils.h"
 


-- 
NetSurf Browser

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to