+ len = strlen(glob);
+ nglob = stralloc(glob);
+
+ if(glob_is_separator_only(nglob, separator)) {
+ regex = alloc(7); /* Length of what is written below plus '\0' */
+ dst = regex;
+ *dst++ = '^';
+ *dst++ = '\\';
+ *dst++ = separator;
+ *dst++ = '\\';
+ *dst++ = separator;
+ *dst++ = '$';
+ *dst = '\0';
+ } else {
+ /*
+ * Unlike what happens for tar and disk expressions, here the
+ * substitution table needs to be dynamically allocated. When we enter
+ * here, we know what the expansions will be for the question mark, the
+ * star and the double star, and also the worst case expansion. We
+ * calculate the begin and end expansions below.
+ */
+
+#define MATCHWORD_STAR_EXPANSION(c) (const char []) { \
+ '[', '^', (c), ']', '*', 0 \
+}
+#define MATCHWORD_QUESTIONMARK_EXPANSION(c) (const char []) { \
+ '[', '^', (c), ']', 0 \
+}
+#define MATCHWORD_DOUBLESTAR_EXPANSION ".*"
+
+ struct subst_table table;
+ size_t worst_case = 5;
+ const char *begin, *end;
+ char *p, *g = nglob;
+
+ /*
+ * Calculate the beginning of the regex:
+ * - by default, it is an unanchored separator;
+ * - if the glob begins with a caret, make that an anchored separator,
+ * and increment g appropriately;
+ * - if it begins with a separator, make it the empty string.
+ */
+
+ p = nglob;
+
+#define REGEX_BEGIN_FULL(c) (const char[]) { '^', '\\', (c), 0 }
+#define REGEX_BEGIN_NOANCHOR(c) (const char[]) { '\\', (c), 0 }
+#define REGEX_BEGIN_ANCHORONLY "^" /* Unused, but defined for consistency */
+#define REGEX_BEGIN_EMPTY ""
+
+ begin = REGEX_BEGIN_NOANCHOR(separator);
+
+ if (*p == '^') {
+ begin = REGEX_BEGIN_FULL(separator);
+ p++, g++;
+ if (*p == separator)
+ g++;
+ } else if (*p == separator)
+ begin = REGEX_BEGIN_EMPTY;
+
+ /*
+ * Calculate the end of the regex:
+ * - an unanchored separator by default;
+ * - if the last character is a backslash or the separator itself, it
+ * should be the empty string;
+ * - if it is a dollar sign, overwrite it with 0 and look at the
+ * character before it: if it is the separator, only anchor at the
+ * end, otherwise, add a separator before the anchor.
+ */
+
+ p = &(nglob[strlen(nglob) - 1]);
+
+#define REGEX_END_FULL(c) (const char[]) { '\\', (c), '$', 0 }
+#define REGEX_END_NOANCHOR(c) REGEX_BEGIN_NOANCHOR(c)
+#define REGEX_END_ANCHORONLY "$"
+#define REGEX_END_EMPTY REGEX_BEGIN_EMPTY
+
+ end = REGEX_END_NOANCHOR(separator);
+
+ if (*p == '\\' || *p == separator)
+ end = REGEX_END_EMPTY;
+ else if (*p == '$') {
+ char prev = *(p - 1);
+ *p = '\0';
+ if (prev == separator)
+ end = REGEX_END_ANCHORONLY;
+ else
+ end = REGEX_END_FULL(separator);
+ }
+
+ /*
+ * Fill in our substitution table and generate the regex
+ */
+
+ table.begin = begin;
+ table.end = end;
+ table.question_mark = MATCHWORD_QUESTIONMARK_EXPANSION(separator);
+ table.star = MATCHWORD_STAR_EXPANSION(separator);
+ table.double_star = MATCHWORD_DOUBLESTAR_EXPANSION;
+
+ regex = amglob_to_regex(g, &table, worst_case);
+ }
+
+ ret = do_match(regex, nword, TRUE);