Trivial: Rename completion_result variables.
[paraslash.git] / filter_common.c
index 6fb9bd9..add788a 100644 (file)
-/*
- * Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
 /** \file filter_common.c Common helper functions for filter input/output. */
 
 #include <regex.h>
 #include <sys/types.h>
+#include <lopsub.h>
 
+#include "filter_cmd.lsg.h"
 #include "para.h"
 #include "list.h"
 #include "sched.h"
 #include "fd.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "filter.h"
 #include "error.h"
 #include "string.h"
 
-/** Iterate over the array of supported filters. */
-#define FOR_EACH_SUPPORTED_FILTER(j)  for (j = 0; j < NUM_SUPPORTED_FILTERS; j++)
-
-/** The array of supported filters. */
-static struct filter filters[NUM_SUPPORTED_FILTERS] = {FILTER_ARRAY};
+/** Iterate over all filters. */
+#define FOR_EACH_FILTER(j) for (j = 1; FILTER_CMD(j); j++)
 
 /**
  * Obtain a reference to a filter structure.
  *
  * \param filter_num Between zero and NUM_SUPPORTED_FILTERS, inclusively.
  *
- * \return Pointer to the filter identified by the given filter number.
+ * \return Pointer to the filter identified by the given filter number, or
+ * NULL if the filter number is out of range.
  *
- * It is a fatal error if the given number is out of range. In this case
- * the function aborts.
+ * \sa filter_name().
  */
 const struct filter *filter_get(int filter_num)
 {
-       assert(filter_num >= 0);
-       assert(filter_num < NUM_SUPPORTED_FILTERS);
-       return filters + filter_num;
+       if (filter_num < 1 || filter_num > LSG_NUM_FILTER_CMD_SUBCOMMANDS)
+               return NULL;
+       return lls_user_data(FILTER_CMD(filter_num));
 }
 
-/**
- * Call the init function of each supported filter.
- * \sa filter::init
- */
-void filter_init(void)
+static inline bool filter_supported(int filter_num)
 {
-       int i;
-
-       FOR_EACH_SUPPORTED_FILTER(i)
-               filter_get(i)->init((struct filter *)filter_get(i));
+       return lls_user_data(FILTER_CMD(filter_num));
 }
 
-/*
- * If the filter has a command line parser and options is not NULL, run it.
- * Returns filter_num on success, negative on errors
+/**
+ * Return the name of a filter, given its number.
+ *
+ * \param filter_num See \ref filter_get().
+ *
+ * \return A pointer to a string literal, or NULL if filter_num is out of
+ * range. The caller must not attempt to call free(3) on the returned pointer.
  */
-static int parse_filter_args(int filter_num, char *options, void **conf)
+const char *filter_name(int filter_num)
 {
-       const struct filter *f = filter_get(filter_num);
-       int ret, argc;
-       char **argv;
-
-       if (!f->parse_config)
-               return strlen(options)? -E_BAD_FILTER_OPTIONS : filter_num;
-       argc = create_shifted_argv(options, " \t", &argv);
-       if (argc < 0)
-               return -E_BAD_FILTER_OPTIONS;
-       argv[0] = para_strdup(f->name);
-       ret = f->parse_config(argc, argv, conf);
-       free_argv(argv);
-       return ret < 0? ret : filter_num;
+       if (filter_num < 1 || filter_num > LSG_NUM_FILTER_CMD_SUBCOMMANDS)
+               return NULL;
+       return lls_command_name(FILTER_CMD(filter_num));
 }
 
 /**
- * Check the filter command line options.
- *
- * \param fa The command line options.
- * \param conf Points to the filter configuration upon successful return.
+ * Parse a filter command line and call the corresponding ->setup method.
  *
- * Check if \a fa starts with a the name of a supported filter, followed by
- * a colon. If yes, call the command line parser of that filter.
+ * \param fa The filter argument.
+ * \param conf Points to filter-specific setup upon successful return.
+ * \param lprp Parsed command line options are returned here.
  *
- * \return On success, the number of the filter is returned and \a conf
- * is initialized to point to the filter configuration determined by \a fa.
- * On errors, a negative value is returned.
+ * Check if the given filter argument starts with the name of a supported
+ * filter, optionally followed by options for this filter. If yes, call the
+ * command line parser of that filter and its ->setup method.
  *
- * Note: If \a fa specifies a filter that has no command line parser success is
- * returned, and \a conf is initialized to \p NULL.
- *
- * \sa filter::parse_config
+ * \return This function either succeeds or does not return. On success, the
+ * number of the filter is returned and conf is initialized to point to the
+ * filter configuration as returned by the filter's ->setup() method, if any.
+ * Moreover, *lprp is initialized to contain the parsed command line options.
+ * On errors, the function calls exit(EXIT_FAILURE).
  */
-int check_filter_arg(char *fa, void **conf)
+int filter_setup(const char *fa, void **conf, struct lls_parse_result **lprp)
 {
-       int j;
-
-       *conf = NULL;
-//     PARA_DEBUG_LOG("arg: %s\n", fa);
-       FOR_EACH_SUPPORTED_FILTER(j) {
-               const char *name = filter_get(j)->name;
-               size_t len = strlen(name);
-               char c;
-               if (strlen(fa) < len)
-                       continue;
-               if (strncmp(name, fa, len))
-                       continue;
-               c = fa[len];
-               if (c && c != ' ')
-                       continue;
-               if (c && !filter_get(j)->parse_config)
-                       return -E_BAD_FILTER_OPTIONS;
-               return parse_filter_args(j, c? fa + len + 1 :
-                       fa + strlen(fa), conf);
+       int ret, filter_num, argc;
+       char *errctx = NULL, **argv;
+       const struct lls_command *cmd;
+       const struct filter *f;
+
+       ret = create_argv(fa, " \t\n", &argv);
+       if (ret < 0)
+               goto fail;
+       argc = ret;
+       ret = lls(lls_lookup_subcmd(argv[0], filter_cmd_suite, &errctx));
+       if (ret < 0)
+               goto free_argv;
+       filter_num = ret;
+       cmd = FILTER_CMD(filter_num);
+       if (!filter_supported(filter_num)) {
+               ret = -E_UNSUPPORTED_FILTER;
+               errctx = make_message("bad filter name: %s",
+                       lls_command_name(cmd));
+               goto free_argv;
        }
-       return -E_UNSUPPORTED_FILTER;
+       ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
+       if (ret < 0)
+               goto free_argv;
+       f = filter_get(filter_num);
+       *conf = f->setup? f->setup(*lprp) : NULL;
+       ret = filter_num;
+free_argv:
+       free_argv(argv);
+       if (ret >= 0)
+               return ret;
+fail:
+       if (errctx)
+               PARA_ERROR_LOG("%s\n", errctx);
+       free(errctx);
+       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+       exit(EXIT_FAILURE);
 }
 
 /**
  * Print help text of each filter to stdout.
  *
- * \param flags Passed to \ref ggo_print_help().
+ * \param detailed Whether to print short or long help.
  */
-void print_filter_helps(unsigned flags)
+void print_filter_helps(bool detailed)
 {
        int i, num = 0;
 
-       printf_or_die("\nAvailable filters: ");
-       FOR_EACH_SUPPORTED_FILTER(i) {
+       printf("\nAvailable filters: ");
+       FOR_EACH_FILTER(i) {
+               if (!filter_supported(i))
+                       continue;
                if (num > 50) {
-                       printf_or_die("\n                  ");
+                       printf("\n                  ");
                        num = 0;
                }
-               num += printf_or_die("%s%s", i? " " : "", filter_get(i)->name);
+               num += printf("%s%s", i? " " : "", filter_name(i));
+       }
+       printf("\n");
+
+       FOR_EACH_FILTER(i) {
+               const struct lls_command *cmd = FILTER_CMD(i);
+               char *help;
+
+               if (!filter_supported(i))
+                       continue;
+               help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
+               if (!help)
+                       continue;
+               printf("%s\n", help);
+               free(help);
        }
-       printf_or_die("\n");
+}
 
-       FOR_EACH_SUPPORTED_FILTER(i) {
-               struct filter *f = (struct filter *)filter_get(i);
+/**
+ * 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;
 
-               if (!f->help.short_help)
+       printf("Available filters:\n");
+       FOR_EACH_FILTER(i) {
+               const struct lls_command *cmd = FILTER_CMD(i);
+               if (!filter_supported(i))
                        continue;
-               printf_or_die("\nOptions for %s (%s):", f->name,
-                       f->help.purpose);
-               ggo_print_help(&f->help, flags);
+               printf("%-9s %s\n", filter_name(i), lls_purpose(cmd));
        }
 }
 
@@ -203,7 +223,7 @@ int decoder_execute(const char *cmd, unsigned sample_rate, unsigned channels,
                return 1;
        }
        if (!strcmp(cmd, "sample_format")) {
-               *result = make_message("%u", DECODER_SAMPLE_FORMAT);
+               *result = make_message("%d", DECODER_SAMPLE_FORMAT);
                return 1;
        }
        return -ERRNO_TO_PARA_ERROR(ENOTSUP);