From: Daniel Carl Date: Sat, 3 May 2014 13:22:25 +0000 (+0200) Subject: Use already existing expansion logic also for ex commands. X-Git-Url: https://git.owens.tech/assets/static/git-logo.png/assets/static/git-logo.png/git?a=commitdiff_plain;h=61ee4fb16765da89f47a84d3a2941b6201ab71e7;p=vimb.git Use already existing expansion logic also for ex commands. --- diff --git a/src/ascii.h b/src/ascii.h index 928e128..8f6ae9c 100644 --- a/src/ascii.h +++ b/src/ascii.h @@ -26,9 +26,6 @@ #define VB_SPACE 0x08 #define VB_PUNKT 0x10 #define VB_CTRL 0x20 -#define VB_IDENT 0x40 -#define VB_ALPHA (VB_UPPER|VB_LOWER) -#define VB_ALNUM (VB_ALPHA|VB_DIGIT) #define U VB_UPPER #define L VB_LOWER @@ -36,20 +33,16 @@ #define P VB_PUNKT #define S VB_SPACE #define C VB_CTRL -#define I VB_IDENT -#define LI VB_LOWER|VB_IDENT -#define UI VB_UPPER|VB_IDENT #define SC VB_SPACE|VB_CTRL -#define PI VB_PUNKT|VB_IDENT static const unsigned char chartable[256] = { /* 0x00-0x0f */ C, C, C, C, C, C, C, C, C, SC, SC, C, SC, SC, C, C, /* 0x10-0x1f */ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, /* 0x20-0x2f */ S, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, /* 0x30-0x3f */ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, -/* 0x40-0x4f */ PI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, -/* 0x50-0x5f */ UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI, P, P, P, P, PI, -/* 0x60-0x6f */ P, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, -/* 0x70-0x7f */ LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, LI, P, P, P, P, C, +/* 0x40-0x4f */ P, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, +/* 0x50-0x5f */ U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, +/* 0x60-0x6f */ P, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, +/* 0x70-0x7f */ L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, /* 0x80-0x8f */ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, /* 0x90-0x9f */ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, /* 0xa0-0xaf */ P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, @@ -65,20 +58,18 @@ static const unsigned char chartable[256] = { #undef P #undef S #undef C -#undef I -#undef LI -#undef UI #undef SC -#define VB_IS_UPPER(c) ((chartable[(unsigned char)c] & VB_UPPER) != 0) -#define VB_IS_LOWER(c) ((chartable[(unsigned char)c] & VB_LOWER) != 0) -#define VB_IS_DIGIT(c) ((chartable[(unsigned char)c] & VB_DIGIT) != 0) -#define VB_IS_PUNKT(c) ((chartable[(unsigned char)c] & VB_PUNKT) != 0) -#define VB_IS_SPACE(c) ((chartable[(unsigned char)c] & VB_SPACE) != 0) -#define VB_IS_CTRL(c) ((chartable[(unsigned char)c] & VB_CTRL) != 0) -#define VB_IS_IDENT(c) ((chartable[(unsigned char)c] & VB_IDENT) != 0) -#define VB_IS_ALPHA(c) ((chartable[(unsigned char)c] & VB_ALPHA) != 0) -#define VB_IS_ALNUM(c) ((chartable[(unsigned char)c] & VB_ALNUM) != 0) +#define VB_IS_UPPER(c) ((chartable[(unsigned char)c] & VB_UPPER) != 0) +#define VB_IS_LOWER(c) ((chartable[(unsigned char)c] & VB_LOWER) != 0) +#define VB_IS_DIGIT(c) ((chartable[(unsigned char)c] & VB_DIGIT) != 0) +#define VB_IS_PUNKT(c) ((chartable[(unsigned char)c] & VB_PUNKT) != 0) +#define VB_IS_SPACE(c) ((chartable[(unsigned char)c] & VB_SPACE) != 0) +#define VB_IS_CTRL(c) ((chartable[(unsigned char)c] & VB_CTRL) != 0) +#define VB_IS_SEPARATOR(c) (VB_IS_SPACE(c) || c == '"' || c == '\'') +#define VB_IS_ALPHA(c) (VB_IS_LOWER(c) || VB_IS_UPPER(c)) +#define VB_IS_ALNUM(c) (VB_IS_ALPHA(c) || VB_IS_DIGIT(c)) +#define VB_IS_IDENT(c) (VB_IS_ALNUM(c) || c == '_') /* CSI (control sequence introducer) is the first byte of a control sequence * and is always followed by two bytes. */ diff --git a/src/ex.c b/src/ex.c index 8ad0096..81167da 100644 --- a/src/ex.c +++ b/src/ex.c @@ -117,7 +117,6 @@ static gboolean parse_command_name(const char **input, ExArg *arg); static gboolean parse_bang(const char **input, ExArg *arg); static gboolean parse_lhs(const char **input, ExArg *arg); static gboolean parse_rhs(const char **input, ExArg *arg); -static void expand_input(const char **input, ExArg *arg); static void skip_whitespace(const char **input); static void free_cmdarg(ExArg *arg); static gboolean execute(const ExArg *arg); @@ -645,7 +644,8 @@ static gboolean parse_lhs(const char **input, ExArg *arg) */ static gboolean parse_rhs(const char **input, ExArg *arg) { - char quote = '\\'; + char quote = '\\'; + int expflags = UTIL_EXP_TILDE|UTIL_EXP_DOLLAR|UTIL_EXP_SPECIAL; if (!*input || !**input) { return false; @@ -670,9 +670,17 @@ static gboolean parse_rhs(const char **input, ExArg *arg) } } else { /* unquoted char */ /* check for expansion placeholder */ - if (arg->flags & EX_FLAG_EXP && strchr("%~", **input)) { - /* handle expansion */ - expand_input(input, arg); + if (arg->flags & EX_FLAG_EXP) { + util_parse_expansion(input, arg->rhs, expflags); + + if (VB_IS_SPACE(**input)) { + /* add tilde expansion for next loop needs to be first + * char or to be after a space */ + expflags |= UTIL_EXP_TILDE; + } else { + /* remove tile expansion for next loop */ + expflags &= ~UTIL_EXP_TILDE; + } } else { g_string_append_c(arg->rhs, **input); } @@ -682,28 +690,6 @@ static gboolean parse_rhs(const char **input, ExArg *arg) return true; } -static void expand_input(const char **input, ExArg *arg) -{ - const char *uri; - switch (**input) { - case '%': - if ((uri = GET_URI())) { - /* TODO check for modifiers like :h:t:r:e */ - g_string_append(arg->rhs, uri); - } - break; - - case '~': - (*input)++; - /* expand only ~/ because ~user is not handled at the moment */ - if (**input == '/') { - g_string_append(arg->rhs, g_get_home_dir()); - g_string_append_c(arg->rhs, **input); - } - break; - } -} - /** * Executes the command given by ExArg. */ diff --git a/src/setting.c b/src/setting.c index 9b3e252..36ceea1 100644 --- a/src/setting.c +++ b/src/setting.c @@ -641,7 +641,7 @@ static SettingStatus ca_bundle(const Setting *s, const SettingType type) print_value(s, vb.config.cafile); } else { /* expand the given file and set it to the file database */ - expanded = util_expand(s->arg.s); + expanded = util_expand(s->arg.s, UTIL_EXP_TILDE|UTIL_EXP_DOLLAR); vb.config.tls_db = g_tls_file_database_new(expanded, &error); g_free(expanded); if (error) { diff --git a/src/util.c b/src/util.c index 64b2fd2..69c2b59 100644 --- a/src/util.c +++ b/src/util.c @@ -26,6 +26,8 @@ #include "ascii.h" #include "completion.h" +extern VbCore vb; + char *util_get_config_dir(void) { char *path = g_build_filename(g_get_user_config_dir(), PROJECT, NULL); @@ -302,9 +304,10 @@ gboolean util_create_tmp_file(const char *content, char **file) char *util_build_path(const char *path, const char *dir) { char *fullPath = NULL, *fexp, *dexp, *p; + int expflags = UTIL_EXP_TILDE|UTIL_EXP_DOLLAR; /* if the path could be expanded */ - if ((fexp = util_expand(path))) { + if ((fexp = util_expand(path, expflags))) { if (*fexp == '/') { /* path is already absolute, no need to use given dir - there is * no need to free fexp, bacuse this should be done by the caller @@ -312,7 +315,7 @@ char *util_build_path(const char *path, const char *dir) fullPath = fexp; } else if (dir && *dir) { /* try to expand also the dir given - this may be ~/path */ - if ((dexp = util_expand(dir))) { + if ((dexp = util_expand(dir, expflags))) { /* use expanded dir and append expanded path */ fullPath = g_build_filename(dexp, fexp, NULL); g_free(dexp); @@ -341,80 +344,128 @@ char *util_build_path(const char *path, const char *dir) * * Returned path must be g_freed. */ -char *util_expand(const char *src) +char *util_expand(const char *src, int expflags) { - GString *dst = g_string_new(""); - GString *name; - gboolean start = true; /* is start of string of subpart */ - const char *env; + const char **input = &src; char *result; + GString *dst = g_string_new(""); + int flags = expflags; + + while (**input) { + util_parse_expansion(input, dst, flags); + if (VB_IS_SEPARATOR(**input)) { + /* after space the tilde expansion is allowed */ + flags = expflags; + } else { + /* remove tile expansion for next loop */ + flags &= ~UTIL_EXP_TILDE; + } + /* move pointer to the next char */ + (*input)++; + } + + result = dst->str; + g_string_free(dst, false); + + return result; +} + +/** + * 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. + * Returns true if input started with expandable pattern. + */ +gboolean util_parse_expansion(const char **input, GString *str, int flags) +{ + GString *name; + const char *env, *prev; struct passwd *pwd; + gboolean expanded = false; - while (*src) { - /* expand ~/path and ~user */ - if (*src == '~' && start) { - /* skip the ~ */ - src++; - if (*src == '/') { - g_string_append(dst, util_get_home_dir()); - } else { - name = g_string_new(""); - /* look ahead to / space or end of string */ - while (*src && *src != '/' && !VB_IS_SPACE(*src)) { - g_string_append_c(name, *src); - src++; - } - /* append the name to the destination string */ - if ((pwd = getpwnam(name->str))) { - g_string_append(dst, pwd->pw_dir); - } - g_string_free(name, true); - } - } else if (*src == '$') { + prev = *input; + if (flags & UTIL_EXP_TILDE && **input == '~') { + /* skip ~ */ + (*input)++; + + if (**input == '/') { + g_string_append(str, util_get_home_dir()); + expanded = true; + } else { + /* look ahead to / space or end of string to get a possible + * username for ~user pattern */ name = g_string_new(""); - /* skip the $ */ - src++; - /* look for ${VAR}*/ - if (*src == '{') { - /* skip { */ - src++; - /* look ahead to } or end of string */ - while (*src && *src != '}') { - g_string_append_c(name, *src); - src++; - } - /* if the } was reached - skip this */ - if (*src == '}') { - src++; - } - } else { /* process $VAR */ - /* look ahead to /, space or end of string */ - while (*src && VB_IS_IDENT(*src)) { - g_string_append_c(name, *src); - src++; - } + /* 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 variable to the destination string */ - if ((env = g_getenv(name->str))) { - g_string_append(dst, env); + /* 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); - } else if (!VB_IS_ALNUM(*src)) { - /* if we match non alnum char - mark this as beginning of new part */ - start = true; - } else { - /* we left the start of phrase behind */ - start = false; } - - g_string_append_c(dst, *src); - src++; + /* 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 == '%') { + const char *uri; + if ((uri = GET_URI())) { + /* TODO check for modifiers like :h:t:r:e */ + g_string_append(str, uri); + expanded = true; + } } - result = dst->str; - g_string_free(dst, false); + if (!expanded) { + /* restore the pointer position if no expansion was found */ + *input = prev; + /* take the char like it is */ + g_string_append_c(str, **input); + } - return result; + return expanded; } /** diff --git a/src/util.h b/src/util.h index ba74fb2..237f0ea 100644 --- a/src/util.h +++ b/src/util.h @@ -22,6 +22,12 @@ #include "main.h" +enum { + UTIL_EXP_TILDE = 0x01, /* ~/ and ~user expansion */ + UTIL_EXP_DOLLAR = 0x02, /* $ENV and ${ENV} expansion */ + UTIL_EXP_SPECIAL = 0x04, /* expand % to current URI */ +}; + typedef gboolean (*Util_Comp_Func)(const char*, const char*); typedef void *(*Util_Content_Func)(const char*); @@ -40,7 +46,8 @@ char* util_strcasestr(const char* haystack, const char* needle); char *util_str_replace(const char* search, const char* replace, const char* string); gboolean util_create_tmp_file(const char *content, char **file); char *util_build_path(const char *path, const char *dir); -char *util_expand(const char *src); +char *util_expand(const char *src, int expflags); +gboolean util_parse_expansion(const char **input, GString *str, int flags); gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src); #endif /* end of include guard: _UTIL_H */