CC := cc
endif
+LOGLEVELS := LL_DEBUG,LL_INFO,LL_NOTICE,LL_WARNING,LL_ERROR,LL_CRIT,LL_EMERG
vardir := /var/paraslash
mandir := $(datarootdir)/man/man1
STRIP := $(CROSS_COMPILE)strip
$(audiod_objs) $(audioc_objs) $(fade_objs) $(server_objs) \
$(write_objs) $(afh_objs) $(play_objs))
deps := $(addprefix $(dep_dir)/, $(filter-out %.cmdline.d, $(all_objs:.o=.d)))
-m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(executables)))
+converted_executables := audioc
+unconverted_executables := $(filter-out $(converted_executables), $(executables))
+audioc_objs += audioc.lsg.o
audiod_objs += audiod_cmd.lsg.o
server_objs += server_cmd.lsg.o
play_objs += play_cmd.lsg.o
+m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
+m4_lls_deps := audiod_cmd server_cmd play_cmd $(converted_executables)
+m4_lls_deps := $(addprefix $(lls_suite_dir)/, $(addsuffix .m4d, $(m4_lls_deps)))
+
# now prefix all objects with object dir
recv_objs := $(addprefix $(object_dir)/, $(recv_objs))
filter_objs := $(addprefix $(object_dir)/, $(filter_objs))
ifeq ($(findstring clean, $(MAKECMDGOALS)),)
-include $(deps)
-include $(m4_deps)
+-include $(m4_lls_deps)
endif
$(object_dir) $(man_dir) $(ggo_dir) $(cmdline_dir) $(dep_dir) $(m4depdir) \
CPPFLAGS += -DBINDIR='"$(bindir)"'
CPPFLAGS += -DCOPYRIGHT_YEAR='"$(COPYRIGHT_YEAR)"'
CPPFLAGS += -DBUILD_DATE='"$(build_date)"'
+CPPFLAGS += -DLOGLEVELS='$(LOGLEVELS)'
CPPFLAGS += -DUNAME_RS='"$(uname_rs)"'
CPPFLAGS += -DCC_VERSION='"$(cc_version)"'
CPPFLAGS += -I/usr/local/include
$(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: $(man_util_command_lists) git-version.h \
+$(man_dir)/para_%.1: $(lls_suite_dir)/%.lsg.man $(man_util_command_lists) \
+ $(lls_m4_dir)/copyright.m4 | $(man_dir)
+ @[ -z "$(Q)" ] || echo 'LLSMAN $<'
+ $(Q) cat $< $(man_util_command_lists) > $@
+ $(Q) $(M4) -D COPYRIGHT_YEAR=$(COPYRIGHT_YEAR) $(lls_m4_dir)/copyright.m4 >> $@
+
+$(man_dir)/para_%.1: $(man_util_command_lists) \
$(ggo_dir)/%.ggo man_util.bash \
| $(man_dir) $(help2man_dir)
@[ -z "$(Q)" ] || echo 'MAN $<'
#include <sys/un.h>
#include <netdb.h>
#include <signal.h>
+#include <lopsub.h>
-#include "audioc.cmdline.h"
#include "audiod_cmd.lsg.h"
+#include "audioc.lsg.h"
#include "para.h"
#include "error.h"
#include "net.h"
#include "string.h"
#include "fd.h"
-#include "ggo.h"
#include "version.h"
/** Array of error strings. */
DEFINE_PARA_ERRLIST;
-/** The gengetopt structure containing command line args. */
-static struct audioc_args_info conf;
static char *socket_name;
+static struct lls_parse_result *lpr;
+#define CMD_PTR (lls_cmd(0, audioc_suite))
+#define OPT_RESULT(_name) \
+ (lls_opt_result(LSG_AUDIOC_PARA_AUDIOC_OPT_ ## _name, lpr))
+#define OPT_GIVEN(_name) (lls_opt_given(OPT_RESULT(_name)))
+#define OPT_STRING_VAL(_name) (lls_string_val(0, OPT_RESULT(_name)))
+#define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
static int loglevel;
INIT_STDERR_LOGGING(loglevel);
char *buf = NULL;
for (i = 0; i < argc; i++) {
- buf = para_strcat(buf, argv[i]);
+ const char *arg = argv? argv[i] : lls_input(i, lpr);
+ buf = para_strcat(buf, arg);
if (i != argc - 1)
buf = para_strcat(buf, "\n");
}
char *buf = NULL;
struct audioc_task *at = context;
int ret = btr_node_status(at->btrn, 0, BTR_NT_ROOT);
+ size_t bufsize;
if (ret < 0)
goto out;
if (!FD_ISSET(at->fd, &s->rfds))
return 0;
- buf = para_malloc(conf.bufsize_arg);
- ret = recv_bin_buffer(at->fd, buf, conf.bufsize_arg);
+ bufsize = PARA_MAX(1024U, OPT_UINT32_VAL(BUFSIZE));
+ buf = para_malloc(bufsize);
+ ret = recv_bin_buffer(at->fd, buf, bufsize);
PARA_DEBUG_LOG("recv: %d\n", ret);
if (ret == 0)
ret = -E_AUDIOC_EOF;
static int audioc_i9e_line_handler(char *line)
{
- char *args = NULL;
- int ret;
+ int argc, ret;
+ char *args, **argv;
PARA_DEBUG_LOG("line: %s\n", line);
- ret = create_argv(line, " ", &conf.inputs);
+ ret = create_argv(line, " ", &argv);
if (ret < 0)
return ret;
- conf.inputs_num = ret;
- args = concat_args(conf.inputs_num, conf.inputs);
- free_argv(conf.inputs);
+ argc = ret;
+ args = concat_args(argc, argv);
+ free_argv(argv);
if (!args)
return 0;
- conf.inputs_num = 0; /* required for audioc_cmdline_parser_free() */
ret = connect_audiod(socket_name, args);
+ free(args);
if (ret < 0)
goto out;
at->fd = ret;
ret = mark_fd_nonblocking(at->fd);
if (ret < 0)
goto close;
- free(args);
- args = NULL;
at->btrn = btr_new_node(&(struct btr_node_description)
EMBRACE(.name = "audioc line handler"));
at->task = task_register(&(struct task_info) {
.loglevel = loglevel,
.completers = audiod_completers,
};
+
PARA_NOTICE_LOG("\n%s\n", version_text("audioc"));
- if (conf.history_file_given)
- history_file = para_strdup(conf.history_file_arg);
+ if (OPT_GIVEN(HISTORY_FILE))
+ history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
else {
char *home = para_homedir();
history_file = make_message("%s/.paraslash/audioc.history",
para_log = stderr_log;
out:
free(history_file);
- audioc_cmdline_parser_free(&conf);
+ free(socket_name);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
return NULL;
}
-__noreturn static void print_help_and_die(void)
+static void handle_help_flag(void)
{
- struct ggo_help h = DEFINE_GGO_HELP(audioc);
- bool d = conf.detailed_help_given;
+ char *help;
- ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
- exit(0);
+ if (OPT_GIVEN(DETAILED_HELP))
+ help = lls_long_help(CMD_PTR);
+ else if (OPT_GIVEN(HELP))
+ help = lls_short_help(CMD_PTR);
+ else
+ return;
+ printf("%s\n", help);
+ free(help);
+ exit(EXIT_SUCCESS);
}
/**
*/
int main(int argc, char *argv[])
{
+ const struct lls_command *cmd = CMD_PTR;
int ret, fd;
- char *cf, *buf = NULL, *args = NULL;
+ char *cf = NULL, *buf, *args, *errctx = NULL;
size_t bufsize;
+ struct lls_parse_result *lpr1, *lpr2, *lpr3;
+ unsigned num_inputs;
- audioc_cmdline_parser(argc, argv, &conf);
- loglevel = get_loglevel_by_name(conf.loglevel_arg);
- version_handle_flag("audioc", conf.version_given);
- if (conf.help_given || conf.detailed_help_given)
- print_help_and_die();
+ ret = lls(lls_parse(argc, argv, cmd, &lpr1, &errctx));
+ if (ret < 0)
+ goto fail;
+ lpr = lpr1;
+ loglevel = OPT_UINT32_VAL(LOGLEVEL);
+ version_handle_flag("audioc", OPT_GIVEN(VERSION));
+ handle_help_flag();
cf = configfile_exists();
if (cf) {
- struct audioc_cmdline_parser_params params = {
- .override = 0,
- .initialize = 0,
- .check_required = 0,
- .check_ambiguity = 0,
- .print_errors = 1,
-
- };
- audioc_cmdline_parser_config_file(cf, &conf, ¶ms);
- free(cf);
- loglevel = get_loglevel_by_name(conf.loglevel_arg);
+ void *map;
+ size_t sz;
+ int cf_argc;
+ char **cf_argv;
+ ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
+ if (ret != -E_EMPTY) {
+ if (ret < 0)
+ goto out;
+ ret = lls(lls_convert_config(map, sz, NULL, &cf_argv,
+ &errctx));
+ para_munmap(map, sz);
+ if (ret < 0) {
+ PARA_ERROR_LOG("syntax error in %s\n", cf);
+ goto out;
+ }
+ cf_argc = ret;
+ ret = lls(lls_parse(cf_argc, cf_argv, cmd, &lpr2,
+ &errctx));
+ lls_free_argv(cf_argv);
+ if (ret < 0) {
+ PARA_ERROR_LOG("parse error in %s\n", cf);
+ goto out;
+ }
+ ret = lls(lls_merge(lpr1, lpr2, cmd, &lpr3, &errctx));
+ lls_free_parse_result(lpr2, cmd);
+ if (ret < 0)
+ goto out;
+ lls_free_parse_result(lpr1, cmd);
+ lpr = lpr3;
+ loglevel = OPT_UINT32_VAL(LOGLEVEL);
+ }
}
- if (conf.socket_given)
- socket_name = para_strdup(conf.socket_arg);
+ if (OPT_GIVEN(COMPLETE))
+ print_completions();
+ if (OPT_GIVEN(SOCKET))
+ socket_name = para_strdup(OPT_STRING_VAL(SOCKET));
else {
char *hn = para_hostname();
socket_name = make_message("/var/paraslash/audiod_socket.%s",
hn);
free(hn);
}
-
- if (conf.complete_given)
- print_completions();
-
- if (conf.inputs_num == 0)
+ num_inputs = lls_num_inputs(lpr);
+ if (num_inputs == 0)
interactive_session();
- args = concat_args(conf.inputs_num, conf.inputs);
+ args = concat_args(num_inputs, NULL);
ret = connect_audiod(socket_name, args);
free(socket_name);
+ free(args);
if (ret < 0)
goto out;
fd = ret;
ret = mark_fd_blocking(STDOUT_FILENO);
if (ret < 0)
goto out;
- bufsize = conf.bufsize_arg;
+ bufsize = PARA_MAX(1024U, OPT_UINT32_VAL(BUFSIZE));
buf = para_malloc(bufsize);
do {
size_t n = ret = recv_bin_buffer(fd, buf, bufsize);
break;
ret = write_all(STDOUT_FILENO, buf, n);
} while (ret >= 0);
-out:
free(buf);
- free(args);
+out:
+ lls_free_parse_result(lpr, cmd);
+ free(cf);
+fail:
+ if (errctx)
+ PARA_ERROR_LOG("%s\n", errctx);
+ free(errctx);
if (ret < 0)
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
array="$(for i in $writers; do printf '{.init = '$i'_write_init},'; done)"
AC_DEFINE_UNQUOTED(WRITER_ARRAY, $array, array of supported writers)
######################################################################## audioc
-audioc_cmdline_objs="audioc"
audioc_errlist_objs="
audioc
string
net
fd
version
- ggo
"
if test $HAVE_READLINE = yes; then
audioc_errlist_objs="$audioc_errlist_objs
time
"
fi
-audioc_objs="add_cmdline($audioc_cmdline_objs) $audioc_errlist_objs"
+audioc_objs="$audioc_errlist_objs"
AC_SUBST(audioc_objs, add_dot_o($audioc_objs))
################################################################## status items
+++ /dev/null
-args "--unamed-opts=command --conf-parser --no-handle-version --no-handle-help"
-
-purpose "Communicate with para_audiod through a local socket"
-
-include(header.m4)
-<qu>
-option "socket" s
-#~~~~~~~~~~~~~~~~
-"well-known socket (default=/var/paraslash/audiod.socket.$HOSTNAME)"
- string typestr="filename"
- optional
-
-
-option "bufsize" b
-#~~~~~~~~~~~~~~~~~
-"size of internal buffer"
- int typestr="bytes"
- default="8192"
- optional
-</qu>
-
-define(CURRENT_PROGRAM,para_audioc)
-define(DEFAULT_HISTORY_FILE,~/.paraslash/audioc.history)
-include(loglevel.m4)
-include(history_file.m4)
-include(complete.m4)
--- /dev/null
+m4_define(PROGRAM, para_audioc)
+m4_define(DEFAULT_HISTORY_FILE, ~/.paraslash/audioc.history)
+[suite audioc]
+version-string = GIT_VERSION()
+[supercommand para_audioc]
+ purpose = communicate with para_audiod through a local socket
+ non-opts-name = [command [options]]
+ [description]
+ The client program to control para_audiod at runtime. It allows to
+ enable/disable streaming, to receive status info, or to grab the
+ audio stream at any point of the decoding process.
+
+ If no command is given, para_audioc enters interactive mode.
+ [/description]
+ m4_include(common-option-section.m4)
+ m4_include(help.m4)
+ m4_include(detailed-help.m4)
+ m4_include(version.m4)
+ m4_include(loglevel.m4)
+ m4_include(complete.m4)
+ m4_include(history-file.m4)
+ m4_include(per-command-options-section.m4)
+ [option socket]
+ short_opt = s
+ summary = path to well-known socket
+ arg_info = required_arg
+ arg_type = string
+ typestr = path
+ [help]
+ The default path of the socket is
+ /var/paraslash/audiod.socket.$HOSTNAME.
+ [/help]
+ [option bufsize]
+ short_opt = b
+ summary = size of internal buffer
+ arg_info = required_arg
+ arg_type = uint32
+ typestr = bytes
+ default_val = 8192
--- /dev/null
+.SH COPYRIGHT
+Written by Andre Noll
+.br
+Copyright (C) COPYRIGHT_YEAR() Andre Noll
+.br
+License: GNU GPL version 2
+.br
+This is free software: you are free to change and redistribute it.
+.br
+There is NO WARRANTY, to the extent permitted by law.
+.br
+Report bugs to
+.MT <maan@tuebingen.mpg.de>
+Andre Noll
+.ME
--- /dev/null
+[option common-option-section]
+ summary = Common options
+ flag ignored
+ [help]
+ The following options are implemented generically and are available
+ for many of the commands.
+ [/help]
+
--- /dev/null
+[option complete]
+ summary = print possible command line completions
+ [help]
+ If this flag is given, the environment variables COMP_LINE and
+ COMP_POINT are examined to obtain the current command line and the
+ cursor position respectively. Possible completions are written to
+ stdout and the program exits.
+ [/help]
--- /dev/null
+
+[option detailed-help]
+ summary = print help, including all details, and exit
--- /dev/null
+[option help]
+ summary = print help and exit
+ short_opt = h
--- /dev/null
+[option history-file]
+arg_info = required_arg
+arg_type = string
+typestr = filename
+summary = location of the file for the command history list
+[help]
+ If PROGRAM() runs in interactive mode, it reads the history file
+ on startup. Upon exit, the in-memory history is appended to the
+ history file.
+
+ If this option is not given, the history file is expected at
+ DEFAULT_HISTORY_FILE().
+[/help]
--- /dev/null
+[option host]
+ short_opt = i
+ summary = IP address or hostname
+ typestr = host
+ arg_info = required_arg
+ arg_type = string
+ default_val = localhost
+ [help]
+ Both IPv4 and IPv6 addresses are supported.
+ [/help]
--- /dev/null
+m4_define(`downcase', `m4_translit(`$*', `A-Z', `a-z')')
+m4_define(`SUITE_LOGLEVELS', `m4_patsubst(`$*', `LL_\([A-Z]+\)',
+ `LSGLL_\1 = "downcase(`\1')" ')')
+[option loglevel]
+ summary = control amount of logging
+ short_opt = l
+ arg_info = required_arg
+ arg_type = string
+ typestr = severity
+ values = {SUITE_LOGLEVELS(LOGLEVELS())}
+ default_val = warning
+ [help]
+ Log only messages with severity greater or equal than the given
+ value. Possible values:
+
+ debug: Produces really noisy output.
+ info: Still noisy, but won't fill up the disk quickly.
+ notice: Indicates normal, but significant event.
+ warning: Unexpected events that can be handled.
+ error: Unhandled error condition.
+ crit: System might be unreliable.
+ emerg: Last message before exit.
+ [/help]
--- /dev/null
+[option per-command-option-section]
+ summary = Options for PROGRAM()
+ flag ignored
--- /dev/null
+[option version]
+ summary = print version and exit
+ short_opt = V
.PRECIOUS: $(lls_suite_dir)/%.suite
+lls_m4_include_dir := $(lls_m4_dir)/include
+
+$(lls_suite_dir)/%.m4d: $(lls_m4_dir)/%.suite.m4 | $(lls_suite_dir)
+ @[ -z "$(Q)" ] || echo 'M4D $<'
+
+ $(Q) $(M4) -Pg -I $(lls_m4_include_dir) -s $< \
+ | awk '{if ($$1 ~ /#line/) {gsub(/"/, "", $$3); if ($$3 != "$<") \
+ print "$(lls_suite_dir)/$(*F).suite: " $$3}}' | sort | uniq > $@
$(lls_suite_dir)/%.suite: $(lls_m4_dir)/%.suite.m4 | $(lls_suite_dir)
- @[ -z "$(Q)" ] || echo 'M4 $<'
- $(Q) $(M4) -Pg $< > $@
+ $(Q) $(M4) -Pg -I $(lls_m4_include_dir) -D GIT_VERSION=$(GIT_VERSION) \
+ -D COPYRIGHT_YEAR=$(COPYRIGHT_YEAR) -D LOGLEVELS=$(LOGLEVELS) \
+ $< > $@
$(lls_suite_dir)/%.lsg.c: $(lls_suite_dir)/%.suite
@[ -z "$(Q)" ] || echo 'LSGC $<'
#define SAMPLE_FORMAT(a, b) b
/** \endcond sample_format */
-/** Debug loglevel, gets really noisy. */
-#define LL_DEBUG 0
-/** Still noisy, but won't fill your disk. */
-#define LL_INFO 1
-/** Normal, but significant event. */
-#define LL_NOTICE 2
-/** Unexpected event that can be handled. */
-#define LL_WARNING 3
-/** Unhandled error condition. */
-#define LL_ERROR 4
-/** System might be unreliable. */
-#define LL_CRIT 5
-/** Last message before exit. */
-#define LL_EMERG 6
-/** Number of all loglevels. */
-#define NUM_LOGLEVELS 7
-
-/** \cond log */
+/** Debug, Info, etc. */
+enum loglevels {LOGLEVELS, NUM_LOGLEVELS};
+
#define PARA_DEBUG_LOG(f,...) para_log(LL_DEBUG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_INFO_LOG(f,...) para_log(LL_INFO, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_NOTICE_LOG(f,...) para_log(LL_NOTICE, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_ERROR_LOG(f,...) para_log(LL_ERROR, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_CRIT_LOG(f,...) para_log(LL_CRIT, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#define PARA_EMERG_LOG(f,...) para_log(LL_EMERG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
-/** \endcond log */