static void test_expand_tilde_home(void) { char *dir; const char *home = util_get_home_dir(); check_expand("~", "~"); check_expand("~/", home); check_expand("foo~/bar", "foo~/bar"); check_expand("~/foo", (dir = g_strdup_printf("%s/foo", home))); g_free(dir); check_expand("foo ~/bar", (dir = g_strdup_printf("foo %s/bar", home))); g_free(dir); check_expand("~/~", (dir = g_strdup_printf("%s/~", home))); g_free(dir); check_expand("~/~/", (dir = g_strdup_printf("%s/~/", home))); g_free(dir); }
static void test_expand_tilde_user(void) { const char *home = util_get_home_dir(); const char *user = g_get_user_name(); char *in, *out; /* don't expand within words */ in = g_strdup_printf("foo~%s/bar", user); check_expand(in, in); g_free(in); check_expand((in = g_strdup_printf("foo ~%s", user)), (out = g_strdup_printf("foo %s", home))); g_free(in); g_free(out); check_expand((in = g_strdup_printf("~%s", user)), home); g_free(in); check_expand((in = g_strdup_printf("~%s/bar", user)), (out = g_strdup_printf("%s/bar", home))); g_free(in); g_free(out); }
/** * Reads given input and try to parse ~/, ~user, $VAR or ${VAR} expansion * from the start of the input and moves the input pointer to the first * not expanded char. If no expansion pattern was found, the first char is * appended to given GString. * * @input: String pointer with the content to be parsed. * @str: GString that will be filled with expanded content. * @flags Flags that determine which expansion are processed. * @quoteable String of chars that are additionally escapable by \. * Returns true if input started with expandable pattern. */ gboolean util_parse_expansion(const char **input, GString *str, int flags, const char *quoteable) { GString *name; const char *env, *prev, quote = '\\'; struct passwd *pwd; gboolean expanded = false; prev = *input; if (flags & UTIL_EXP_TILDE && **input == '~') { /* skip ~ */ (*input)++; if (**input == '/') { g_string_append(str, util_get_home_dir()); expanded = true; /* if there is no char or space after ~/ skip the / to get * /home/user instead of /home/user/ */ if (!*(*input + 1) || VB_IS_SPACE(*(*input + 1))) { (*input)++; } } else { /* look ahead to / space or end of string to get a possible * username for ~user pattern */ name = g_string_new(""); /* current char is ~ that is skipped to get the user name */ while (VB_IS_IDENT(**input)) { g_string_append_c(name, **input); (*input)++; } /* append the name to the destination string */ if ((pwd = getpwnam(name->str))) { g_string_append(str, pwd->pw_dir); expanded = true; } g_string_free(name, true); } /* move pointer back to last expanded char */ (*input)--; } else if (flags & UTIL_EXP_DOLLAR && **input == '$') { /* skip the $ */ (*input)++; name = g_string_new(""); /* look for ${VAR}*/ if (**input == '{') { /* skip { */ (*input)++; /* look ahead to } or end of string */ while (**input && **input != '}') { g_string_append_c(name, **input); (*input)++; } /* if the } was reached - skip this */ if (**input == '}') { (*input)++; } } else { /* process $VAR */ /* look ahead to /, space or end of string */ while (VB_IS_IDENT(**input)) { g_string_append_c(name, **input); (*input)++; } } /* append the variable to the destination string */ if ((env = g_getenv(name->str))) { g_string_append(str, env); } /* move pointer back to last expanded char */ (*input)--; /* variable are expanded even if they do not exists */ expanded = true; g_string_free(name, true); } else if (flags & UTIL_EXP_SPECIAL && **input == '%') { if (*vb.state.uri) { /* TODO check for modifiers like :h:t:r:e */ g_string_append(str, vb.state.uri); expanded = true; } } if (!expanded) { /* restore the pointer position if no expansion was found */ *input = prev; /* handle escaping of quoteable chars */ if (**input == quote) { /* move pointer to the next char */ (*input)++; if (!**input) { /* if input ends here - use only the quote char */ g_string_append_c(str, quote); (*input)--; } else if (strchr(quoteable, **input) || (flags & UTIL_EXP_TILDE && **input == '~') || (flags & UTIL_EXP_DOLLAR && **input == '$') || (flags & UTIL_EXP_SPECIAL && **input == '%') ) { /* escaped char becomes only char */ g_string_append_c(str, **input); } else { /* put escape char and next char into the result string */ g_string_append_c(str, quote); g_string_append_c(str, **input); } } else { /* take the char like it is */ g_string_append_c(str, **input); } } return expanded; }