Any knowledge of how to work with mouse and icons is not required.
+Installing lopsub
+~~~~~~~~~~~~~~~~~
+ git clone git://git.tuebingen.mpg.de/lopsub
+ cd lopsub && make && sudo make install
+ (see http://people.tuebingen.mpg.de/maan/lopsub/)
+
Installing osl
~~~~~~~~~~~~~~
git clone git://git.tuebingen.mpg.de/osl
id3tag_cppflags := @id3tag_cppflags@
openssl_cppflags := @openssl_cppflags@
gcrypt_cppflags := @gcrypt_cppflags@
+lopsub_cppflags := @lopsub_cppflags@
ogg_cppflags := @ogg_cppflags@
mad_cppflags := @mad_cppflags@
faad_cppflags := @faad_cppflags@
faad_ldflags := @faad_ldflags@
mad_ldflags := @mad_ldflags@
flac_ldflags := @flac_ldflags@
+lopsub_ldflags := @lopsub_ldflags@
oss_ldflags := @oss_ldflags@
alsa_ldflags := @alsa_ldflags@
pthread_ldflags := @pthread_ldflags@
cmdlist_dir := $(build_dir)/cmdlist
m4depdir := $(build_dir)/m4deps
help2man_dir := $(build_dir)/help2man
+lls_suite_dir := $(build_dir)/lls
+lls_m4_dir := m4/lls
m4_ggo_dir := m4/gengetopt
test_dir := t
deps := $(addprefix $(dep_dir)/, $(filter-out %.cmdline.d, $(all_objs:.o=.d)))
m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(executables)))
+audiod_objs += audiod_cmd.lsg.o
+
# now prefix all objects with object dir
recv_objs := $(addprefix $(object_dir)/, $(recv_objs))
filter_objs := $(addprefix $(object_dir)/, $(filter_objs))
man: $(man_pages)
tarball: $(tarball)
+include $(lls_m4_dir)/makefile
include $(m4_ggo_dir)/makefile
include $(test_dir)/makefile.test
ifeq ($(findstring clean, $(MAKECMDGOALS)),)
endif
$(object_dir) $(man_dir) $(ggo_dir) $(cmdline_dir) $(dep_dir) $(m4depdir) \
- $(help2man_dir) $(cmdlist_dir):
+ $(help2man_dir) $(cmdlist_dir) $(lls_suite_dir):
$(Q) $(MKDIR_P) $@
# When in doubt, use brute force (Ken Thompson)
CPPFLAGS += -I/usr/local/include
CPPFLAGS += -I$(cmdline_dir)
CPPFLAGS += -I$(cmdlist_dir)
+CPPFLAGS += -I$(lls_suite_dir)
+CPPFLAGS += $(lopsub_cppflags)
CFLAGS += -Os
CFLAGS += -Wuninitialized
server_command_lists := $(cmdlist_dir)/server.command_list.man \
$(cmdlist_dir)/afs.command_list.man
-audiod_command_lists := $(cmdlist_dir)/audiod.command_list.man
+audiod_command_lists := $(lls_suite_dir)/audiod_cmd.lsg.man
play_command_lists := $(cmdlist_dir)/play.command_list.man
$(man_dir)/para_server.1: $(server_command_lists)
$(man_dir)/para_audiod.1: man_util_command_lists := $(audiod_command_lists)
$(man_dir)/para_play.1: man_util_command_lists := $(play_command_lists)
-$(man_dir)/para_%.1: $(ggo_dir)/%.ggo man_util.bash \
- git-version.h | $(man_dir) $(help2man_dir)
+$(man_dir)/para_%.1: $(man_util_command_lists) git-version.h \
+ $(ggo_dir)/%.ggo man_util.bash \
+ | $(man_dir) $(help2man_dir)
@[ -z "$(Q)" ] || echo 'MAN $<'
$(Q) \
COMMAND_LISTS="$(man_util_command_lists)" \
$(Q) $(CC) $(CPPFLAGS) -MM -MG -MP -MT $@ -MT $(object_dir)/$(*F).o $< \
| sed -e "s@ \([a-zA-Z0-9_]\{1,\}\.cmdline.h\)@ $(cmdline_dir)/\1@g" \
-e "s@ \([a-zA-Z0-9_]\{1,\}\.command_list.h\)@ $(cmdlist_dir)/\1@g" \
+ -e "s@ \([a-zA-Z0-9_]\{1,\}.lsg.h\)@ $(lls_suite_dir)/\1@g" \
-e "s@ \([a-zA-Z0-9_]\{1,\}\.completion.h\)@ $(cmdlist_dir)/\1@g" > $@
para_recv para_afh para_play para_server: LDFLAGS += $(id3tag_ldflags)
$(oss_ldflags) \
$(alsa_ldflags)
+para_audioc \
+para_audiod \
+: LDFLAGS += $(lopsub_ldflags)
+
para_server \
para_filter \
para_audiod \
#include <signal.h>
#include "audioc.cmdline.h"
+#include "audiod_cmd.lsg.h"
+
#include "para.h"
#include "error.h"
#include "net.h"
#include "sched.h"
#include "buffer_tree.h"
#include "interactive.h"
-#include "audiod.completion.h"
static struct sched sched;
static void version_completer(struct i9e_completion_info *ci,
struct i9e_completion_result *cr)
{
- char *opts[] = {"-v", NULL};
+ char *opts[] = {LSG_AUDIOD_CMD_VERSION_OPTS, NULL};
if (ci->word_num <= 2 && ci->word && ci->word[0] == '-')
i9e_complete_option(opts, ci, cr);
struct i9e_completion_result *cr)
{
char *sia[] = {STATUS_ITEM_ARRAY NULL};
- char *opts[] = {"-p", NULL};
+ char *opts[] = {LSG_AUDIOD_CMD_STAT_OPTS, NULL};
if (ci->word_num <= 2 && ci->word && ci->word[0] == '-')
i9e_complete_option(opts, ci, cr);
static void grab_completer(struct i9e_completion_info *ci,
struct i9e_completion_result *cr)
{
- char *opts[] = {"-ms", "-ms", "-ma", "-p=", "-n=", "-o", NULL};
+ char *opts[] = {LSG_AUDIOD_CMD_GRAB_OPTS, NULL};
i9e_complete_option(opts, ci, cr);
}
+I9E_DUMMY_COMPLETER(SUPERCOMMAND_UNAVAILABLE);
static struct i9e_completer audiod_completers[] = {
- AUDIOD_COMPLETERS
+#define LSG_AUDIOD_CMD_CMD(_name) {.name = #_name, \
+ .completer = _name ## _completer}
+ LSG_AUDIOD_CMD_SUBCOMMANDS
+#undef LSG_AUDIOD_CMD_CMD
{.name = NULL}
};
#include <netdb.h>
#include <signal.h>
#include <pwd.h>
+#include <lopsub.h>
#include "para.h"
#include "error.h"
SF: audiod_command.c
SN: list of audiod commands
---
-N: cycle
-D: switch to next mode
-U: cycle
-H: on -> standby -> off -> on
----
-N: grab
-D: grab the audio stream
-L:
-U: -- grab [-m[{s|p|a}]] [-p=PARENT] [-n=NAME] [-o]
-H:
-H: grab ('splice') the audio stream at any position in the buffer
-H: tree and send that data back to the client.
-H:
-H: Options:
-H:
-H: -m Change grab mode. Defaults to sloppy grab if not given.
-H:
-H: -ms: sloppy grab
-H: -mp: pedantic grab
-H: -ma: aggressive grab
-H:
-H: The various grab modes only differ in what happens if an attempt to
-H: write the grabbed audio data would block. Sloppy mode ignores the
-H: write, pedantic mode aborts and aggressive mode tries to write anyway.
-H:
-H: -p Grab output of node PARENT of the buffer tree.
-H:
-H: -n Name of the new buffer tree node. Defaults to 'grab'.
-H:
-H: -o One-shot mode: Stop grabbing if audio file changes.
----
-N: help
-D: display command list or help for given command
-U: help [command]
-H: When I was younger, so much younger than today, I never needed anybody's help
-H: in any way. But now these days are gone, I'm not so self assured. Now I find
-H: I've changed my mind and opened up the doors.
-H: -- Beatles: Help
----
-N: off
-D: deactivate para_audiod
-U: off
-H: Close connection to para_server and stop all decoders.
----
-N: on
-D: activate para_audiod
-U: on
-H: Establish connection to para_server, retrieve para_server's current status. If
-H: playing, start corresponding decoder. Otherwise stop all decoders.
----
-N: sb
-D: enter standby mode
-U: sb
-H: Stop all decoders but leave connection to para_server open.
----
-N: stat
-D: print status information
-U: stat [-p] [item1 ...]
-H: Dump given status items (all if none given) to stdout. If -p is given, use
-H: parser-friendly mode.
----
-N: tasks
-D: list current tasks
-U: tasks
-H: Print the list of task ids together with the status of each task.
----
-N: term
-D: terminate audiod
-U: term
-H: Stop all decoders, shut down connection to para_server and exit.
----
-N: version
-D: print the version of para_audiod
-U: version [-v]
-H: If the -v option is given, a more detailed version text is printed.
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
+#include <lopsub.h>
#include "para.h"
+#include "audiod_cmd.lsg.h"
#include "audiod.cmdline.h"
-#include "audiod.command_list.h"
#include "list.h"
#include "sched.h"
#include "ggo.h"
extern struct sched sched;
extern char *stat_item_values[NUM_STAT_ITEMS];
-typedef int audiod_command_handler_t(int, int, char **);
-static audiod_command_handler_t AUDIOD_COMMAND_HANDLERS;
-
-/* Defines one command of para_audiod. */
-struct audiod_command {
- const char *name;
- /* Pointer to the function that handles the command. */
- /*
- * Command handlers must never never close their file descriptor. A
- * positive return value tells audiod that the status items have
- * changed. In this case audiod will send an updated version of all
- * status items to to each connected stat client.
- */
- audiod_command_handler_t *handler;
- /* One-line description. */
- const char *description;
- /* Summary of the command line options. */
- const char *usage;
- /* The long help text. */
- const char *help;
-};
+/** The maximal number of simultaneous connections. */
+#define MAX_STAT_CLIENTS 50
-static struct audiod_command audiod_cmds[] = {DEFINE_AUDIOD_CMD_ARRAY};
+/** Pointer to a command handler function. */
+typedef int (*audiod_cmd_handler_t)(int, struct lls_parse_result *);
-/** Iterate over the array of all audiod commands. */
-#define FOR_EACH_COMMAND(c) for (c = 0; audiod_cmds[c].name; c++)
+/** The lopsub user_data pointer. Only the command handler at the moment. */
+struct audiod_command_info {
+ audiod_cmd_handler_t handler; /**< Implementation of the command. */
+};
-/** The maximal number of simultaneous connections. */
-#define MAX_STAT_CLIENTS 50
+/** Define the user_data pointer as expected by lopsub. */
+#define EXPORT_AUDIOD_CMD_HANDLER(_cmd) \
+ /** Implementation of _cmd. */ \
+ const struct audiod_command_info lsg_audiod_cmd_com_ ## _cmd ## _user_data = { \
+ .handler = com_ ## _cmd \
+ };
/** Flags used for the stat command of para_audiod. */
enum stat_client_flags {
char *buf = para_strdup(""), *tmp = NULL;
int i;
ssize_t ret;
+ const struct lls_command *cmd;
- FOR_EACH_COMMAND(i) {
- tmp = make_message("%s%s\t%s\n", buf, audiod_cmds[i].name,
- audiod_cmds[i].description);
+ for (i = 1; (cmd = lls_cmd(i, audiod_cmd_suite)); i++) {
+ tmp = make_message("%s%s\t%s\n", buf, lls_command_name(cmd),
+ lls_purpose(cmd));
free(buf);
buf = tmp;
}
return ret;
}
-static int com_help(int fd, int argc, char **argv)
+static int com_help(int fd, struct lls_parse_result *lpr)
{
- int i, ret;
- char *buf;
-
- if (argc < 2) {
- ret = dump_commands(fd);
- goto out;
+ int ret;
+ char *buf, *errctx;
+ const struct lls_command *cmd;
+
+ ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx));
+ if (ret < 0) {
+ if (errctx) {
+ buf = make_message("%s\n", errctx);
+ client_write(fd, buf);
+ free(buf);
+ free(errctx);
+ }
+ return ret;
}
- FOR_EACH_COMMAND(i) {
- if (strcmp(audiod_cmds[i].name, argv[1]))
- continue;
- buf = make_message(
- "NAME\n\t%s -- %s\n"
- "SYNOPSIS\n\tpara_audioc %s\n"
- "DESCRIPTION\n%s\n",
- argv[1],
- audiod_cmds[i].description,
- audiod_cmds[i].usage,
- audiod_cmds[i].help
- );
- ret = client_write(fd, buf);
+ if (lls_num_inputs(lpr) == 0)
+ return dump_commands(fd);
+ ret = lls(lls_lookup_subcmd(lls_input(0, lpr), audiod_cmd_suite,
+ &errctx));
+ if (ret < 0) {
+ buf = make_message("%s: %s\nAvailable commands:\n", errctx?
+ errctx : lls_input(0, lpr), para_strerror(-ret));
+ if (client_write(fd, buf) >= 0)
+ dump_commands(fd);
+ free(errctx);
free(buf);
goto out;
}
- ret = client_write(fd, "No such command. Available commands:\n");
- if (ret > 0)
- ret = dump_commands(fd);
+ cmd = lls_cmd(ret, audiod_cmd_suite);
+ buf = lls_long_help(cmd);
+ assert(buf);
+ ret = client_write(fd, buf);
+ free(buf);
out:
return ret < 0? ret : 0;
}
+EXPORT_AUDIOD_CMD_HANDLER(help)
-static int com_tasks(int fd, __a_unused int argc, __a_unused char **argv)
+static int com_tasks(int fd, __a_unused struct lls_parse_result *lpr)
{
+ int ret;
char *tl = get_task_list(&sched);
- int ret = 1;
- if (tl)
- ret = client_write(fd, tl);
+ if (!tl) /* no tasks registered yet */
+ return 0;
+ ret = client_write(fd, tl);
free(tl);
- return ret < 0? ret : 0;
+ return ret;
}
+EXPORT_AUDIOD_CMD_HANDLER(tasks)
-static int com_stat(int fd, int argc, char **argv)
+static int com_stat(int fd, struct lls_parse_result *lpr)
{
int i, ret, parser_friendly = 0;
uint64_t mask = 0;
const uint64_t one = 1;
struct para_buffer b = {.flags = 0};
+ const struct lls_opt_result *r;
+ unsigned num_inputs;
ret = mark_fd_nonblocking(fd);
if (ret < 0)
return ret;
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
- if (arg[0] != '-')
- break;
- if (!strcmp(arg, "--")) {
- i++;
- break;
- }
- if (!strncmp(arg, "-p", 2)) {
- parser_friendly = 1;
- b.flags = PBF_SIZE_PREFIX;
- }
+ r = lls_opt_result(LSG_AUDIOD_CMD_STAT_OPT_PARSER_FRIENDLY, lpr);
+ if (lls_opt_given(r) > 0) {
+ parser_friendly = 1;
+ b.flags = PBF_SIZE_PREFIX;
}
- if (i >= argc)
+ num_inputs = lls_num_inputs(lpr);
+ if (num_inputs == 0)
mask--; /* set all bits */
- for (; i < argc; i++) {
- ret = stat_item_valid(argv[i]);
+ for (i = 0; i < num_inputs; i++) {
+ ret = stat_item_valid(lls_input(i, lpr));
if (ret < 0)
return ret;
mask |= (one << ret);
free(b.buf);
return ret < 0? ret : 0;
}
+EXPORT_AUDIOD_CMD_HANDLER(stat)
-static int com_grab(int fd, int argc, char **argv)
+static int com_grab(int fd, struct lls_parse_result *lpr)
{
- int ret = grab_client_new(fd, argc, argv, &sched);
+ int ret = grab_client_new(fd, lpr, &sched);
return ret < 0? ret : 0;
}
+EXPORT_AUDIOD_CMD_HANDLER(grab)
-static int com_term(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
+static int com_term(__a_unused int fd, __a_unused struct lls_parse_result *lpr)
{
return -E_AUDIOD_TERM;
}
+EXPORT_AUDIOD_CMD_HANDLER(term)
-static int com_on(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
+static int com_on(__a_unused int fd, __a_unused struct lls_parse_result *lpr)
{
audiod_status = AUDIOD_ON;
return 1;
}
+EXPORT_AUDIOD_CMD_HANDLER(on)
-static int com_off(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
+static int com_off(__a_unused int fd, __a_unused struct lls_parse_result *lpr)
{
audiod_status = AUDIOD_OFF;
return 1;
}
+EXPORT_AUDIOD_CMD_HANDLER(off)
-static int com_sb(__a_unused int fd, __a_unused int argc, __a_unused char **argv)
+static int com_sb(__a_unused int fd, __a_unused struct lls_parse_result *lpr)
{
audiod_status = AUDIOD_STANDBY;
return 1;
}
+EXPORT_AUDIOD_CMD_HANDLER(sb)
-static int com_cycle(__a_unused int fd, int argc, char **argv)
+static int com_cycle(__a_unused int fd, __a_unused struct lls_parse_result *lpr)
{
switch (audiod_status) {
- case AUDIOD_ON:
- return com_sb(fd, argc, argv);
- break;
- case AUDIOD_OFF:
- return com_on(fd, argc, argv);
- break;
- case AUDIOD_STANDBY:
- return com_off(fd, argc, argv);
- break;
+ case AUDIOD_ON: audiod_status = AUDIOD_STANDBY; break;
+ case AUDIOD_OFF: audiod_status = AUDIOD_ON; break;
+ case AUDIOD_STANDBY: audiod_status = AUDIOD_OFF; break;
}
return 1;
}
+EXPORT_AUDIOD_CMD_HANDLER(cycle)
-static int com_version(int fd, int argc, char **argv)
+static int com_version(int fd, struct lls_parse_result *lpr)
{
int ret;
char *msg;
+ const struct lls_opt_result *r_v;
- if (argc > 1 && strcmp(argv[1], "-v") == 0)
+ r_v = lls_opt_result(LSG_AUDIOD_CMD_VERSION_OPT_VERBOSE, lpr);
+ if (lls_opt_given(r_v))
msg = make_message("%s", version_text("audiod"));
else
msg = make_message("%s\n", version_single_line("audiod"));
free(msg);
return ret < 0? ret : 0;
}
+EXPORT_AUDIOD_CMD_HANDLER(version)
/**
* Handle arriving connections on the local socket.
* */
int handle_connect(int accept_fd, fd_set *rfds)
{
- int i, argc, ret, clifd;
+ int argc, ret, clifd;
char buf[MAXLINE], **argv = NULL;
struct sockaddr_un unix_addr;
uid_t uid;
+ const struct lls_command *cmd;
+ struct lls_parse_result *lpr;
+ char *errctx;
+ const struct audiod_command_info *aci;
ret = para_accept(accept_fd, rfds, &unix_addr, sizeof(struct sockaddr_un), &clifd);
if (ret <= 0)
if (ret <= 0)
goto out;
argc = ret;
- //PARA_INFO_LOG("argv[0]: %s, argc = %d\n", argv[0], argc);
- FOR_EACH_COMMAND(i) {
- if (strcmp(audiod_cmds[i].name, argv[0]))
- continue;
- ret = audiod_cmds[i].handler(clifd, argc, argv);
+ ret = lls(lls_lookup_subcmd(argv[0], audiod_cmd_suite, &errctx));
+ if (ret < 0)
goto out;
- }
- ret = -E_INVALID_AUDIOD_CMD;
+ cmd = lls_cmd(ret, audiod_cmd_suite);
+ ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
+ if (ret < 0)
+ goto out;
+ aci = lls_user_data(cmd);
+ ret = aci->handler(clifd, lpr);
+ lls_free_parse_result(lpr, cmd);
out:
free_argv(argv);
if (ret < 0 && ret != -E_CLIENT_WRITE) {
- char *tmp = make_message("%s\n", para_strerror(-ret));
+ char *tmp;
+ if (errctx) {
+ tmp = make_message("%s\n", errctx);
+ free(errctx);
+ client_write(clifd, tmp);
+ free(tmp);
+ }
+ tmp = make_message("%s\n", para_strerror(-ret));
client_write(clifd, tmp);
free(tmp);
}
test -z "$INSTALL" && AC_MSG_ERROR(
[The install program is required to build this package])
+AC_PATH_PROG([lopsubgen], [lopsubgen])
+test -z "$lopsubgen" && AC_MSG_ERROR(
+ [lopsubgen is required to build this package])
+
AC_PROG_CC
AC_PROG_CPP
AC_CHECK_LIB([osl], [osl_open_table], [], [HAVE_OSL=no])
LIB_SUBST_FLAGS(osl)
UNSTASH_FLAGS
+######################################################################## lopsub
+STASH_FLAGS
+LIB_ARG_WITH([lopsub], [-llopsub])
+HAVE_LOPSUB=yes
+AC_CHECK_HEADER(lopsub.h, [], [HAVE_LOPSUB=no])
+AC_CHECK_LIB([lopsub], [lls_merge], [], [HAVE_LOPSUB=yes])
+if test $HAVE_LOPSUB = no; then AC_MSG_ERROR([
+ The lopsub library is required to build this software, but
+ the above checks indicate it is not installed on your system.
+ Run the following command to download a copy.
+ git clone git://git.tuebingen.mpg.de/lopsub.git
+ Install the library, then run this configure script again.
+])
+fi
+LIB_SUBST_FLAGS([lopsub])
+UNSTASH_FLAGS
######################################################################## openssl
STASH_FLAGS
HAVE_OPENSSL=yes
PARA_ERROR(ID3_SETENCODING, "could not set id3 text encoding field"), \
PARA_ERROR(ID3_SETSTRING, "could not set id3 string field"), \
PARA_ERROR(INCOHERENT_BLOCK_LEN, "incoherent block length"), \
- PARA_ERROR(INVALID_AUDIOD_CMD, "invalid command"), \
PARA_ERROR(KEY_MARKER, "invalid/missing key header or footer"), \
PARA_ERROR(KEY_PERM, "unprotected private key"), \
PARA_ERROR(LIBSAMPLERATE, "secret rabbit code error"), \
*/
#define OSL_ERROR_BIT 29
+#define LLS_ERROR_BIT 28
+
/** Check whether the system error bit is set. */
#define IS_SYSTEM_ERROR(num) (!!((num) & (1 << SYSTEM_ERROR_BIT)))
/** Check whether the osl error bit is set. */
#define IS_OSL_ERROR(num) (!!((num) & (1 << OSL_ERROR_BIT)))
+/** Check whether the lopsub error bit is set. */
+#define IS_LLS_ERROR(num) (!!((num) & (1 << LLS_ERROR_BIT)))
+
/** Set the system error bit for the given number. */
#define ERRNO_TO_PARA_ERROR(num) ((num) | (1 << SYSTEM_ERROR_BIT))
/** Set the osl error bit for the given number. */
#define OSL_ERRNO_TO_PARA_ERROR(num) ((num) | (1 << OSL_ERROR_BIT))
+/** Set the lopsub error bit for the error code. */
+#define LLS_ERRNO_TO_PARA_ERROR(num) ((num) | (1 << LLS_ERROR_BIT))
+
static const char *weak_osl_strerror(int) __attribute__ ((weakref("osl_strerror")));
+static const char *weak_lls_strerror(int) __attribute__ ((weakref("lls_strerror")));
/**
* Paraslash's version of strerror(3).
*
assert(weak_osl_strerror);
return weak_osl_strerror(num & ~(1U << OSL_ERROR_BIT));
}
+ if (IS_LLS_ERROR(num)) {
+ assert(weak_lls_strerror);
+ return weak_lls_strerror(num & ~(1U << LLS_ERROR_BIT));
+ }
if (IS_SYSTEM_ERROR(num))
return strerror(num & ~(1U << SYSTEM_ERROR_BIT));
return para_errlist[num];
return ret;
return -OSL_ERRNO_TO_PARA_ERROR(-ret);
}
+
+/**
+ * Wrapper for lopsub library calls.
+ *
+ * \param ret See osl().
+ * \return See osl().
+ */
+_static_inline_ int lls(int ret)
+{
+ if (ret >= 0)
+ return ret;
+ return -LLS_ERRNO_TO_PARA_ERROR(-ret);
+}
#include <regex.h>
#include <sys/types.h>
+#include <inttypes.h>
+#include <lopsub.h>
+
+#include "audiod_cmd.lsg.h"
#include "para.h"
#include "list.h"
#include "sched.h"
-#include "ggo.h"
#include "buffer_tree.h"
#include "grab_client.h"
#include "audiod.h"
return ret;
}
-static int gc_check_args(int argc, char **argv, struct grab_client *gc)
+static int gc_check_args(struct lls_parse_result *lpr, struct grab_client *gc)
{
- int i;
+ const struct lls_opt_result *r;
- for (i = 1; i < argc; i++) {
- const char *arg = argv[i];
- if (arg[0] != '-')
- break;
- if (!strcmp(arg, "--")) {
- i++;
- break;
- }
- if (!strncmp(arg, "-m", 2)) {
- if (*(arg + 3))
- return -E_GC_SYNTAX;
- switch(*(arg + 2)) {
- case 's':
- gc->mode = GM_SLOPPY;
- continue;
- case 'a':
- gc->mode = GM_AGGRESSIVE;
- continue;
- case 'p':
- gc->mode = GM_PEDANTIC;
- continue;
- default:
- return -E_GC_SYNTAX;
- }
- }
- if (!strcmp(arg, "-o")) {
- gc->flags |= GF_ONE_SHOT;
- continue;
- }
- if (!strncmp(arg, "-p=", 3)) {
- gc->parent = para_strdup(arg + 3);
- continue;
- }
- if (!strncmp(arg, "-n=", 3)) {
- gc->name = para_strdup(arg + 3);
- continue;
- }
- return -E_GC_SYNTAX;
+ r = lls_opt_result(LSG_AUDIOD_CMD_GRAB_OPT_MODE, lpr);
+ if (lls_opt_given(r) > 0) {
+ const char *arg = lls_string_val(0, r);
+ if (strcmp(arg, "s") == 0)
+ gc->mode = GM_SLOPPY;
+ else if (strcmp(arg, "a") == 0)
+ gc->mode = GM_AGGRESSIVE;
+ else if (strcmp(arg, "p") == 0)
+ gc->mode = GM_PEDANTIC;
+ else
+ return -E_GC_SYNTAX;
+ }
+
+ r = lls_opt_result(LSG_AUDIOD_CMD_GRAB_OPT_ONE_SHOT, lpr);
+ if (lls_opt_given(r) > 0)
+ gc->flags |= GF_ONE_SHOT;
+
+ r = lls_opt_result(LSG_AUDIOD_CMD_GRAB_OPT_PARENT, lpr);
+ if (lls_opt_given(r) > 0) {
+ const char *arg = lls_string_val(0, r);
+ gc->parent = para_strdup(arg);
+ }
+
+ r = lls_opt_result(LSG_AUDIOD_CMD_GRAB_OPT_NAME, lpr);
+ if (lls_opt_given(r) > 0) {
+ const char *arg = lls_string_val(0, r);
+ gc->name = para_strdup(arg);
}
- if (i != argc)
- return -E_GC_SYNTAX;
return 1;
}
/**
- * Check the command line options and allocate a grab_client structure.
+ * Create and activate a grab client.
*
* \param fd The file descriptor of the client.
- * \param argc Argument count.
- * \param argv Argument vector.
+ * \param lpr The parsed command line of the grab command.
* \param s The scheduler to register the grab client task to.
*
- * If the command line options given by \a argc and \a argv are valid.
- * allocate a struct grab_client and initialize it with this valid
- * configuration.
- *
- * If the new grab client can be added to an existing buffer tree, activate it.
- * Otherwise, add it to the inactive list for later activation.
+ * This function semantically parses the arguments given as options to the grab
+ * command. On success it allocates a struct grab_client, associates it with
+ * the given file descriptor and activates it. If the new grab client can not
+ * be attached to an existing buffer tree node it is put into the inactive list
+ * for later activation.
*
* \return Standard.
*/
-int grab_client_new(int fd, int argc, char **argv, struct sched *s)
+int grab_client_new(int fd, struct lls_parse_result *lpr, struct sched *s)
{
int ret;
struct grab_client *gc = para_calloc(sizeof(struct grab_client));
- ret = gc_check_args(argc, argv, gc);
+ ret = gc_check_args(lpr, gc);
if (ret < 0)
goto err_out;
ret = dup(fd);
/** \file grab_client.h exported symbols from grab_client.c */
-int grab_client_new(int fd, int argc, char **argv, struct sched *s);
+int grab_client_new(int fd, struct lls_parse_result *lpr, struct sched *s);
void activate_grab_clients(struct sched *s);
--- /dev/null
+[suite audiod_cmd]
+caption = list of audiod commands
+[subcommand cycle]
+ purpose = switch to next operating mode
+ [description]
+ Cycle through the three operation modes (on, standby, off).
+ [/description]
+
+[subcommand help]
+ purpose = display command list or help for given command
+ non-opts-name = [subcommand]
+ [description]
+ When I was younger, so much younger than today, I never needed
+ anybody's help in any way. But now these days are gone, I'm not so self
+ assured. Now I find I've changed my mind and opened up the doors. --
+ Beatles: Help
+ [/description]
+
+[subcommand grab]
+ purpose = grab the audio stream
+ [description]
+ grab ('splice') the audio stream at any position in the buffer tree
+ and send that data back to the client.
+ [/description]
+ [option mode]
+ short_opt = m
+ summary = change grab mode
+ arg_info = required_arg
+ arg_type = string
+ typestr = mode
+ default_val = s
+ [help]
+ The various grab modes only differ in what happens if an attempt to
+ write the grabbed audio data would block. Sloppy mode ("s") ignores
+ the write, pedantic mode ("p") aborts and aggressive mode ("a")
+ tries to write anyway.
+ [/help]
+ [option parent]
+ short_opt = p
+ summary = Grab output of the given node of the buffer tree
+ arg_info = required_arg
+ arg_type = string
+ typestr = node
+ [option name]
+ short_opt = n
+ summary = Name of the new buffer tree node. Defaults to 'grab'
+ arg_info = optional_arg
+ arg_type = string
+ typestr = string
+ [option one-shot]
+ short_opt = o
+ summary = One-shot mode: Stop grabbing if audio file changes
+
+[subcommand off]
+ purpose = deactivate para_audiod
+ [description]
+ Close connection to para_server and stop all decoders.
+ [/description]
+
+[subcommand on]
+ purpose = activate para_audiod
+ [description]
+ Establish connection to para_server, retrieve para_server's current
+ status. If playing, start corresponding decoder. Otherwise stop
+ all decoders.
+ [/description]
+
+[subcommand sb]
+ purpose = enter standby mode
+ [description]
+ Stop all decoders but leave connection to para_server open.
+ [/description]
+
+[subcommand stat]
+ purpose = print status information
+ non-opts-name = [item...]
+ [description]
+ Dump given status items (all if none given) to stdout.
+ [/description]
+ [option parser-friendly]
+ short_opt = p
+ summary = use parser-friendly output format
+
+[subcommand version]
+ purpose = print the version of para_audiod
+ [option verbose]
+ short_opt = v
+ summary = print detailed (multi-line) version text
+
+[subcommand tasks]
+ purpose = list current tasks
+ [description]
+ Print the list of task ids together with the status of each task.
+ [/description]
+
+[subcommand term]
+ purpose = terminate para_audiod
+ [description]
+ Stop all decoders, shut down connection to para_server and exit.
+ [/description]
--- /dev/null
+.PRECIOUS: $(lls_suite_dir)/%.suite
+
+$(lls_suite_dir)/%.suite: $(lls_m4_dir)/%.suite.m4 | $(lls_suite_dir)
+ @[ -z "$(Q)" ] || echo 'M4 $<'
+ $(Q) $(M4) -Pg $< > $@
+
+$(lls_suite_dir)/%.lsg.c: $(lls_suite_dir)/%.suite
+ @[ -z "$(Q)" ] || echo 'LSGC $<'
+ $(Q) lopsubgen --gen-c --output-dir $(lls_suite_dir) < $<
+
+$(lls_suite_dir)/%.lsg.h: $(lls_suite_dir)/%.suite
+ @[ -z "$(Q)" ] || echo 'LSGH $<'
+ $(Q) lopsubgen --gen-header --output-dir $(lls_suite_dir) < $<
+
+$(lls_suite_dir)/%.lsg.man: $(lls_suite_dir)/%.suite
+ @[ -z "$(Q)" ] || echo 'LSGM $<'
+ $(Q) lopsubgen --gen-man --output-dir $(lls_suite_dir) < $<
+
+$(object_dir)/%.o: $(lls_suite_dir)/%.c | $(object_dir)
+ @[ -z "$(Q)" ] || echo 'CC $<'
+ $(Q) $(CC) -c -o $@ $(CPPFLAGS) $(STRICT_CFLAGS) $<
link="$HELP2MAN_DIR/para_$target"
cl_opts=
+tempfiles=
for cl in $COMMAND_LISTS; do
- cl_opts+=" --include $cl"
+ if [[ "$cl" =~ lsg ]]; then
+ tempfiles+=" $cl.man_util.$$"
+ sed -e '/^\.SH / s/$/]/1' -e '/^\.SH / s/^\.SH /[/1' "$cl" > "$cl.man_util.$$"
+ cl_opts+=" --include $cl.man_util.$$"
+ else
+ cl_opts+=" --include $cl"
+ fi
done
# Create a symlink para_$target, pointing to this script. This hack is
# This will call us again twice, with either --help-$target or --version given.
$HELP2MAN --no-info --help-option "--help-$target" $cl_opts \
"$link" > "$output_file"
-if (($? != 0)); then
+ret=$?
+rm -f $tempfiles
+if (($ret != 0)); then
rm -f "$output_file"
exit 1
fi
git clone git://git.tuebingen.mpg.de/osl
+- [lopsub](http://people.tuebingen.mpg.de/maan/lopsub/). The long
+option parser for subcommands generates the command line and config
+file parsers for all paraslash executables. Clone the source code
+repository with
+
+ git clone git://git.tuebingen.mpg.de/lopsub
+
- [gcc](ftp://ftp.gnu.org/pub/gnu/gcc) or
[clang](http://clang.llvm.org). All gcc versions >= 4.2 are currently
supported. Clang version 1.1 or newer should work as well.