+ * 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.
+ */
+
+static GStaticMutex re_cache_mutex = G_STATIC_MUTEX_INIT;
+static GHashTable *regex_cache = NULL, *regex_cache_newline = NULL;
+
+/*
+ * REGEX FUNCTIONS
+ */
+
+/*
+ * Initialize regex caches. NOTE: this function MUST be called with
+ * re_cache_mutex LOCKED, see get_regex_from_cache()