From d949983845cdc514aebe08cf43cfc13c49495ea8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 26 May 2007 23:39:33 +0000 Subject: Add a new meta command ".ifexists" to the CLI language, to execute commands only if a specified file exists. Original patch from cjvdb. Closes #36 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1456 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/cli-command.c | 81 ++++++++++++++++++++++++++++++++++++++------- src/pulsecore/cli-command.h | 3 ++ src/pulsecore/pdispatch.c | 2 +- 3 files changed, 73 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c index e87b257b..2755c5c9 100644 --- a/src/pulsecore/cli-command.c +++ b/src/pulsecore/cli-command.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -63,9 +64,18 @@ struct command { unsigned args; }; -#define INCLUDE_META ".include" -#define FAIL_META ".fail" -#define NOFAIL_META ".nofail" +#define META_INCLUDE ".include" +#define META_FAIL ".fail" +#define META_NOFAIL ".nofail" +#define META_IFEXISTS ".ifexists" +#define META_ELSE ".else" +#define META_ENDIF ".endif" + +enum { + IFSTATE_NONE = -1, + IFSTATE_FALSE = 0, + IFSTATE_TRUE = 1, +}; /* Prototypes for all available commands */ static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail); @@ -959,7 +969,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G return 0; } -int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { +int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) { const char *cs; cs = s+strspn(s, whitespace); @@ -967,19 +977,50 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * if (*cs == '#' || !*cs) return 0; else if (*cs == '.') { - if (!strcmp(cs, FAIL_META)) + if (!strcmp(cs, META_ELSE)) { + if (!ifstate || *ifstate == IFSTATE_NONE) { + pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); + return -1; + } else if (*ifstate == IFSTATE_TRUE) + *ifstate = IFSTATE_FALSE; + else + *ifstate = IFSTATE_TRUE; + return 0; + } else if (!strcmp(cs, META_ENDIF)) { + if (!ifstate || *ifstate == IFSTATE_NONE) { + pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); + return -1; + } else + *ifstate = IFSTATE_NONE; + return 0; + } + if (ifstate && *ifstate == IFSTATE_FALSE) + return 0; + if (!strcmp(cs, META_FAIL)) *fail = 1; - else if (!strcmp(cs, NOFAIL_META)) + else if (!strcmp(cs, META_NOFAIL)) *fail = 0; else { size_t l; l = strcspn(cs, whitespace); - if (l == sizeof(INCLUDE_META)-1 && !strncmp(cs, INCLUDE_META, l)) { + if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) { const char *filename = cs+l+strspn(cs+l, whitespace); if (pa_cli_command_execute_file(c, filename, buf, fail) < 0) if (*fail) return -1; + } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) { + if (!ifstate) { + pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); + return -1; + } else if (*ifstate != IFSTATE_NONE) { + pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs); + return -1; + } else { + const char *filename = cs+l+strspn(cs+l, whitespace); + + *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE; + } } else { pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs); if (*fail) return -1; @@ -990,8 +1031,12 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * int unknown = 1; size_t l; - l = strcspn(cs, whitespace); + if (ifstate && *ifstate == IFSTATE_FALSE) + return 0; + + l = strcspn(cs, whitespace); + for (command = commands; command->name; command++) if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { int ret; @@ -1017,11 +1062,19 @@ int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int * return 0; } +int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { + return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL); +} + int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) { char line[256]; FILE *f = NULL; + int ifstate = IFSTATE_NONE; int ret = -1; - assert(c && fn && buf); + + assert(c); + assert(fn); + assert(buf); if (!(f = fopen(fn, "r"))) { pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno)); @@ -1034,7 +1087,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int char *e = line + strcspn(line, linebreak); *e = 0; - if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail) + if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) goto fail; } @@ -1049,14 +1102,18 @@ fail: int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) { const char *p; - assert(c && s && buf && fail); + int ifstate = IFSTATE_NONE; + + assert(c); + assert(s); + assert(buf); p = s; while (*p) { size_t l = strcspn(p, linebreak); char *line = pa_xstrndup(p, l); - if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) { + if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) { pa_xfree(line); return -1; } diff --git a/src/pulsecore/cli-command.h b/src/pulsecore/cli-command.h index 10d50f37..01bca8be 100644 --- a/src/pulsecore/cli-command.h +++ b/src/pulsecore/cli-command.h @@ -39,4 +39,7 @@ int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int /* Split the specified string into lines and run pa_cli_command_execute_line() for each. */ int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail); +/* Same as pa_cli_command_execute_line() but also take ifstate var. */ +int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate); + #endif diff --git a/src/pulsecore/pdispatch.c b/src/pulsecore/pdispatch.c index 758beaff..10238acb 100644 --- a/src/pulsecore/pdispatch.c +++ b/src/pulsecore/pdispatch.c @@ -258,7 +258,7 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa struct timeval tv; assert(pd && pd->ref >= 1 && cb); - r = pa_xmalloc(sizeof(struct reply_info)); + r = pa_xnew(struct reply_info, 1); r->pdispatch = pd; r->callback = cb; r->userdata = userdata; -- cgit