complete implementation of the command line
authorLennart Poettering <lennart@poettering.net>
Wed, 14 Jul 2004 21:52:41 +0000 (21:52 +0000)
committerLennart Poettering <lennart@poettering.net>
Wed, 14 Jul 2004 21:52:41 +0000 (21:52 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@65 fefdeb5f-60dc-0310-8127-8f9354f1896f

12 files changed:
src/Makefile.am
src/cli-command.c [new file with mode: 0644]
src/cli-command.h [new file with mode: 0644]
src/cli.c
src/cmdline.c
src/cmdline.h
src/main.c
src/module-oss-mmap.c
src/module-oss.c
src/polypaudio.run [new file with mode: 0755]
src/strbuf.c
src/strbuf.h

index bdd621a..c973af5 100644 (file)
@@ -28,14 +28,11 @@ pkglib_LTLIBRARIES=libiochannel.la \
                liboss-util.la \
                libioline.la \
                libcli.la \
-               libtokenizer.la \
-               libdynarray.la \
                libprotocol-cli.la \
                libtagstruct.la \
                libpstream-util.la \
                libpdispatch.la \
                libauthkey.la \
-               libclitext.la \
                libsocket-util.la \
                libprotocol-simple.la \
                libprotocol-esound.la \
@@ -85,7 +82,11 @@ polypaudio_SOURCES = idxset.c idxset.h \
                sconv-s16be.c sconv-s16be.h \
                sioman.c sioman.h \
                modargs.c modargs.h \
-               cmdline.c cmdline.h
+               cmdline.c cmdline.h \
+               cli-command.c cli-command.h \
+               clitext.c clitext.h \
+               tokenizer.c tokenizer.h \
+               dynarray.c dynarray.h
 
 polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS)
 polypaudio_INCLUDES = $(INCLTDL)
@@ -118,7 +119,7 @@ libpdispatch_la_LIBADD = libtagstruct.la
 
 libiochannel_la_SOURCES = iochannel.c iochannel.h
 libiochannel_la_LDFLAGS = -avoid-version
-libiochannel_la_LIBDADD = libsocket-util.la
+libiochannel_la_LIBADD = libsocket-util.la
 
 libpacket_la_SOURCES = packet.c packet.h
 libpacket_la_LDFLAGS = -avoid-version
@@ -132,14 +133,7 @@ libioline_la_LIBADD = libiochannel.la
 
 libcli_la_SOURCES = cli.c cli.h
 libcli_la_LDFLAGS = -avoid-version
-libcli_la_LIBADD = libiochannel.la libioline.la libclitext.la libtokenizer.la
-
-libdynarray_la_SOURCES = dynarray.c dynarray.h
-libdynarray_la_LDFLAGS = -avoid-version
-
-libtokenizer_la_SOURCES = tokenizer.c tokenizer.h
-libtokenizer_la_LDFLAGS = -avoid-version
-libtokenizer_la_LIBADD = libdynarray.la
+libcli_la_LIBADD = libiochannel.la libioline.la
 
 libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h
 libprotocol_cli_la_LDFLAGS = -avoid-version
@@ -159,9 +153,6 @@ libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la
 libauthkey_la_SOURCES = authkey.c authkey.h
 libauthkey_la_LDFLAGS = -avoid-version
 
-libclitext_la_SOURCES = clitext.c clitext.h
-libclitext_la_LDFLAGS = -avoid-version
-
 libsocket_util_la_SOURCES = socket-util.c socket-util.h
 libsocket_util_la_LDFLAGS = -avoid-version
 
@@ -219,7 +210,7 @@ module_oss_mmap_la_LIBADD = liboss-util.la
 
 module_cli_la_SOURCES = module-cli.c
 module_cli_la_LDFLAGS = -module -avoid-version
-module_cli_la_LIBADD = libcli.la libiochannel.la libtokenizer.la
+module_cli_la_LIBADD = libcli.la libiochannel.la
 
 libpolyp_la_SOURCES = polyp.c polyp.h \
                polypdef.h \
diff --git a/src/cli-command.c b/src/cli-command.c
new file mode 100644 (file)
index 0000000..06e0eb3
--- /dev/null
@@ -0,0 +1,531 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "cli-command.h"
+#include "module.h"
+#include "sink.h"
+#include "source.h"
+#include "client.h"
+#include "sinkinput.h"
+#include "sourceoutput.h"
+#include "tokenizer.h"
+#include "strbuf.h"
+#include "namereg.h"
+#include "clitext.h"
+
+struct command {
+    const char *name;
+    int (*proc) (struct pa_core *c, struct pa_tokenizer*t, struct pa_strbuf *buf, int *fail, int *verbose);
+    const char *help;
+    unsigned args;
+};
+
+static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose);
+
+static const struct command commands[] = {
+    { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
+    { "help",                    pa_cli_command_help,               "Show this help",               1 },
+    { "modules",                 pa_cli_command_modules,            "List loaded modules",          1 },
+    { "sinks",                   pa_cli_command_sinks,              "List loaded sinks",            1 },
+    { "sources",                 pa_cli_command_sources,            "List loaded sources",          1 },
+    { "clients",                 pa_cli_command_clients,            "List loaded clients",          1 },
+    { "sink_inputs",             pa_cli_command_sink_inputs,        "List sink inputs",             1 },
+    { "source_outputs",          pa_cli_command_source_outputs,     "List source outputs",          1 },
+    { "stat",                    pa_cli_command_stat,               "Show memory block statistics", 1 },
+    { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
+    { "ls",                      pa_cli_command_info,               NULL,                           1 },
+    { "list",                    pa_cli_command_info,               NULL,                           1 },
+    { "load",                    pa_cli_command_load,               "Load a module (args: name, arguments)",                     3},
+    { "unload",                  pa_cli_command_unload,             "Unload a module (args: index)",                             2},
+    { "sink_volume",             pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)",             3},
+    { "sink_input_volume",       pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index|name, volume)", 3},
+    { "sink_default",            pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
+    { "source_default",          pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
+    { "kill_client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
+    { "kill_sink_input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
+    { "kill_source_output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
+    { NULL, NULL, NULL, 0 }
+};
+
+static const char whitespace[] = " \t\n\r";
+static const char linebreak[] = "\n\r";
+
+static uint32_t parse_index(const char *n) {
+    long index;
+    char *x;
+    index = strtol(n, &x, 0);
+    if (!x || *x != 0 || index < 0)
+        return (uint32_t) PA_IDXSET_INVALID;
+
+    return (uint32_t) index;
+}
+
+static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    assert(c && c->mainloop && t);
+    c->mainloop->quit(c->mainloop, 0);
+    return 0;
+}
+
+static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const struct command*command;
+    assert(c && t && buf);
+
+    pa_strbuf_puts(buf, "Available commands:\n");
+    
+    for (command = commands; command->name; command++)
+        if (command->help)
+            pa_strbuf_printf(buf, "    %-20s %s\n", command->name, command->help);
+    return 0;
+}
+
+static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char *s;
+    assert(c && t);
+    s = pa_module_list_to_string(c);
+    assert(s);
+    pa_strbuf_puts(buf, s);
+    free(s);
+    return 0;
+}
+
+static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char *s;
+    assert(c && t);
+    s = pa_client_list_to_string(c);
+    assert(s);
+    pa_strbuf_puts(buf, s);
+    free(s);
+    return 0;
+}
+
+static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char *s;
+    assert(c && t);
+    s = pa_sink_list_to_string(c);
+    assert(s);
+    pa_strbuf_puts(buf, s);
+    free(s);
+    return 0;
+}
+
+static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char *s;
+    assert(c && t);
+    s = pa_source_list_to_string(c);
+    assert(s);
+    pa_strbuf_puts(buf, s);
+    free(s);
+    return 0;
+}
+
+static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char *s;
+    assert(c && t);
+    s = pa_sink_input_list_to_string(c);
+    assert(s);
+    pa_strbuf_puts(buf, s);
+    free(s);
+    return 0;
+}
+
+static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char *s;
+    assert(c && t);
+    s = pa_source_output_list_to_string(c);
+    assert(s);
+    pa_strbuf_puts(buf, s);
+    free(s);
+    return 0;
+}
+
+static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    assert(c && t);
+    pa_strbuf_printf(buf, "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_count, pa_memblock_total);
+    return 0;
+}
+
+static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    assert(c && t);
+    pa_cli_command_stat(c, t, buf, fail, verbose);
+    pa_cli_command_modules(c, t, buf, fail, verbose);
+    pa_cli_command_sinks(c, t, buf, fail, verbose);
+    pa_cli_command_sources(c, t, buf, fail, verbose);
+    pa_cli_command_clients(c, t, buf, fail, verbose);
+    pa_cli_command_sink_inputs(c, t, buf, fail, verbose);
+    pa_cli_command_source_outputs(c, t, buf, fail, verbose);
+    return 0;
+}
+
+static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    struct pa_module *m;
+    const char *name;
+    char txt[256];
+    assert(c && t);
+
+    if (!(name = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
+        return -1;
+    }
+    
+    if (!(m = pa_module_load(c, name,  pa_tokenizer_get(t, 2)))) {
+        pa_strbuf_puts(buf, "Module load failed.\n");
+        return -1;
+    }
+
+    if (*verbose)
+        snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index);
+    pa_strbuf_puts(buf, txt);
+    return 0;
+}
+
+static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    struct pa_module *m;
+    uint32_t index;
+    const char *i;
+    char *e;
+    assert(c && t);
+
+    if (!(i = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify the module index.\n");
+        return -1;
+    }
+
+    index = (uint32_t) strtoul(i, &e, 10);
+    if (*e || !(m = pa_idxset_get_by_index(c->modules, index))) {
+        pa_strbuf_puts(buf, "Invalid module index.\n");
+        return -1;
+    }
+
+    pa_module_unload_request(c, m);
+    return 0;
+}
+
+static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n, *v;
+    char *x = NULL;
+    struct pa_sink *sink;
+    long volume;
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
+        return -1;
+    }
+
+    if (!(v = pa_tokenizer_get(t, 2))) {
+        pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
+        return -1;
+    }
+
+    volume = strtol(v, &x, 0);
+    if (!x || *x != 0 || volume < 0) {
+        pa_strbuf_puts(buf, "Failed to parse volume.\n");
+        return -1;
+    }
+
+    if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
+        pa_strbuf_puts(buf, "No sink found by this name or index.\n");
+        return -1;
+    }
+
+    sink->volume = (uint32_t) volume;
+    return 0;
+}
+
+static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n, *v;
+    struct pa_sink_input *si;
+    long volume;
+    uint32_t index;
+    char *x;
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
+        return -1;
+    }
+
+    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
+        pa_strbuf_puts(buf, "Failed to parse index.\n");
+        return -1;
+    }
+
+    if (!(v = pa_tokenizer_get(t, 2))) {
+        pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
+        return -1;
+    }
+
+    x = NULL;
+    volume = strtol(v, &x, 0);
+    if (!x || *x != 0 || volume < 0) {
+        pa_strbuf_puts(buf, "Failed to parse volume.\n");
+        return -1;
+    }
+
+    if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) index))) {
+        pa_strbuf_puts(buf, "No sink input found with this index.\n");
+        return -1;
+    }
+
+    si->volume = (uint32_t) volume;
+    return 0;
+}
+
+static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n;
+    struct pa_sink *sink;
+    assert(c && t);
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
+        return -1;
+    }
+
+    if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
+        pa_strbuf_puts(buf, "No sink found by this name or index.\n");
+        return -1;
+    }
+
+    c->default_sink_index = sink->index;
+    return 0;
+}
+
+static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n;
+    struct pa_source *source;
+    assert(c && t);
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
+        return -1;
+    }
+
+    if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
+        pa_strbuf_puts(buf, "No source found by this name or index.\n");
+        return -1;
+    }
+
+    c->default_source_index = source->index;
+    return 0;
+}
+
+static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n;
+    struct pa_client *client;
+    uint32_t index;
+    assert(c && t);
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
+        return -1;
+    }
+
+    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
+        pa_strbuf_puts(buf, "Failed to parse index.\n");
+        return -1;
+    }
+
+    if (!(client = pa_idxset_get_by_index(c->clients, index))) {
+        pa_strbuf_puts(buf, "No client found by this index.\n");
+        return -1;
+    }
+
+    pa_client_kill(client);
+    return 0;
+}
+
+static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n;
+    struct pa_sink_input *sink_input;
+    uint32_t index;
+    assert(c && t);
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
+        return -1;
+    }
+
+    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
+        pa_strbuf_puts(buf, "Failed to parse index.\n");
+        return -1;
+    }
+
+    if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, index))) {
+        pa_strbuf_puts(buf, "No sink input found by this index.\n");
+        return -1;
+    }
+
+    pa_sink_input_kill(sink_input);
+    return 0;
+}
+
+static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *n;
+    struct pa_source_output *source_output;
+    uint32_t index;
+    assert(c && t);
+
+    if (!(n = pa_tokenizer_get(t, 1))) {
+        pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
+        return -1;
+    }
+
+    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
+        pa_strbuf_puts(buf, "Failed to parse index.\n");
+        return -1;
+    }
+
+    if (!(source_output = pa_idxset_get_by_index(c->source_outputs, index))) {
+        pa_strbuf_puts(buf, "No source output found by this index.\n");
+        return -1;
+    }
+
+    pa_source_output_kill(source_output);
+    return 0;
+}
+
+int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *cs;
+    
+    cs = s+strspn(s, whitespace);
+
+    if (*cs == '#' || !*cs)
+        return 0;
+    else if (*cs == '.') {
+        static const char fail_meta[] = ".fail";
+        static const char nofail_meta[] = ".nofail";
+        static const char verbose_meta[] = ".verbose";
+        static const char noverbose_meta[] = ".noverbose";
+
+        if (!strcmp(cs, verbose_meta))
+            *verbose = 1;
+        else if (!strcmp(cs, noverbose_meta))
+            *verbose = 0;
+        else if (!strcmp(cs, fail_meta))
+            *fail = 1;
+        else if (!strcmp(cs, nofail_meta))
+            *fail = 0;
+        else {
+            size_t l;
+            static const char include_meta[] = ".include";
+            l = strcspn(cs, whitespace);
+
+            if (l == sizeof(include_meta)-1 && !strncmp(cs, include_meta, l)) {
+                const char *filename = cs+l+strspn(cs+l, whitespace);
+
+                if (pa_cli_command_execute_file(c, filename, buf, fail, verbose) < 0)
+                    if (*fail) return -1;
+            } else {
+                pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
+                if (*fail) return -1;
+            }
+        }
+    } else {
+        const struct command*command;
+        int unknown = 1;
+        size_t l;
+        
+        l = strcspn(cs, whitespace);
+
+        for (command = commands; command->name; command++) 
+            if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
+                int ret;
+                struct pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
+                assert(t);
+                ret = command->proc(c, t, buf, fail, verbose);
+                pa_tokenizer_free(t);
+                unknown = 0;
+
+                if (ret < 0 && *fail)
+                    return -1;
+                
+                break;
+            }
+
+        if (unknown) {
+            pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
+            if (*fail)
+                return -1;
+        }
+    }
+
+    return 0;
+}
+
+int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail, int *verbose) {
+    char line[256];
+    FILE *f = NULL;
+    int ret = -1;
+    assert(c && fn && buf);
+
+    if (!(f = fopen(fn, "r"))) {
+        pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, strerror(errno));
+        if (!*fail)
+            ret = 0;
+        goto fail;
+    }
+
+    if (*verbose)
+        pa_strbuf_printf(buf, "Executing file: '%s'\n", fn);
+
+    while (fgets(line, sizeof(line), f)) {
+        char *e = line + strcspn(line, linebreak);
+        *e = 0;
+
+        if (pa_cli_command_execute_line(c, line, buf, fail, verbose) < 0 && *fail)
+            goto fail;
+    }
+
+    if (*verbose)
+        pa_strbuf_printf(buf, "Executed file: '%s'\n", fn);
+
+    ret = 0;
+
+fail:
+    if (f)
+        fclose(f);
+
+    return ret;
+}
+
+int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) {
+    const char *p;
+    assert(c && s && buf && fail && verbose);
+
+    p = s;
+    while (*p) {
+        size_t l = strcspn(p, linebreak);
+        char *line = strndup(p, l);
+        assert(line);
+        
+        if (pa_cli_command_execute_line(c, line, buf, fail, verbose) < 0&& *fail) {
+            free(line);
+            return -1;
+        }
+        free(line);
+
+        p += l;
+        p += strspn(p, linebreak);
+    }
+
+    return 0;
+}
diff --git a/src/cli-command.h b/src/cli-command.h
new file mode 100644 (file)
index 0000000..f95261b
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef fooclicommandhfoo
+#define fooclicommandhfoo
+
+#include "strbuf.h"
+#include "core.h"
+
+int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose);
+int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail, int *verbose);
+int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose);
+
+#endif
index d5b46c4..b4d6625 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -15,6 +15,7 @@
 #include "strbuf.h"
 #include "namereg.h"
 #include "clitext.h"
+#include "cli-command.h"
 
 struct pa_cli {
     struct pa_core *core;
@@ -24,62 +25,12 @@ struct pa_cli {
     void *userdata;
 
     struct pa_client *client;
-};
 
-struct command {
-    const char *name;
-    int (*proc) (struct pa_cli *cli, struct pa_tokenizer*t);
-    const char *help;
-    unsigned args;
+    int fail, verbose, kill_requested, defer_kill;
 };
 
 static void line_callback(struct pa_ioline *line, const char *s, void *userdata);
 
-static int pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t);
-static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t);
-
-static const struct command commands[] = {
-    { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
-    { "help",                    pa_cli_command_help,               "Show this help",               1 },
-    { "modules",                 pa_cli_command_modules,            "List loaded modules",          1 },
-    { "sinks",                   pa_cli_command_sinks,              "List loaded sinks",            1 },
-    { "sources",                 pa_cli_command_sources,            "List loaded sources",          1 },
-    { "clients",                 pa_cli_command_clients,            "List loaded clients",          1 },
-    { "sink_inputs",             pa_cli_command_sink_inputs,        "List sink inputs",             1 },
-    { "source_outputs",          pa_cli_command_source_outputs,     "List source outputs",          1 },
-    { "stat",                    pa_cli_command_stat,               "Show memory block statistics", 1 },
-    { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
-    { "ls",                      pa_cli_command_info,               NULL,                           1 },
-    { "list",                    pa_cli_command_info,               NULL,                           1 },
-    { "load",                    pa_cli_command_load,               "Load a module (args: name, arguments)",                     3},
-    { "unload",                  pa_cli_command_unload,             "Unload a module (args: index)",                             2},
-    { "sink_volume",             pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)",             3},
-    { "sink_input_volume",       pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index|name, volume)", 3},
-    { "sink_default",            pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
-    { "source_default",          pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
-    { "kill_client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
-    { "kill_sink_input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
-    { "kill_source_output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
-    { NULL, NULL, NULL, 0 }
-};
-
 static const char prompt[] = ">>> ";
 
 static void client_kill(struct pa_client *c);
@@ -108,6 +59,9 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct
     pa_ioline_set_callback(c->line, line_callback, c);
     pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n");
     pa_ioline_puts(c->line, prompt);
+
+    c->fail = c->kill_requested = c->defer_kill = 0;
+    c->verbose = 1;
     
     return c;
 }
@@ -123,16 +77,20 @@ static void client_kill(struct pa_client *client) {
     struct pa_cli *c;
     assert(client && client->userdata);
     c = client->userdata;
+    
     fprintf(stderr, "CLI client killed.\n");
-
-    if (c->eof_callback)
-        c->eof_callback(c, c->userdata);
+    if (c->defer_kill)
+        c->kill_requested = 1;
+    else {
+        if (c->eof_callback)
+            c->eof_callback(c, c->userdata);
+    }
 }
 
 static void line_callback(struct pa_ioline *line, const char *s, void *userdata) {
+    struct pa_strbuf *buf;
     struct pa_cli *c = userdata;
-    const char *cs;
-    const char delimiter[] = " \t\n\r";
+    char *p;
     assert(line && c);
 
     if (!s) {
@@ -143,34 +101,19 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata)
         return;
     }
 
-    cs = s+strspn(s, delimiter);
-    if (*cs && *cs != '#') {
-        const struct command*command;
-        int unknown = 1;
-        size_t l;
-        
-        l = strcspn(s, delimiter);
-
-        for (command = commands; command->name; command++) 
-            if (strlen(command->name) == l && !strncmp(s, command->name, l)) {
-                int ret;
-                struct pa_tokenizer *t = pa_tokenizer_new(s, command->args);
-                assert(t);
-                ret = command->proc(c, t);
-                pa_tokenizer_free(t);
-                unknown = 0;
-
-                /* A negative return value denotes that the cli object is probably invalid now */
-                if (ret < 0)
-                    return;
-                break;
-            }
+    buf = pa_strbuf_new();
+    assert(buf);
+    c->defer_kill++;
+    pa_cli_command_execute_line(c->core, s, buf, &c->fail, &c->verbose);
+    c->defer_kill--;
+    pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf));
+    free(p);
 
-        if (unknown)
-            pa_ioline_puts(line, "Unknown command\n");
-    }
-    
-    pa_ioline_puts(line, prompt);
+    if (c->kill_requested) {
+        if (c->eof_callback)
+            c->eof_callback(c, c->userdata);
+    } else    
+        pa_ioline_puts(line, prompt);
 }
 
 void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void *userdata), void *userdata) {
@@ -178,346 +121,3 @@ void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void
     c->eof_callback = cb;
     c->userdata = userdata;
 }
-
-static uint32_t parse_index(const char *n) {
-    long index;
-    char *x;
-    index = strtol(n, &x, 0);
-    if (!x || *x != 0 || index < 0)
-        return (uint32_t) PA_IDXSET_INVALID;
-
-    return (uint32_t) index;
-}
-
-static int pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t) {
-    assert(c && c->core && c->core->mainloop && t);
-    c->core->mainloop->quit(c->core->mainloop, 0);
-    return 0;
-}
-
-static int pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t) {
-    const struct command*command;
-    struct pa_strbuf *pa_strbuf;
-    char *p;
-    assert(c && t);
-
-    pa_strbuf = pa_strbuf_new();
-    assert(pa_strbuf);
-
-    pa_strbuf_puts(pa_strbuf, "Available commands:\n");
-    
-    for (command = commands; command->name; command++)
-        if (command->help)
-            pa_strbuf_printf(pa_strbuf, "    %-20s %s\n", command->name, command->help);
-
-    pa_ioline_puts(c->line, p = pa_strbuf_tostring_free(pa_strbuf));
-    free(p);
-    return 0;
-}
-
-static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t) {
-    char *s;
-    assert(c && t);
-    s = pa_module_list_to_string(c->core);
-    assert(s);
-    pa_ioline_puts(c->line, s);
-    free(s);
-    return 0;
-}
-
-static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t) {
-    char *s;
-    assert(c && t);
-    s = pa_client_list_to_string(c->core);
-    assert(s);
-    pa_ioline_puts(c->line, s);
-    free(s);
-    return 0;
-}
-
-static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t) {
-    char *s;
-    assert(c && t);
-    s = pa_sink_list_to_string(c->core);
-    assert(s);
-    pa_ioline_puts(c->line, s);
-    free(s);
-    return 0;
-}
-
-static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t) {
-    char *s;
-    assert(c && t);
-    s = pa_source_list_to_string(c->core);
-    assert(s);
-    pa_ioline_puts(c->line, s);
-    free(s);
-    return 0;
-}
-
-static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t) {
-    char *s;
-    assert(c && t);
-    s = pa_sink_input_list_to_string(c->core);
-    assert(s);
-    pa_ioline_puts(c->line, s);
-    free(s);
-    return 0;
-}
-
-static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t) {
-    char *s;
-    assert(c && t);
-    s = pa_source_output_list_to_string(c->core);
-    assert(s);
-    pa_ioline_puts(c->line, s);
-    free(s);
-    return 0;
-}
-
-static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t) {
-    char txt[256];
-    assert(c && t);
-    snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_count, pa_memblock_total);
-    pa_ioline_puts(c->line, txt);
-    return 0;
-}
-
-static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t) {
-    assert(c && t);
-    pa_cli_command_stat(c, t);
-    pa_cli_command_modules(c, t);
-    pa_cli_command_sinks(c, t);
-    pa_cli_command_sources(c, t);
-    pa_cli_command_clients(c, t);
-    pa_cli_command_sink_inputs(c, t);
-    pa_cli_command_source_outputs(c, t);
-    return 0;
-}
-
-static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t) {
-    struct pa_module *m;
-    const char *name;
-    char txt[256];
-    assert(c && t);
-
-    if (!(name = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specfiy the module name and optionally arguments.\n");
-        return 0;
-    }
-    
-    if (!(m = pa_module_load(c->core, name,  pa_tokenizer_get(t, 2)))) {
-        pa_ioline_puts(c->line, "Module load failed.\n");
-        return 0;
-    }
-
-    snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index);
-    pa_ioline_puts(c->line, txt);
-    return 0;
-}
-
-static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) {
-    struct pa_module *m;
-    uint32_t index;
-    const char *i;
-    char *e;
-    assert(c && t);
-
-    if (!(i = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specfiy the module index.\n");
-        return 0;
-    }
-
-    index = (uint32_t) strtoul(i, &e, 10);
-    if (*e || !(m = pa_idxset_get_by_index(c->core->modules, index))) {
-        pa_ioline_puts(c->line, "Invalid module index.\n");
-        return 0;
-    }
-
-    pa_module_unload_request(c->core, m);
-    return 0;
-}
-
-static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n, *v;
-    char *x = NULL;
-    struct pa_sink *sink;
-    long volume;
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n");
-        return 0;
-    }
-
-    if (!(v = pa_tokenizer_get(t, 2))) {
-        pa_ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
-        return 0;
-    }
-
-    volume = strtol(v, &x, 0);
-    if (!x || *x != 0 || volume < 0) {
-        pa_ioline_puts(c->line, "Failed to parse volume.\n");
-        return 0;
-    }
-
-    if (!(sink = pa_namereg_get(c->core, n, PA_NAMEREG_SINK))) {
-        pa_ioline_puts(c->line, "No sink found by this name or index.\n");
-        return 0;
-    }
-
-    sink->volume = (uint32_t) volume;
-    return 0;
-}
-
-static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n, *v;
-    struct pa_sink_input *si;
-    long volume;
-    uint32_t index;
-    char *x;
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n");
-        return 0;
-    }
-
-    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
-        pa_ioline_puts(c->line, "Failed to parse index.\n");
-        return 0;
-    }
-
-    if (!(v = pa_tokenizer_get(t, 2))) {
-        pa_ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
-        return 0;
-    }
-
-    x = NULL;
-    volume = strtol(v, &x, 0);
-    if (!x || *x != 0 || volume < 0) {
-        pa_ioline_puts(c->line, "Failed to parse volume.\n");
-        return 0;
-    }
-
-    if (!(si = pa_idxset_get_by_index(c->core->sink_inputs, (uint32_t) index))) {
-        pa_ioline_puts(c->line, "No sink input found with this index.\n");
-        return 0;
-    }
-
-    si->volume = (uint32_t) volume;
-    return 0;
-}
-
-static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n;
-    struct pa_sink *sink;
-    assert(c && t);
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n");
-        return 0;
-    }
-
-    if (!(sink = pa_namereg_get(c->core, n, PA_NAMEREG_SINK))) {
-        pa_ioline_puts(c->line, "No sink found by this name or index.\n");
-        return 0;
-    }
-
-    c->core->default_sink_index = sink->index;
-    return 0;
-}
-
-static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n;
-    struct pa_source *source;
-    assert(c && t);
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a source either by its name or its index.\n");
-        return 0;
-    }
-
-    if (!(source = pa_namereg_get(c->core, n, PA_NAMEREG_SOURCE))) {
-        pa_ioline_puts(c->line, "No source found by this name or index.\n");
-        return 0;
-    }
-
-    c->core->default_source_index = source->index;
-    return 0;
-}
-
-static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n;
-    struct pa_client *client;
-    uint32_t index;
-    int ret;
-    assert(c && t);
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a client by its index.\n");
-        return 0;
-    }
-
-    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
-        pa_ioline_puts(c->line, "Failed to parse index.\n");
-        return 0;
-    }
-
-    if (!(client = pa_idxset_get_by_index(c->core->clients, index))) {
-        pa_ioline_puts(c->line, "No client found by this index.\n");
-        return 0;
-    }
-
-    ret = (client->userdata == c) ? -1 : 0;
-    pa_client_kill(client);
-    return ret;
-}
-
-static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n;
-    struct pa_sink_input *sink_input;
-    uint32_t index;
-    assert(c && t);
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n");
-        return 0;
-    }
-
-    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
-        pa_ioline_puts(c->line, "Failed to parse index.\n");
-        return 0;
-    }
-
-    if (!(sink_input = pa_idxset_get_by_index(c->core->sink_inputs, index))) {
-        pa_ioline_puts(c->line, "No sink input found by this index.\n");
-        return 0;
-    }
-
-    pa_sink_input_kill(sink_input);
-    return 0;
-}
-
-static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t) {
-    const char *n;
-    struct pa_source_output *source_output;
-    uint32_t index;
-    assert(c && t);
-
-    if (!(n = pa_tokenizer_get(t, 1))) {
-        pa_ioline_puts(c->line, "You need to specify a source output by its index.\n");
-        return 0;
-    }
-
-    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
-        pa_ioline_puts(c->line, "Failed to parse index.\n");
-        return 0;
-    }
-
-    if (!(source_output = pa_idxset_get_by_index(c->core->source_outputs, index))) {
-        pa_ioline_puts(c->line, "No source output found by this index.\n");
-        return 0;
-    }
-
-    pa_source_output_kill(source_output);
-    return 0;
-}
index 36fe3e6..d53d028 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "cmdline.h"
 #include "util.h"
+#include "strbuf.h"
 
 void pa_cmdline_help(const char *argv0) {
     const char *e;
@@ -17,56 +18,38 @@ void pa_cmdline_help(const char *argv0) {
     
     printf("%s [options]\n"
            "  -L MODULE  Load the specified plugin module with the specified argument\n"
-           "  -F FILE    A shortcut for '-L module-cli file=FILE', i.e. run the specified script after startup\n"
-           "  -C         A shortcut for '-L module-cli', i.e. open a command line on the running TTY\n"
+           "  -F FILE    Run the specified script\n"
+           "  -C         Open a command line on the running TTY\n"
            "  -D         Daemonize after loading the modules\n"
+           "  -f         Dont quit when the startup fails\n"
+           "  -v         Verbose startup\n"
            "  -h         Show this help\n", e);
 }
 
-static void add_module(struct pa_cmdline *cmdline, char *name, char *arguments) {
-    struct pa_cmdline_module *m;
-    assert(cmdline && name);
-
-    m = malloc(sizeof(struct pa_cmdline_module));
-    assert(m);
-    m->name = name;
-    m->arguments = name;
-    m->next = NULL;
-
-    if (cmdline->last_module)
-        cmdline->last_module->next = m;
-    else {
-        assert(!cmdline->first_module);
-        cmdline->first_module = m;
-    }
-    cmdline->last_module = m;
-}
-
 struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
     char c;
     struct pa_cmdline *cmdline = NULL;
+    struct pa_strbuf *buf = NULL;
     assert(argc && argv);
 
     cmdline = malloc(sizeof(struct pa_cmdline));
     assert(cmdline);
-    cmdline->daemonize = cmdline->help = 0;
-    cmdline->first_module = cmdline->last_module = NULL;
+    cmdline->daemonize = cmdline->help = cmdline->verbose = 0;
+    cmdline->fail = 1;
+
+    buf = pa_strbuf_new();
+    assert(buf);
     
-    while ((c = getopt(argc, argv, "L:F:CDh")) != -1) {
+    while ((c = getopt(argc, argv, "L:F:CDhfv")) != -1) {
         switch (c) {
-            case 'L': {
-                char *space;
-                if ((space = strchr(optarg, ' ')))
-                    add_module(cmdline, strndup(optarg, space-optarg), space+1);
-                else
-                    add_module(cmdline, strdup(optarg), NULL);
+            case 'L':
+                pa_strbuf_printf(buf, "load %s\n", optarg);
                 break;
-            }
             case 'F':
-                add_module(cmdline, strdup("module-cli"), pa_sprintf_malloc("file='%s'", optarg));
+                pa_strbuf_printf(buf, ".include %s\n", optarg);
                 break;
             case 'C':
-                add_module(cmdline, strdup("module-cli"), NULL);
+                pa_strbuf_puts(buf, "load module-cli\n");
                 break;
             case 'D':
                 cmdline->daemonize = 1;
@@ -74,29 +57,30 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
             case 'h':
                 cmdline->help = 1;
                 break;
+            case 'f':
+                cmdline->fail = 0;
+                break;
+            case 'v':
+                cmdline->verbose = 0;
+                break;
             default:
                 goto fail;
         }
     }
 
+    cmdline->cli_commands = pa_strbuf_tostring_free(buf);
     return cmdline;
     
 fail:
     if (cmdline)
         pa_cmdline_free(cmdline);
+    if (buf)
+        pa_strbuf_free(buf);
     return NULL;
 }
 
 void pa_cmdline_free(struct pa_cmdline *cmd) {
-    struct pa_cmdline_module *m;
     assert(cmd);
-
-    while ((m = cmd->first_module)) {
-        cmd->first_module = m->next;
-        free(m->name);
-        free(m->arguments);
-        free(m);
-    }
-        
+    free(cmd->cli_commands);
     free(cmd);
 }
index 9a64770..ec2dd0c 100644 (file)
@@ -1,14 +1,10 @@
 #ifndef foocmdlinehfoo
 #define foocmdlinehfoo
 
-struct pa_cmdline_module {
-    char *name, *arguments;
-    struct pa_cmdline_module *next;
-};
 
 struct pa_cmdline {
-    int daemonize, help;
-    struct pa_cmdline_module *first_module, *last_module;
+    int daemonize, help, fail, verbose;
+    char *cli_commands;
 };
 
 struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []);
index e2c8eb6..d2ae61c 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdlib.h>
 #include <stdio.h>
 #include <signal.h>
 #include <stddef.h>
@@ -10,6 +11,7 @@
 #include "module.h"
 #include "mainloop-signal.h"
 #include "cmdline.h"
+#include "cli-command.h"
 
 static struct pa_mainloop *mainloop;
 
@@ -28,10 +30,12 @@ static void aux_signal_callback(void *id, int sig, void *userdata) {
 int main(int argc, char *argv[]) {
     struct pa_core *c;
     struct pa_cmdline *cmdline = NULL;
+    struct pa_strbuf *buf = NULL;
+    char *s;
     int r, retval = 0;
 
     if (!(cmdline = pa_cmdline_parse(argc, argv))) {
-        fprintf(stderr, "Failed to parse command line.\n");
+        fprintf(stderr, __FILE__": failed to parse command line.\n");
         return 1;
     }
 
@@ -55,33 +59,48 @@ int main(int argc, char *argv[]) {
     c = pa_core_new(pa_mainloop_get_api(mainloop));
     assert(c);
     
-    pa_module_load(c, "module-oss-mmap", "device=/dev/dsp playback=1 record=1");
-/*    pa_module_load(c, "module-oss-mmap", "/dev/dsp1");*/
-/*    pa_module_load(c, "module-pipe-sink", NULL);*/
+/*    pa_module_load(c, "module-oss-mmap", "device=/dev/dsp playback=1 record=1");
+    pa_module_load(c, "module-oss-mmap", "/dev/dsp1");
+    pa_module_load(c, "module-pipe-sink", NULL);
     pa_module_load(c, "module-simple-protocol-tcp", NULL);
-/*    pa_module_load(c, "module-simple-protocol-unix", NULL);
+    pa_module_load(c, "module-simple-protocol-unix", NULL);
     pa_module_load(c, "module-cli-protocol-tcp", NULL);
     pa_module_load(c, "module-cli-protocol-unix", NULL);
-    pa_module_load(c, "module-native-protocol-tcp", NULL);*/
+    pa_module_load(c, "module-native-protocol-tcp", NULL);
     pa_module_load(c, "module-native-protocol-unix", NULL);
     pa_module_load(c, "module-esound-protocol-tcp", NULL);
-    pa_module_load(c, "module-cli", NULL);
+    pa_module_load(c, "module-cli", NULL);*/
 
     pa_signal_register(SIGUSR1, aux_signal_callback, c);
     pa_signal_register(SIGUSR2, aux_signal_callback, c);
+
+    buf = pa_strbuf_new();
+    assert(buf);
+    r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose);
+    fprintf(stderr, s = pa_strbuf_tostring_free(buf));
+    free(s);
     
-    fprintf(stderr, "main: mainloop entry.\n");
-    if (pa_mainloop_run(mainloop, &retval) < 0)
+    if (r < 0 && cmdline->fail) {
+        fprintf(stderr, __FILE__": failed to initialize daemon.\n");
         retval = 1;
-    fprintf(stderr, "main: mainloop exit.\n");
-    
+    } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) {
+        fprintf(stderr, __FILE__": daemon startup without any loaded modules, refusing to work.\n");
+        retval = 1;
+    } else {
+        fprintf(stderr, __FILE__": mainloop entry.\n");
+        if (pa_mainloop_run(mainloop, &retval) < 0)
+            retval = 1;
+        fprintf(stderr, __FILE__": mainloop exit.\n");
+    }
+
+        
     pa_core_free(c);
 
     pa_signal_done();
     pa_mainloop_free(mainloop);
+    
+    pa_cmdline_free(cmdline);
 
-        
-        
     lt_dlexit();
     
     return retval;
index a9e1308..020daa2 100644 (file)
@@ -270,7 +270,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
                 fprintf(stderr, "module-oss-mmap: mmap filed for output. Changing to O_RDONLY mode.\n");
                 mode = O_RDONLY;
             } else {
-                fprintf(stderr, "modeule-oss-mmap: mmap(): %s\n", strerror(errno));
+                fprintf(stderr, "module-oss-mmap: mmap(): %s\n", strerror(errno));
                 goto fail;
             }
         } else {
index 31ca2db..5a6513c 100644 (file)
@@ -195,7 +195,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) {
         assert(u->source);
         u->source->userdata = u;
         pa_source_set_owner(u->source, m);
-        u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p);
+        u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p);
     } else
         u->source = NULL;
 
diff --git a/src/polypaudio.run b/src/polypaudio.run
new file mode 100755 (executable)
index 0000000..f82ad40
--- /dev/null
@@ -0,0 +1,13 @@
+#!./polypaudio -F
+
+# Load the CLI module
+load module-cli
+
+load module-esound-protocol-tcp
+load module-simple-protocol-tcp
+load module-native-protocol-unix
+load module-cli-protocol-unix
+
+load module-oss-mmap device="/dev/dsp"
+
+load module-cli
index 2082002..41c139b 100644 (file)
@@ -5,6 +5,8 @@
 #include <stdarg.h>
 #include <stdio.h>
 
+#include "strbuf.h"
+
 struct chunk {
     struct chunk *next;
     size_t length;
@@ -63,11 +65,17 @@ char *pa_strbuf_tostring_free(struct pa_strbuf *sb) {
 }
 
 void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) {
-    struct chunk *c;
-    size_t l;
     assert(sb && t);
+    pa_strbuf_putsn(sb, t, strlen(t));
+} 
 
-    l = strlen(t);
+void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) {
+    struct chunk *c;
+    assert(sb && t);
+    
+    if (!l)
+       return;
+   
     c = malloc(sizeof(struct chunk)+l);
     assert(c);
 
index ab0c6a7..0e9bb5e 100644 (file)
@@ -10,5 +10,6 @@ char *pa_strbuf_tostring_free(struct pa_strbuf *sb);
 
 int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) __attribute__ ((format (printf, 2, 3)));;
 void pa_strbuf_puts(struct pa_strbuf *sb, const char *t);
+void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t m);
 
 #endif