+/*
+ * Convert backslash-escaped string to QCHAR-escaped
+ * string useful for globbing; loses QCHAR unless it
+ * can squeeze in, eg. by previous loss of backslash
+ */
+static void
+x_glob_hlp_add_qchar(char *cp)
+{
+ char ch, *dp = cp;
+ bool escaping = false;
+
+ while ((ch = *cp++)) {
+ if (ch == '\\' && !escaping) {
+ escaping = true;
+ continue;
+ }
+ if (escaping || (ch == QCHAR && (cp - dp) > 1)) {
+ /*
+ * empirically made list of chars to escape
+ * for globbing as well as QCHAR itself
+ */
+ switch (ch) {
+ case QCHAR:
+ case '$':
+ case '*':
+ case '?':
+ case '[':
+ case '\\':
+ case '`':
+ *dp++ = QCHAR;
+ break;
+ }
+ escaping = false;
+ }
+ *dp++ = ch;
+ }
+ *dp = '\0';
+}
+
+/*
+ * Run tilde expansion on argument string, return the result
+ * after unescaping; if the flag is set, the original string
+ * is freed if changed and assumed backslash-escaped, if not
+ * it is assumed QCHAR-escaped
+ */
+static char *
+x_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag)
+{
+ char ch, *cp, *dp;
+
+ /*
+ * On the string, check whether we have a tilde expansion,
+ * and if so, discern "~foo/bar" and "~/baz" from "~blah";
+ * if we have a directory part (the former), try to expand
+ */
+ if (*s == '~' && (cp = strchr(s, '/')) != NULL) {
+ /* ok, so split into "~foo"/"bar" or "~"/"baz" */
+ *cp++ = 0;
+ /* try to expand the tilde */
+ if (!(dp = tilde(s + 1))) {
+ /* nope, revert damage */
+ *--cp = '/';
+ } else {
+ /* ok, expand and replace */
+ cp = shf_smprintf("%s/%s", dp, cp);
+ if (magic_flag)
+ afree(s, ATEMP);
+ s = cp;
+ }
+ }
+
+ /* ... convert it from backslash-escaped via QCHAR-escaped... */
+ if (magic_flag)
+ x_glob_hlp_add_qchar(s);
+ /* ... to unescaped, for comparison with the matches */
+ cp = dp = s;
+
+ while ((ch = *cp++)) {
+ if (ch == QCHAR && !(ch = *cp++))
+ break;
+ *dp++ = ch;
+ }
+ *dp = '\0';
+
+ return (s);
+}
+