+#include "match.h"
+#include <regex.h>
+
+/*
+ * DATA STRUCTURES, MACROS, STATIC DATA
+ */
+
+/*
+ * Return codes used by try_match()
+ */
+
+#define MATCH_OK (1)
+#define MATCH_NONE (0)
+#define MATCH_ERROR (-1)
+
+/*
+ * Macro to tell whether a character is a regex metacharacter. Note that '*'
+ * and '?' are NOT included: they are themselves special in globs.
+ */
+
+#define IS_REGEX_META(c) ( \
+ (c) == '.' || (c) == '(' || (c) == ')' || (c) == '{' || (c) == '}' || \
+ (c) == '+' || (c) == '^' || (c) == '$' || (c) == '|' \
+)
+
+/*
+ * Define a specific type to hold error messages in case regex compile/matching
+ * fails
+ */
+
+typedef char regex_errbuf[STR_SIZE];
+
+/*
+ * Structure used by amglob_to_regex() to expand particular glob characters. Its
+ * fields are:
+ * - question_mark: what the question mark ('?') should be replaced with;
+ * - star: what the star ('*') should be replaced with;
+ * - double_star: what two consecutive stars should be replaced with.
+ *
+ * Note that apart from double_star, ALL OTHER FIELDS MUST NOT BE NULL.
+ */
+
+struct subst_table {
+ const char *question_mark;
+ const char *star;
+ const char *double_star;
+};
+
+/*
+ * Susbtitution data for glob_to_regex()
+ */
+
+static struct subst_table glob_subst_stable = {
+ "[^/]", /* question_mark */
+ "[^/]*", /* star */
+ NULL /* double_star */
+};
+
+/*
+ * Substitution data for tar_to_regex()
+ */
+
+static struct subst_table tar_subst_stable = {
+ "[^/]", /* question_mark */
+ ".*", /* star */
+ NULL /* double_star */
+};
+
+/*
+ * Substitution data for match_word(): dot
+ */
+
+static struct subst_table mword_dot_subst_table = {
+ "[^.]", /* question_mark */
+ "[^.]*", /* star */
+ ".*" /* double_star */
+};
+
+/*
+ * Substitution data for match_word(): slash
+ */
+
+static struct subst_table mword_slash_subst_table = {
+ "[^/]", /* question_mark */
+ "[^/]*", /* star */
+ ".*" /* double_star */
+};
+
+/*
+ * match_word() specific data:
+ * - re_double_sep: anchored regex matching two separators;
+ * - re_separator: regex matching the separator;
+ * - re_begin_full: regex matching the separator, anchored at the beginning;
+ * - re_end_full: regex matching the separator, andchored at the end.
+ */
+
+struct mword_regexes {
+ const char *re_double_sep;
+ const char *re_begin_full;
+ const char *re_separator;
+ const char *re_end_full;
+};
+
+static struct mword_regexes mword_dot_regexes = {
+ "^\\.\\.$", /* re_double_sep */
+ "^\\.", /* re_begin_full */
+ "\\.", /* re_separator */
+ "\\.$" /* re_end_full */
+};
+
+static struct mword_regexes mword_slash_regexes = {
+ "^\\/\\/$", /* re_double_sep */
+ "^\\/", /* re_begin_full */
+ "\\/", /* re_separator */
+ "\\/$" /* re_end_full */
+};
+
+/*
+ * Regular expression caches, and a static mutex to protect initialization and
+ * access. This may be unnecessarily coarse, but it is unknown at this time
+ * whether GHashTable accesses are thread-safe, and get_regex_from_cache() may
+ * be called from within threads, so play it safe.
+ */
+
+#if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 31))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+ static GStaticMutex re_cache_mutex = G_STATIC_MUTEX_INIT;
+# pragma GCC diagnostic pop
+#else
+ static GStaticMutex re_cache_mutex = G_STATIC_MUTEX_INIT;
+#endif
+static GHashTable *regex_cache = NULL, *regex_cache_newline = NULL;