Discussion:
[PATCH 1/3] tab-complete commands which take program paths
Johannes Weißl
2011-05-04 01:10:02 UTC
Permalink
commands are :run and :shell
---
command_mode.c | 19 +++++++++++++-
load_dir.h | 13 ++++++++++
misc.c | 8 ++++++
misc.h | 1 +
tabexp_file.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++--------
tabexp_file.h | 2 +
6 files changed, 103 insertions(+), 13 deletions(-)

diff --git a/command_mode.c b/command_mode.c
index 99d8f4e..3fcceb2 100644
--- a/command_mode.c
+++ b/command_mode.c
@@ -1968,6 +1968,11 @@ static int filter_directories(const char *name, const struct stat *s)
return S_ISDIR(s->st_mode);
}

+static int filter_executable_files(const char *name, const struct stat *s)
+{
+ return S_ISREG(s->st_mode) && (s->st_mode & 0111);
+}
+
static int filter_any(const char *name, const struct stat *s)
{
return 1;
@@ -2030,6 +2035,16 @@ static void expand_add(const char *str)
}
}

+static void expand_program_paths(const char *str)
+{
+ if (str == NULL)
+ str = "";
+ if (str[0] == '~' || strchr(str, '/'))
+ expand_files(str);
+ else
+ expand_env_path(str, filter_executable_files);
+}
+
static void expand_load_save(const char *str)
{
int flag = parse_flags(&str, "lp");
@@ -2453,13 +2468,13 @@ struct command commands[] = {
{ "push", cmd_push, 1,-1, expand_commands, 0, 0 },
{ "quit", cmd_quit, 0, 1, NULL, 0, 0 },
{ "refresh", cmd_refresh, 0, 0, NULL, 0, 0 },
- { "run", cmd_run, 1,-1, NULL, 0, CMD_UNSAFE },
+ { "run", cmd_run, 1,-1, expand_program_paths, 0, CMD_UNSAFE },
{ "save", cmd_save, 0, 1, expand_load_save, 0, CMD_UNSAFE },
{ "search-next", cmd_search_next,0, 0, NULL, 0, 0 },
{ "search-prev", cmd_search_prev,0, 0, NULL, 0, 0 },
{ "seek", cmd_seek, 1, 1, NULL, 0, 0 },
{ "set", cmd_set, 1, 1, expand_options, 0, 0 },
- { "shell", cmd_shell, 1,-1, NULL, 0, CMD_UNSAFE },
+ { "shell", cmd_shell, 1,-1, expand_program_paths, 0, CMD_UNSAFE },
{ "showbind", cmd_showbind, 1, 1, expand_unbind_args, 0, 0 },
{ "shuffle", cmd_reshuffle, 0, 0, NULL, 0, 0 },
{ "source", cmd_source, 1, 1, expand_files, 0, CMD_UNSAFE },
diff --git a/load_dir.h b/load_dir.h
index 7a44e01..0363a8c 100644
--- a/load_dir.h
+++ b/load_dir.h
@@ -69,4 +69,17 @@ static inline void ptr_array_sort(struct ptr_array *array,
qsort(array->ptrs, count, sizeof(void *), cmp);
}

+static inline void ptr_array_unique(struct ptr_array *array,
+ int (*cmp)(const void *a, const void *b))
+{
+ void **ptrs = array->ptrs;
+ int i, j = 0;
+
+ for (i = 1; i < array->count; i++) {
+ if (cmp(&ptrs[i-1], &ptrs[i]) != 0)
+ ptrs[j++] = ptrs[i];
+ }
+ array->count = j;
+}
+
#endif
diff --git a/misc.c b/misc.c
index 6b4df37..98a1e8e 100644
--- a/misc.c
+++ b/misc.c
@@ -77,6 +77,14 @@ int strptrcmp(const void *a, const void *b)
return strcmp(as, bs);
}

+int strptrcoll(const void *a, const void *b)
+{
+ const char *as = *(char **)a;
+ const char *bs = *(char **)b;
+
+ return strcoll(as, bs);
+}
+
const char *escape(const char *str)
{
static char *buf = NULL;
diff --git a/misc.h b/misc.h
index ce01f46..159e5cf 100644
--- a/misc.h
+++ b/misc.h
@@ -25,6 +25,7 @@ extern const char *user_name;

char **get_words(const char *text);
int strptrcmp(const void *a, const void *b);
+int strptrcoll(const void *a, const void *b);
int misc_init(void);
const char *escape(const char *str);
const char *unescape(const char *str);
diff --git a/tabexp_file.c b/tabexp_file.c
index 53f574d..87371e2 100644
--- a/tabexp_file.c
+++ b/tabexp_file.c
@@ -73,20 +73,15 @@ static char *get_full_dir_name(const char *dir)
return full;
}

-/*
- * load all directory entries from directory 'dir' starting with 'start' and
- * filtered with 'filter'
- */
-static void tabexp_load_dir(const char *dirname, const char *start,
+static void load_dir(struct ptr_array *array,
+ const char *dirname, const char *start,
int (*filter)(const char *, const struct stat *))
{
int start_len = strlen(start);
struct directory dir;
- PTR_ARRAY(array);
- const char *name;
char *full_dir_name;
+ const char *name;

- /* tabexp is reseted */
full_dir_name = get_full_dir_name(dirname);
if (!full_dir_name)
return;
@@ -118,9 +113,25 @@ static void tabexp_load_dir(const char *dirname, const char *start,
} else {
str = xstrdup(name);
}
- ptr_array_add(&array, str);
+ ptr_array_add(array, str);
}
dir_close(&dir);
+out:
+ free(full_dir_name);
+}
+
+/*
+ * load all directory entries from directory 'dir' starting with 'start' and
+ * filtered with 'filter'
+ */
+static void tabexp_load_dir(const char *dirname, const char *start,
+ int (*filter)(const char *, const struct stat *))
+{
+ PTR_ARRAY(array);
+
+ /* tabexp is reseted */
+ load_dir(&array, dirname, start, filter);
+
if (array.count) {
ptr_array_sort(&array, strptrcmp);

@@ -128,8 +139,37 @@ static void tabexp_load_dir(const char *dirname, const char *start,
tabexp.tails = array.ptrs;
tabexp.count = array.count;
}
-out:
- free(full_dir_name);
+}
+
+static void tabexp_load_env_path(const char *env_path, const char *start,
+ int (*filter)(const char *, const struct stat *))
+{
+ char *path = xstrdup(env_path);
+ PTR_ARRAY(array);
+ char cwd[1024];
+ char *p = path, *n;
+
+ /* tabexp is reseted */
+ do {
+ n = strchr(p, ':');
+ if (n)
+ *n = '\0';
+ if (strcmp(p, "") == 0 && getcwd(cwd, sizeof(cwd)))
+ p = cwd;
+ load_dir(&array, p, start, filter);
+ p = n + 1;
+ } while (n);
+
+ if (array.count) {
+ ptr_array_sort(&array, strptrcoll);
+ ptr_array_unique(&array, strptrcmp);
+
+ tabexp.head = xstrdup("");
+ tabexp.tails = array.ptrs;
+ tabexp.count = array.count;
+ }
+
+ free(path);
}

void expand_files_and_dirs(const char *src,
@@ -164,3 +204,14 @@ void expand_files_and_dirs(const char *src,
}
}
}
+
+void expand_env_path(const char *src,
+ int (*filter)(const char *name, const struct stat *s))
+{
+ const char *env_path = getenv("PATH");
+
+ if (!env_path || strcmp(env_path, "") == 0)
+ return;
+
+ tabexp_load_env_path(env_path, src, filter);
+}
diff --git a/tabexp_file.h b/tabexp_file.h
index 9e8e10e..cbd0967 100644
--- a/tabexp_file.h
+++ b/tabexp_file.h
@@ -23,5 +23,7 @@

void expand_files_and_dirs(const char *src,
int (*filter)(const char *name, const struct stat *s));
+void expand_env_path(const char *src,
+ int (*filter)(const char *name, const struct stat *s));

#endif
--
1.7.5
Johannes Weißl
2011-05-04 01:10:03 UTC
Permalink
options:
dsp.ao.wav_dir
status_display_program

e.g.:
:set status_display_program=~/bin/foo
---
ao.c | 2 +-
command_mode.c | 58 --------------------------------------------------------
misc.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
misc.h | 3 ++
options.c | 2 +-
5 files changed, 63 insertions(+), 60 deletions(-)

diff --git a/ao.c b/ao.c
index ac45df2..668eb32 100644
--- a/ao.c
+++ b/ao.c
@@ -189,7 +189,7 @@ static int op_ao_get_option(int key, char **val)
case 3:
if (wav_dir == NULL)
wav_dir = xstrdup(home_dir);
- *val = xstrdup(wav_dir);
+ *val = expand_filename(wav_dir);
break;
default:
return -OP_ERROR_NOT_OPTION;
diff --git a/command_mode.c b/command_mode.c
index 3fcceb2..687fbee 100644
--- a/command_mode.c
+++ b/command_mode.c
@@ -53,7 +53,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
-#include <pwd.h>

#if defined(__sun__)
#include <ncurses.h>
@@ -67,63 +66,6 @@ static char *history_search_text = NULL;
static int arg_expand_cmd = -1;
static int prev_view = -1;

-static char *get_home_dir(const char *username)
-{
- struct passwd *passwd;
-
- if (username == NULL)
- return xstrdup(home_dir);
- passwd = getpwnam(username);
- if (passwd == NULL)
- return NULL;
- /* don't free passwd */
- return xstrdup(passwd->pw_dir);
-}
-
-static char *expand_filename(const char *name)
-{
- if (name[0] == '~') {
- char *slash;
-
- slash = strchr(name, '/');
- if (slash) {
- char *username, *home;
-
- if (slash - name - 1 > 0) {
- /* ~user/... */
- username = xstrndup(name + 1, slash - name - 1);
- } else {
- /* ~/... */
- username = NULL;
- }
- home = get_home_dir(username);
- free(username);
- if (home) {
- char *expanded;
-
- expanded = xstrjoin(home, slash);
- free(home);
- return expanded;
- } else {
- return xstrdup(name);
- }
- } else {
- if (name[1] == 0) {
- return xstrdup(home_dir);
- } else {
- char *home;
-
- home = get_home_dir(name + 1);
- if (home)
- return home;
- return xstrdup(name);
- }
- }
- } else {
- return xstrdup(name);
- }
-}
-
/* view {{{ */

void view_clear(int view)
diff --git a/misc.c b/misc.c
index 98a1e8e..1d5621e 100644
--- a/misc.c
+++ b/misc.c
@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <dirent.h>
#include <stdarg.h>
+#include <pwd.h>

const char *cmus_config_dir = NULL;
const char *home_dir = NULL;
@@ -217,3 +218,60 @@ int replaygain_decode(unsigned int field, int *gain)
*gain = (sign_bit ? -1 : 1) * val;
return name_code;
}
+
+char *get_home_dir(const char *username)
+{
+ struct passwd *passwd;
+
+ if (username == NULL)
+ return xstrdup(home_dir);
+ passwd = getpwnam(username);
+ if (passwd == NULL)
+ return NULL;
+ /* don't free passwd */
+ return xstrdup(passwd->pw_dir);
+}
+
+char *expand_filename(const char *name)
+{
+ if (name[0] == '~') {
+ char *slash;
+
+ slash = strchr(name, '/');
+ if (slash) {
+ char *username, *home;
+
+ if (slash - name - 1 > 0) {
+ /* ~user/... */
+ username = xstrndup(name + 1, slash - name - 1);
+ } else {
+ /* ~/... */
+ username = NULL;
+ }
+ home = get_home_dir(username);
+ free(username);
+ if (home) {
+ char *expanded;
+
+ expanded = xstrjoin(home, slash);
+ free(home);
+ return expanded;
+ } else {
+ return xstrdup(name);
+ }
+ } else {
+ if (name[1] == 0) {
+ return xstrdup(home_dir);
+ } else {
+ char *home;
+
+ home = get_home_dir(name + 1);
+ if (home)
+ return home;
+ return xstrdup(name);
+ }
+ }
+ } else {
+ return xstrdup(name);
+ }
+}
diff --git a/misc.h b/misc.h
index 159e5cf..120f431 100644
--- a/misc.h
+++ b/misc.h
@@ -42,4 +42,7 @@ const char *unescape(const char *str);
*/
int replaygain_decode(unsigned int field, int *gain);

+char *expand_filename(const char *name);
+char *get_home_dir(const char *username);
+
#endif
diff --git a/options.c b/options.c
index 88ad976..d029aa2 100644
--- a/options.c
+++ b/options.c
@@ -445,7 +445,7 @@ static void set_status_display_program(unsigned int id, const char *buf)
free(status_display_program);
status_display_program = NULL;
if (buf[0])
- status_display_program = xstrdup(buf);
+ status_display_program = expand_filename(buf);
}

/* }}} */
--
1.7.5
Johannes Weißl
2011-05-04 02:49:32 UTC
Permalink
---
misc.c | 2 +-
misc.h | 1 -
2 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/misc.c b/misc.c
index 1d5621e..e18f099 100644
--- a/misc.c
+++ b/misc.c
@@ -219,7 +219,7 @@ int replaygain_decode(unsigned int field, int *gain)
return name_code;
}

-char *get_home_dir(const char *username)
+static char *get_home_dir(const char *username)
{
struct passwd *passwd;

diff --git a/misc.h b/misc.h
index 120f431..aa4f9ae 100644
--- a/misc.h
+++ b/misc.h
@@ -43,6 +43,5 @@ const char *unescape(const char *str);
int replaygain_decode(unsigned int field, int *gain);

char *expand_filename(const char *name);
-char *get_home_dir(const char *username);

#endif
--
1.7.5
Johannes Weißl
2011-05-04 01:10:04 UTC
Permalink
---
command_mode.c | 41 ++++++++++++++++++++++++++++-------------
options.c | 20 ++++++++++++--------
options.h | 8 +++++++-
output.c | 4 ++--
4 files changed, 49 insertions(+), 24 deletions(-)

diff --git a/command_mode.c b/command_mode.c
index 687fbee..2e0d645 100644
--- a/command_mode.c
+++ b/command_mode.c
@@ -1987,6 +1987,17 @@ static void expand_program_paths(const char *str)
expand_env_path(str, filter_executable_files);
}

+static void expand_program_paths_option(const char *str, const char *opt)
+{
+ expand_program_paths(str);
+
+ if (tabexp.head && opt) {
+ snprintf(expbuf, sizeof(expbuf), "%s=%s", opt, tabexp.head);
+ free(tabexp.head);
+ tabexp.head = xstrdup(expbuf);
+ }
+}
+
static void expand_load_save(const char *str)
{
int flag = parse_flags(&str, "lp");
@@ -2257,29 +2268,33 @@ static void expand_options(const char *str)
{
struct cmus_opt *opt;
int len;
- char **tails;
+ char **tails, *sep;

/* tabexp is resetted */
len = strlen(str);
- if (len > 1 && str[len - 1] == '=') {
+ sep = strchr(str, '=');
+ if (len > 1 && sep) {
/* expand value */
- char *var = xstrndup(str, len - 1);
+ char *var = xstrndup(str, sep - str);

list_for_each_entry(opt, &option_head, node) {
if (strcmp(var, opt->name) == 0) {
- char buf[OPTION_MAX_SIZE];
+ if (str[len - 1] == '=') {
+ char buf[OPTION_MAX_SIZE];

- tails = xnew(char *, 1);
+ tails = xnew(char *, 1);

- buf[0] = 0;
- opt->get(opt->id, buf);
- tails[0] = xstrdup(buf);
+ buf[0] = 0;
+ opt->get(opt->id, buf);
+ tails[0] = xstrdup(buf);

- tabexp.head = xstrdup(str);
- tabexp.tails = tails;
- tabexp.count = 1;
- free(var);
- return;
+ tabexp.head = xstrdup(str);
+ tabexp.tails = tails;
+ tabexp.count = 1;
+ } else if (opt->flags & OPT_PROGRAM_PATH) {
+ expand_program_paths_option(sep + 1, var);
+ }
+ break;
}
}
free(var);
diff --git a/options.c b/options.c
index d029aa2..6f9eb75 100644
--- a/options.c
+++ b/options.c
@@ -899,14 +899,16 @@ static void set_format(unsigned int id, const char *buf)

/* }}} */

-#define DN(name) { #name, get_ ## name, set_ ## name, NULL },
-#define DT(name) { #name, get_ ## name, set_ ## name, toggle_ ## name },
+#define DN(name) { #name, get_ ## name, set_ ## name, NULL, 0 },
+#define DN_FLAGS(name, flags) { #name, get_ ## name, set_ ## name, NULL, flags },
+#define DT(name) { #name, get_ ## name, set_ ## name, toggle_ ## name, 0 },

static const struct {
const char *name;
opt_get_cb get;
opt_set_cb set;
opt_toggle_cb toggle;
+ unsigned int flags;
} simple_options[] = {
DT(aaa_mode)
DT(auto_reshuffle)
@@ -934,8 +936,8 @@ static const struct {
DT(shuffle)
DT(softvol)
DN(softvol_state)
- DN(status_display_program)
- { NULL, NULL, NULL, NULL }
+ DN_FLAGS(status_display_program, OPT_PROGRAM_PATH)
+ { NULL, NULL, NULL, NULL, 0 }
};

static const char * const color_names[NR_COLORS] = {
@@ -991,7 +993,7 @@ LIST_HEAD(option_head);
int nr_options = 0;

void option_add(const char *name, unsigned int id, opt_get_cb get,
- opt_set_cb set, opt_toggle_cb toggle)
+ opt_set_cb set, opt_toggle_cb toggle, unsigned int flags)
{
struct cmus_opt *opt = xnew(struct cmus_opt, 1);
struct list_head *item;
@@ -1001,6 +1003,7 @@ void option_add(const char *name, unsigned int id, opt_get_cb get,
opt->get = get;
opt->set = set;
opt->toggle = toggle;
+ opt->flags = flags;

item = option_head.next;
while (item != &option_head) {
@@ -1041,13 +1044,14 @@ void options_add(void)

for (i = 0; simple_options[i].name; i++)
option_add(simple_options[i].name, 0, simple_options[i].get,
- simple_options[i].set, simple_options[i].toggle);
+ simple_options[i].set, simple_options[i].toggle,
+ simple_options[i].flags);

for (i = 0; i < NR_FMTS; i++)
- option_add(str_defaults[i].name, i, get_format, set_format, NULL);
+ option_add(str_defaults[i].name, i, get_format, set_format, NULL, 0);

for (i = 0; i < NR_COLORS; i++)
- option_add(color_names[i], i, get_color, set_color, NULL);
+ option_add(color_names[i], i, get_color, set_color, NULL, 0);

op_add_options();
}
diff --git a/options.h b/options.h
index fcb69b9..71a6d0d 100644
--- a/options.h
+++ b/options.h
@@ -27,6 +27,10 @@ typedef void (*opt_get_cb)(unsigned int id, char *buf);
typedef void (*opt_set_cb)(unsigned int id, const char *buf);
typedef void (*opt_toggle_cb)(unsigned int id);

+enum {
+ OPT_PROGRAM_PATH = 1 << 0,
+};
+
struct cmus_opt {
struct list_head node;

@@ -45,6 +49,8 @@ struct cmus_opt {

/* NULL if not toggle-able */
opt_toggle_cb toggle;
+
+ unsigned int flags;
};

extern struct list_head option_head;
@@ -152,7 +158,7 @@ void resume_load(void);
void resume_exit(void);

void option_add(const char *name, unsigned int id, opt_get_cb get,
- opt_set_cb set, opt_toggle_cb toggle);
+ opt_set_cb set, opt_toggle_cb toggle, unsigned int flags);
struct cmus_opt *option_find(const char *name);
void option_set(const char *name, const char *value);
int parse_enum(const char *buf, int minval, int maxval, const char * const names[], int *val);
diff --git a/output.c b/output.c
index 6efdb1e..949786e 100644
--- a/output.c
+++ b/output.c
@@ -399,13 +399,13 @@ void op_add_options(void)
snprintf(key, sizeof(key), "dsp.%s.%s",
o->name,
o->pcm_options[oid]);
- option_add(xstrdup(key), (pid << 16) | oid, get_dsp_option, set_dsp_option, NULL);
+ option_add(xstrdup(key), (pid << 16) | oid, get_dsp_option, set_dsp_option, NULL, 0);
}
for (oid = 0; o->mixer_ops && o->mixer_options[oid]; oid++) {
snprintf(key, sizeof(key), "mixer.%s.%s",
o->name,
o->mixer_options[oid]);
- option_add(xstrdup(key), (pid << 16) | oid, get_mixer_option, set_mixer_option, NULL);
+ option_add(xstrdup(key), (pid << 16) | oid, get_mixer_option, set_mixer_option, NULL, 0);
}
pid++;
}
--
1.7.5
Gregory Petrosyan
2011-05-04 09:26:25 UTC
Permalink
Thanks, merged to -pu!

Gregory

Continue reading on narkive:
Loading...