Convert para_filter to lopsub.
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 12 Jun 2016 18:46:10 +0000 (20:46 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 Mar 2017 09:02:28 +0000 (11:02 +0200)
Changes the semantics in case --filter is not given. We used to
print an error, but it makes more sense to show the list of supported
filters in this case.

If no filters are given, we now print the list of available filters. A
new function in filter_common.c, print_filter_list(), is introduced
for this purpose.

The manual page of para_filter has been extended to include an overall
description of the command.

The only error code of filter.c, E_NO_FILTERS, becomes unused and is
removed.

Makefile.real
configure.ac
error.h
filter.c
filter.h
filter_common.c
m4/gengetopt/filter.m4 [deleted file]
m4/lls/filter.suite.m4 [new file with mode: 0644]

index c229a1f..2051c3b 100644 (file)
@@ -43,14 +43,14 @@ all_objs := $(sort $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
        $(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)))
-converted_executables := audioc client fade play recv write
+converted_executables := audioc client fade play recv write filter
 unconverted_executables := $(filter-out $(converted_executables), $(executables))
 
 audioc_objs += audioc.lsg.o
 audiod_objs += $(addsuffix _cmd.lsg.o, recv filter audiod write) client.lsg.o
 client_objs += client.lsg.o
 fade_objs += fade.lsg.o
-filter_objs += filter_cmd.lsg.o
+filter_objs += filter_cmd.lsg.o filter.lsg.o
 play_objs += $(addsuffix _cmd.lsg.o, recv filter play write) play.lsg.o
 recv_objs += recv_cmd.lsg.o recv.lsg.o
 server_objs += server_cmd.lsg.o
index d700323..e310e2f 100644 (file)
@@ -681,7 +681,6 @@ filter_errlist_objs="
        sched
        fd
        amp_filter
-       ggo
        fecdec_filter
        fec
        version
@@ -695,9 +694,6 @@ filter_errlist_objs="
        net
        sync_filter
 "
-filter_cmdline_objs="
-       filter
-"
 NEED_VORBIS_OBJECTS && filter_errlist_objs="$filter_errlist_objs oggdec_filter"
 NEED_SPEEX_OBJECTS && filter_errlist_objs="$filter_errlist_objs spxdec_filter spx_common"
 NEED_OPUS_OBJECTS && filter_errlist_objs="$filter_errlist_objs opusdec_filter opus_common"
@@ -711,7 +707,7 @@ fi
 if test $HAVE_SAMPLERATE = yes; then
        filter_errlist_objs="$filter_errlist_objs resample_filter check_wav"
 fi
-filter_objs="add_cmdline($filter_cmdline_objs) $filter_errlist_objs"
+filter_objs="$filter_errlist_objs"
 
 AC_SUBST(filter_objs, add_dot_o($filter_objs))
 ########################################################################## recv
diff --git a/error.h b/error.h
index 9c8d7d3..56dbea2 100644 (file)
--- a/error.h
+++ b/error.h
        PARA_ERROR(NO_ATTRIBUTES, "no attributes defined yet"), \
        PARA_ERROR(NO_AUDIO_FILE, "no audio file"), \
        PARA_ERROR(NOFD, "did not receive open fd from afs"), \
-       PARA_ERROR(NO_FILTERS, "at least one filter must be given"), \
        PARA_ERROR(NO_MATCH, "no matches"), \
        PARA_ERROR(NO_MOOD, "no mood available"), \
        PARA_ERROR(NO_MORE_SLOTS, "no more empty slots"), \
index 1deaf6d..d5dac67 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -7,22 +7,31 @@
 /** \file filter.c The stand-alone filter program. */
 
 #include <regex.h>
+#include <lopsub.h>
 
+#include "filter.lsg.h"
+#include "filter_cmd.lsg.h"
 #include "para.h"
-#include "filter.cmdline.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "filter.h"
 #include "string.h"
 #include "stdin.h"
 #include "stdout.h"
 #include "error.h"
+#include "fd.h"
 #include "version.h"
 
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
+static struct lls_parse_result *lpr; /* command line options */
+
+#define CMD_PTR (lls_cmd(0, filter_suite))
+#define OPT_RESULT(_name) \
+       (lls_opt_result(LSG_FILTER_PARA_FILTER_OPT_ ## _name, lpr))
+#define OPT_GIVEN(_name) (lls_opt_given(OPT_RESULT(_name)))
+#define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
 
 /** The list of all status items used by para_{server,audiod,gui}. */
 const char *status_item_list[] = {STATUS_ITEM_ARRAY};
@@ -45,48 +54,75 @@ static struct stdout_task stdout_task_struct;
 /** Pointer to the stdout task. */
 static struct stdout_task *sot = &stdout_task_struct;
 
-/** Gengetopt struct that holds the command line args. */
-static struct filter_args_info conf;
-
 static int loglevel;
 INIT_STDERR_LOGGING(loglevel);
 
-__noreturn static void print_help_and_die(void)
+static void handle_help_flag(void)
 {
-       struct ggo_help h = DEFINE_GGO_HELP(filter);
-       bool d = conf.detailed_help_given;
-
-       ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
-       print_filter_helps(d);
+       char *help;
+
+       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);
+       print_filter_helps(OPT_GIVEN(DETAILED_HELP));
        exit(EXIT_SUCCESS);
 }
 
 static int parse_config(void)
 {
-       static char *cf; /* config file */
+       char *home, *cf; /* config file */
        struct stat statbuf;
+       int ret;
 
-       version_handle_flag("filter", conf.version_given);
-       if (conf.help_given || conf.detailed_help_given)
-               print_help_and_die();
-       if (!cf) {
-               char *home = para_homedir();
-               cf = make_message("%s/.paraslash/filter.conf", home);
-               free(home);
-       }
+       version_handle_flag("filter", OPT_GIVEN(VERSION));
+       handle_help_flag();
+       home = para_homedir();
+       cf = make_message("%s/.paraslash/filter.conf", home);
+       free(home);
        if (!stat(cf, &statbuf)) {
-               struct filter_cmdline_parser_params params = {
-                       .override = 0,
-                       .initialize = 0,
-                       .check_required = 0,
-                       .check_ambiguity = 0,
-                       .print_errors = 1
-               };
-               filter_cmdline_parser_config_file(cf, &conf, &params);
-               loglevel = get_loglevel_by_name(conf.loglevel_arg);
+               void *map;
+               size_t sz;
+               int cf_argc;
+               char **cf_argv, *errctx;
+               struct lls_parse_result *cf_lpr, *merged_lpr;
+
+               ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
+               if (ret != -E_EMPTY) {
+                       if (ret < 0)
+                               return ret;
+                       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);
+                               return ret;
+                       }
+                       cf_argc = ret;
+                       ret = lls(lls_parse(cf_argc, cf_argv, CMD_PTR, &cf_lpr,
+                               &errctx));
+                       lls_free_argv(cf_argv);
+                       if (ret < 0) {
+                               PARA_ERROR_LOG("parse error in %s\n", cf);
+                               return ret;
+                       }
+                       ret = lls(lls_merge(lpr, cf_lpr, CMD_PTR, &merged_lpr, &errctx));
+                       lls_free_parse_result(cf_lpr, CMD_PTR);
+                       if (ret < 0)
+                               return ret;
+                       lls_free_parse_result(lpr, CMD_PTR);
+                       lpr = merged_lpr;
+                       loglevel = OPT_UINT32_VAL(LOGLEVEL);
+               }
+       }
+       if (!OPT_GIVEN(FILTER)) {
+               print_filter_list();
+               exit(EXIT_SUCCESS);
        }
-       if (!conf.filter_given)
-               return -E_NO_FILTERS;
        return 1;
 }
 
@@ -109,20 +145,23 @@ int main(int argc, char *argv[])
        const struct filter *f;
        struct btr_node *parent;
        struct filter_node **fns;
-       struct lls_parse_result *filter_lpr;
+       struct lls_parse_result *filter_lpr; /* per-filter options */
+       char *errctx;
 
-       filter_cmdline_parser(argc, argv, &conf); /* aborts on errors */
-       loglevel = get_loglevel_by_name(conf.loglevel_arg);
-       ret = parse_config();
+       ret = lls(lls_parse(argc, argv, CMD_PTR, &lpr, &errctx));
        if (ret < 0)
                goto out;
+       loglevel = OPT_UINT32_VAL(LOGLEVEL);
+       ret = parse_config();
+       if (ret < 0)
+               goto free_lpr;
        sit->btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.name = "stdin"));
        stdin_task_register(sit, &s);
 
-       fns = para_malloc(conf.filter_given * sizeof(*fns));
-       for (i = 0, parent = sit->btrn; i < conf.filter_given; i++) {
-               char *fa = conf.filter_arg[i];
+       fns = para_malloc(OPT_GIVEN(FILTER) * sizeof(*fns));
+       for (i = 0, parent = sit->btrn; i < OPT_GIVEN(FILTER); i++) {
+               const char *fa = lls_string_val(i, OPT_RESULT(FILTER));
                const char *name;
                struct filter_node *fn;
                struct task_info ti;
@@ -168,8 +207,14 @@ int main(int argc, char *argv[])
        free(fns);
        btr_remove_node(&sit->btrn);
        btr_remove_node(&sot->btrn);
+free_lpr:
+       lls_free_parse_result(lpr, CMD_PTR);
 out:
-       if (ret < 0)
-               PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       if (ret < 0) {
+               if (errctx)
+                       PARA_ERROR_LOG("%s\n", errctx);
+               free(errctx);
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       }
        exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
 }
index ef8669a..4537b22 100644 (file)
--- a/filter.h
+++ b/filter.h
@@ -113,6 +113,7 @@ struct filter {
 };
 
 void print_filter_helps(bool detailed);
+void print_filter_list(void);
 int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp);
 #define FILTER_CMD(_num) (lls_cmd(_num, filter_cmd_suite))
 #define FILTER_CMD_OPT(_cmd, _opt) (lls_opt( \
index 5a5e9d0..991b3a1 100644 (file)
@@ -142,6 +142,26 @@ void print_filter_helps(bool detailed)
        }
 }
 
+/**
+ * Print a short summary of all available filters to stdout.
+ *
+ * For each supported filter, the filter name and the purpose text is printed
+ * in a single line. Since no options are shown, the filter list is more
+ * concise than the text obtained from print_filter_helps().
+ */
+void print_filter_list(void)
+{
+       int i;
+
+       printf("Available filters:\n");
+       FOR_EACH_FILTER(i) {
+               const struct lls_command *cmd = FILTER_CMD(i);
+               if (!filter_supported(i))
+                       continue;
+               printf("%-9s %s\n", filter_name(i), lls_purpose(cmd));
+       }
+}
+
 /**
  * Set select timeout of the scheduler.
  *
diff --git a/m4/gengetopt/filter.m4 b/m4/gengetopt/filter.m4
deleted file mode 100644 (file)
index b8b49f6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-args "--no-handle-help --no-handle-version --conf-parser"
-
-purpose "Decode or process audio data from STDIN to STDOUT"
-
-include(header.m4)
-include(loglevel.m4)
-<qu>
-option "filter" f
-#~~~~~~~~~~~~~~~~
-"Specify filter."
-string typestr="filter_spec"
-optional
-multiple
-details="
-       May be given multiple times to 'pipe' the stream through
-       arbitrary many filters (without copying the data). The same
-       filter may appear more than once, order matters.
-
-       Options for a particular filter may be specified for each
-       given '--filter' option separately. You will have to quote
-       these options like this:
-
-               --filter 'compress --inertia 5 --damp 2'
-"
-</qu>
diff --git a/m4/lls/filter.suite.m4 b/m4/lls/filter.suite.m4
new file mode 100644 (file)
index 0000000..0cd69eb
--- /dev/null
@@ -0,0 +1,37 @@
+m4_define(PROGRAM, para_filter)
+[suite filter]
+version-string = GIT_VERSION()
+[supercommand para_filter]
+       purpose = decode or process audio data from STDIN to STDOUT
+       [description]
+               This program allows to specify a chain of filters which transform the
+               audio stream read from STDIN. A common mode of operation is to decode
+               an mp3 file with the mp3dec filter, but many other filters exist which
+               transform the audio stream in different ways.
+       [/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(per-command-options-section.m4)
+       [option filter]
+               short_opt = f
+               summary = add one filter to the filter chain
+               arg_info = required_arg
+               arg_type = string
+               flag multiple
+               typestr = filter_spec
+               [help]
+                       A filter specifier begins with the name of a supported filter,
+                       optionally followed by zero or more options for the named filter.
+                       Filter name and options must be separated by whitespace. If the
+                       there is at least one option, the filter specifier needs to be quoted
+                       like this:
+
+                               --filter 'compress --inertia 5 --damp 2'
+
+                       This option may be specified multiple times to 'pipe' the stream
+                       through all given filters (in a single thread without copying the
+                       data). The same filter may appear more than once, and order matters.
+               [/help]