]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Convert receivers to lopsub.
authorAndre Noll <maan@tuebingen.mpg.de>
Mon, 22 Aug 2016 13:13:40 +0000 (15:13 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 26 Mar 2017 09:02:28 +0000 (11:02 +0200)
This converts the four receivers (afh, http, dccp, udp) to use the
lopsub library instead of gengetopt.

The command line options of the receivers are implemented as
subcommands of the new recv_cmd lopsub suite. Hence the four gengetopt
command line parsers and ->ggo_help of struct receiver can be removed.

This change allows to get rid of the receiver array which was defined
through the DEFINE_RECEIVER_ARRAY macro.  We now store each receiver
structure in the user_data pointer provided by lopsub.

Since this structure is initialized at compile time (and constant since
->ggo_help is gone), ->init() of struct receiver is no longer needed to
initialize the various function pointers. The function is now optional
and does not take an argument any more. At the moment, only the afh
receiver needs ->init() to initialize all supported audio format handlers.

t0005 needs slight adjustment since the section headers of the help text
have changed a bit.

21 files changed:
Makefile.in
Makefile.real
afh_recv.c
audiod.c
configure.ac
dccp_recv.c
error.h
http_recv.c
m4/gengetopt/afh_recv.m4 [deleted file]
m4/gengetopt/dccp_recv.m4 [deleted file]
m4/gengetopt/http_recv.m4 [deleted file]
m4/gengetopt/udp_recv.m4 [deleted file]
m4/lls/include/port.m4 [new file with mode: 0644]
m4/lls/recv_cmd.suite.m4 [new file with mode: 0644]
man_util.bash
play.c
recv.c
recv.h
recv_common.c
t/t0005-man.sh
udp_recv.c

index 986877bc2a20358c454cbeda0eda6e92b038346b..2a2bdaf53c1de00056049899212c14ee3f552004 100644 (file)
@@ -16,7 +16,6 @@ HELP2MAN := @HELP2MAN@
 ggo_descriptions_declared := @ggo_descriptions_declared@
 
 executables := @executables@
 ggo_descriptions_declared := @ggo_descriptions_declared@
 
 executables := @executables@
-receivers := @receivers@
 filters := @filters@
 writers := @writers@
 
 filters := @filters@
 writers := @writers@
 
index 045d57816096b9dbd945f15d3dcd1bd960083f53..2d381ad328a2cc777e9e49b8c7e03f1f05760c30 100644 (file)
@@ -47,12 +47,13 @@ converted_executables := audioc
 unconverted_executables := $(filter-out $(converted_executables), $(executables))
 
 audioc_objs += audioc.lsg.o
 unconverted_executables := $(filter-out $(converted_executables), $(executables))
 
 audioc_objs += audioc.lsg.o
-audiod_objs += audiod_cmd.lsg.o
+audiod_objs += audiod_cmd.lsg.o recv_cmd.lsg.o
 server_objs += server_cmd.lsg.o
 server_objs += server_cmd.lsg.o
-play_objs += play_cmd.lsg.o
+play_objs += play_cmd.lsg.o recv_cmd.lsg.o
+recv_objs += recv_cmd.lsg.o
 
 m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
 
 m4_deps := $(addprefix $(m4depdir)/, $(addsuffix .m4d, $(unconverted_executables)))
-m4_lls_deps := audiod_cmd server_cmd play_cmd $(converted_executables)
+m4_lls_deps := audiod_cmd server_cmd play_cmd recv_cmd $(converted_executables)
 m4_lls_deps := $(addprefix $(lls_suite_dir)/, $(addsuffix .m4d, $(m4_lls_deps)))
 
 # now prefix all objects with object dir
 m4_lls_deps := $(addprefix $(lls_suite_dir)/, $(addsuffix .m4d, $(m4_lls_deps)))
 
 # now prefix all objects with object dir
@@ -148,16 +149,21 @@ else
 endif
 
 server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man
 endif
 
 server_command_lists := $(lls_suite_dir)/server_cmd.lsg.man
-audiod_command_lists := $(lls_suite_dir)/audiod_cmd.lsg.man
+audiod_command_lists := \
+       $(lls_suite_dir)/audiod_cmd.lsg.man \
+       $(lls_suite_dir)/recv_cmd.lsg.man
 play_command_lists := $(lls_suite_dir)/play_cmd.lsg.man
 play_command_lists := $(lls_suite_dir)/play_cmd.lsg.man
+recv_command_lists := $(lls_suite_dir)/recv_cmd.lsg.man
 
 $(man_dir)/para_server.1: $(server_command_lists)
 $(man_dir)/para_audiod.1: $(audiod_command_lists)
 $(man_dir)/para_play.1: $(play_command_lists)
 
 $(man_dir)/para_server.1: $(server_command_lists)
 $(man_dir)/para_audiod.1: $(audiod_command_lists)
 $(man_dir)/para_play.1: $(play_command_lists)
+$(man_dir)/para_recv.1: $(recv_command_lists)
 
 $(man_dir)/para_server.1: man_util_command_lists := $(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_server.1: man_util_command_lists := $(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_recv.1: man_util_command_lists := $(recv_command_lists)
 
 $(man_dir)/para_%.1: $(lls_suite_dir)/%.lsg.man $(man_util_command_lists) \
                $(lls_m4_dir)/copyright.m4 | $(man_dir)
 
 $(man_dir)/para_%.1: $(lls_suite_dir)/%.lsg.man $(man_util_command_lists) \
                $(lls_m4_dir)/copyright.m4 | $(man_dir)
@@ -298,6 +304,7 @@ para_fade \
 para_audioc \
 para_audiod \
 para_play \
 para_audioc \
 para_audiod \
 para_play \
+para_recv \
 para_server \
 : LDFLAGS += $(lopsub_ldflags)
 
 para_server \
 : LDFLAGS += $(lopsub_ldflags)
 
index 28d8f3980f814763cfe249e5762203ff5038a9a5..b76c405a47c686ad5eec5d0e4c569101ff83738a 100644 (file)
@@ -8,15 +8,15 @@
 
 #include <regex.h>
 #include <sys/types.h>
 
 #include <regex.h>
 #include <sys/types.h>
+#include <lopsub.h>
 
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "sched.h"
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "buffer_tree.h"
 #include "recv.h"
-#include "afh_recv.cmdline.h"
 #include "string.h"
 #include "fd.h"
 #include "afh.h"
 #include "string.h"
 #include "fd.h"
 #include "afh.h"
@@ -65,40 +65,25 @@ static int afh_execute(struct btr_node *btrn, const char *cmd, char **result)
        return -E_BTR_NAVAIL;
 }
 
        return -E_BTR_NAVAIL;
 }
 
-static void *afh_recv_parse_config(int argc, char **argv)
-{
-       struct afh_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-
-       afh_recv_cmdline_parser(argc, argv, tmp);
-       return tmp;
-}
-
-static void afh_recv_free_config(void *conf)
-{
-       if (!conf)
-               return;
-       afh_recv_cmdline_parser_free(conf);
-       free(conf);
-}
-
 static int afh_recv_open(struct receiver_node *rn)
 {
 static int afh_recv_open(struct receiver_node *rn)
 {
-       struct afh_recv_args_info *conf = rn->conf;
+       struct lls_parse_result *lpr = rn->lpr;
        struct private_afh_recv_data *pard;
        struct afh_info *afhi;
        struct private_afh_recv_data *pard;
        struct afh_info *afhi;
-       char *filename = conf->filename_arg;
-
+       const char *fn = RECV_CMD_OPT_STRING_VAL(AFH, FILENAME, lpr);
+       int32_t bc = RECV_CMD_OPT_INT32_VAL(AFH, BEGIN_CHUNK, lpr);
+       const struct lls_opt_result *r_e = RECV_CMD_OPT_RESULT(AFH, END_CHUNK, lpr);
        int ret;
 
        int ret;
 
-       if (!filename || *filename == '\0')
+       if (!fn || *fn == '\0')
                return -E_AFH_RECV_BAD_FILENAME;
        rn->private_data = pard = para_calloc(sizeof(*pard));
        afhi = &pard->afhi;
                return -E_AFH_RECV_BAD_FILENAME;
        rn->private_data = pard = para_calloc(sizeof(*pard));
        afhi = &pard->afhi;
-       ret = mmap_full_file(filename, O_RDONLY, &pard->map,
+       ret = mmap_full_file(fn, O_RDONLY, &pard->map,
                &pard->map_size, &pard->fd);
        if (ret < 0)
                goto out;
                &pard->map_size, &pard->fd);
        if (ret < 0)
                goto out;
-       ret = compute_afhi(filename, pard->map, pard->map_size,
+       ret = compute_afhi(fn, pard->map, pard->map_size,
                pard->fd, afhi);
        if (ret < 0)
                goto out_unmap;
                pard->fd, afhi);
        if (ret < 0)
                goto out_unmap;
@@ -106,23 +91,22 @@ static int afh_recv_open(struct receiver_node *rn)
        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
        if (afhi->chunks_total == 0)
                goto out_clear_afhi;
        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
        if (afhi->chunks_total == 0)
                goto out_clear_afhi;
-       if (PARA_ABS(conf->begin_chunk_arg) >= afhi->chunks_total)
+       if (PARA_ABS(bc) >= afhi->chunks_total)
                goto out_clear_afhi;
                goto out_clear_afhi;
-       if (conf->begin_chunk_arg >= 0)
-               pard->first_chunk = afh_get_start_chunk(
-                       conf->begin_chunk_arg, &pard->afhi);
+       if (bc >= 0)
+               pard->first_chunk = afh_get_start_chunk(bc, &pard->afhi);
        else
        else
-               pard->first_chunk = afh_get_start_chunk(
-                       afhi->chunks_total + conf->begin_chunk_arg,
+               pard->first_chunk = afh_get_start_chunk(afhi->chunks_total + bc,
                        &pard->afhi);
                        &pard->afhi);
-       if (conf->end_chunk_given) {
+       if (lls_opt_given(r_e)) {
+               int32_t ec = lls_int32_val(0, r_e);
                ret = -ERRNO_TO_PARA_ERROR(EINVAL);
                ret = -ERRNO_TO_PARA_ERROR(EINVAL);
-               if (PARA_ABS(conf->end_chunk_arg) > afhi->chunks_total)
+               if (PARA_ABS(ec) > afhi->chunks_total)
                        goto out_clear_afhi;
                        goto out_clear_afhi;
-               if (conf->end_chunk_arg >= 0)
-                       pard->last_chunk = conf->end_chunk_arg;
+               if (ec >= 0)
+                       pard->last_chunk = ec;
                else
                else
-                       pard->last_chunk = afhi->chunks_total + conf->end_chunk_arg;
+                       pard->last_chunk = afhi->chunks_total + ec;
        } else
                pard->last_chunk = afhi->chunks_total - 1;
        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
        } else
                pard->last_chunk = afhi->chunks_total - 1;
        ret = -ERRNO_TO_PARA_ERROR(EINVAL);
@@ -158,13 +142,14 @@ static void afh_recv_pre_select(struct sched *s, void *context)
        struct receiver_node *rn = context;
        struct private_afh_recv_data *pard = rn->private_data;
        struct afh_info *afhi = &pard->afhi;
        struct receiver_node *rn = context;
        struct private_afh_recv_data *pard = rn->private_data;
        struct afh_info *afhi = &pard->afhi;
-       struct afh_recv_args_info *conf = rn->conf;
+       struct lls_parse_result *lpr = rn->lpr;
        struct timeval chunk_time;
        int state = generic_recv_pre_select(s, rn);
        struct timeval chunk_time;
        int state = generic_recv_pre_select(s, rn);
+       unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
 
        if (state <= 0)
                return;
 
        if (state <= 0)
                return;
-       if (!conf->just_in_time_given) {
+       if (!j_given) {
                sched_min_delay(s);
                return;
        }
                sched_min_delay(s);
                return;
        }
@@ -176,7 +161,7 @@ static void afh_recv_pre_select(struct sched *s, void *context)
 static int afh_recv_post_select(__a_unused struct sched *s, void *context)
 {
        struct receiver_node *rn = context;
 static int afh_recv_post_select(__a_unused struct sched *s, void *context)
 {
        struct receiver_node *rn = context;
-       struct afh_recv_args_info *conf = rn->conf;
+       struct lls_parse_result *lpr = rn->lpr;
        struct private_afh_recv_data *pard = rn->private_data;
        struct btr_node *btrn = rn->btrn;
        struct afh_info *afhi = &pard->afhi;
        struct private_afh_recv_data *pard = rn->private_data;
        struct btr_node *btrn = rn->btrn;
        struct afh_info *afhi = &pard->afhi;
@@ -185,11 +170,13 @@ static int afh_recv_post_select(__a_unused struct sched *s, void *context)
        const char *start, *end;
        size_t size;
        struct timeval chunk_time;
        const char *start, *end;
        size_t size;
        struct timeval chunk_time;
+       unsigned j_given = RECV_CMD_OPT_GIVEN(AFH, JUST_IN_TIME, lpr);
+       unsigned H_given = RECV_CMD_OPT_GIVEN(AFH, NO_HEADER, lpr);
 
        ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
        if (ret <= 0)
                goto out;
 
        ret = btr_node_status(btrn, 0, BTR_NT_ROOT);
        if (ret <= 0)
                goto out;
-       if (pard->first_chunk > 0 && !conf->no_header_given) {
+       if (pard->first_chunk > 0 && !H_given) {
                char *header;
                afh_get_header(afhi, pard->audio_format_num, pard->map,
                        pard->map_size, &header, &size);
                char *header;
                afh_get_header(afhi, pard->audio_format_num, pard->map,
                        pard->map_size, &header, &size);
@@ -201,7 +188,7 @@ static int afh_recv_post_select(__a_unused struct sched *s, void *context)
                        afh_free_header(header, pard->audio_format_num);
                }
        }
                        afh_free_header(header, pard->audio_format_num);
                }
        }
-       if (!conf->just_in_time_given) {
+       if (!j_given) {
                afh_get_chunk(pard->first_chunk, afhi, pard->map, &start, &size);
                afh_get_chunk(pard->last_chunk, afhi, pard->map, &end, &size);
                end += size;
                afh_get_chunk(pard->first_chunk, afhi, pard->map, &start, &size);
                afh_get_chunk(pard->last_chunk, afhi, pard->map, &end, &size);
                end += size;
@@ -236,26 +223,11 @@ out:
        return ret;
 }
 
        return ret;
 }
 
-/**
- * The init function of the afh receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * This initializes all function pointers of \a r.
- */
-void afh_recv_init(struct receiver *r)
-{
-       struct afh_recv_args_info dummy;
-
-       afh_init();
-       afh_recv_cmdline_parser_init(&dummy);
-       r->open = afh_recv_open;
-       r->close = afh_recv_close;
-       r->pre_select = afh_recv_pre_select;
-       r->post_select = afh_recv_post_select;
-       r->parse_config = afh_recv_parse_config;
-       r->free_config = afh_recv_free_config;
-       r->execute = afh_execute;
-       r->help = (struct ggo_help)DEFINE_GGO_HELP(afh_recv);
-       afh_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_afh_user_data = {
+       .init = afh_init,
+       .open = afh_recv_open,
+       .close = afh_recv_close,
+       .pre_select = afh_recv_pre_select,
+       .post_select = afh_recv_post_select,
+       .execute = afh_execute,
+};
index fa4019160bf8148a8503fa856c5dac3f9103b260..181d6ab12e6370a4e0df6b661ce20132d6036e78 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -17,6 +17,7 @@
 #include <pwd.h>
 #include <lopsub.h>
 
 #include <pwd.h>
 #include <lopsub.h>
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "crypt.h"
 #include "para.h"
 #include "error.h"
 #include "crypt.h"
@@ -47,14 +48,12 @@ __printf_2_3 void (*para_log)(int, const char*, ...) = daemon_log;
 /** define the array containing all supported audio formats */
 const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL};
 
 /** define the array containing all supported audio formats */
 const char *audio_formats[] = {AUDIOD_AUDIO_FORMAT_ARRAY NULL};
 
-DEFINE_RECEIVER_ARRAY;
-
 /** Defines how audiod handles one supported audio format. */
 struct audio_format_info {
 /** Defines how audiod handles one supported audio format. */
 struct audio_format_info {
-       /** pointer to the receiver for this audio format */
-       struct receiver *receiver;
-       /** the receiver configuration */
-       void *receiver_conf;
+       /** the receiver for this audio format */
+       int receiver_num;
+       /** Parsed receiver command line. */
+       struct lls_parse_result *receiver_lpr;
        /** the number of filters that should be activated for this audio format */
        unsigned int num_filters;
        /** Array of filter numbers to be activated. */
        /** the number of filters that should be activated for this audio format */
        unsigned int num_filters;
        /** Array of filter numbers to be activated. */
@@ -89,6 +88,9 @@ struct slot_info {
        struct writer_node *wns;
 };
 
        struct writer_node *wns;
 };
 
+#define RECEIVER_CMD(_a) lls_cmd((_a)->receiver_num, recv_cmd_suite)
+#define RECEIVER(_a) ((const struct receiver *)lls_user_data(RECEIVER_CMD(_a)))
+
 /** Maximal number of simultaneous instances. */
 #define MAX_STREAM_SLOTS 5
 
 /** Maximal number of simultaneous instances. */
 #define MAX_STREAM_SLOTS 5
 
@@ -477,7 +479,7 @@ static void close_receiver(int slot_num)
        a = &afi[s->format];
        PARA_NOTICE_LOG("closing %s receiver in slot %d\n",
                audio_formats[s->format], slot_num);
        a = &afi[s->format];
        PARA_NOTICE_LOG("closing %s receiver in slot %d\n",
                audio_formats[s->format], slot_num);
-       a->receiver->close(s->receiver_node);
+       RECEIVER(a)->close(s->receiver_node);
        btr_remove_node(&s->receiver_node->btrn);
        task_reap(&s->receiver_node->task);
        free(s->receiver_node);
        btr_remove_node(&s->receiver_node->btrn);
        task_reap(&s->receiver_node->task);
        free(s->receiver_node);
@@ -639,7 +641,8 @@ static int open_receiver(int format)
        struct audio_format_info *a = &afi[format];
        struct slot_info *s;
        int ret, slot_num;
        struct audio_format_info *a = &afi[format];
        struct slot_info *s;
        int ret, slot_num;
-       struct receiver *r = a->receiver;
+       const struct receiver *r = RECEIVER(a);
+       const char *name = lls_command_name(RECEIVER_CMD(a));
        struct receiver_node *rn;
 
        tv_add(now, &(struct timeval)EMBRACE(2, 0), &a->restart_barrier);
        struct receiver_node *rn;
 
        tv_add(now, &(struct timeval)EMBRACE(2, 0), &a->restart_barrier);
@@ -649,9 +652,9 @@ static int open_receiver(int format)
        slot_num = ret;
        rn = para_calloc(sizeof(*rn));
        rn->receiver = r;
        slot_num = ret;
        rn = para_calloc(sizeof(*rn));
        rn->receiver = r;
-       rn->conf = a->receiver_conf;
+       rn->lpr = a->receiver_lpr;
        rn->btrn = btr_new_node(&(struct btr_node_description)
        rn->btrn = btr_new_node(&(struct btr_node_description)
-               EMBRACE(.name = r->name, .context = rn));
+               EMBRACE(.name = name, .context = rn));
        ret = r->open(rn);
        if (ret < 0) {
                btr_remove_node(&rn->btrn);
        ret = r->open(rn);
        if (ret < 0) {
                btr_remove_node(&rn->btrn);
@@ -662,9 +665,9 @@ static int open_receiver(int format)
        s->format = format;
        s->receiver_node = rn;
        PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n",
        s->format = format;
        s->receiver_node = rn;
        PARA_NOTICE_LOG("started %s: %s receiver in slot %d\n",
-               audio_formats[format], r->name, slot_num);
+               audio_formats[format], name, slot_num);
        rn->task = task_register(&(struct task_info) {
        rn->task = task_register(&(struct task_info) {
-               .name = r->name,
+               .name = name,
                .pre_select = r->pre_select,
                .post_select = r->post_select,
                .context = rn,
                .pre_select = r->pre_select,
                .post_select = r->post_select,
                .context = rn,
@@ -827,7 +830,7 @@ static int update_item(int itemnum, char *buf)
        return 1;
 }
 
        return 1;
 }
 
-static int parse_stream_command(const char *txt, char **cmd)
+static int parse_stream_command(const char *txt, const char **cmd)
 {
        int ret, len;
        char *re, *p = strchr(txt, ':');
 {
        int ret, len;
        char *re, *p = strchr(txt, ':');
@@ -844,7 +847,7 @@ static int parse_stream_command(const char *txt, char **cmd)
        return ret;
 }
 
        return ret;
 }
 
-static int add_filter(int format, char *cmdline)
+static int add_filter(int format, const char *cmdline)
 {
        struct audio_format_info *a = &afi[format];
        int filter_num, nf = a->num_filters;
 {
        struct audio_format_info *a = &afi[format];
        int filter_num, nf = a->num_filters;
@@ -868,7 +871,7 @@ static int add_filter(int format, char *cmdline)
 static int parse_writer_args(void)
 {
        int i, ret;
 static int parse_writer_args(void)
 {
        int i, ret;
-       char *cmd;
+       const char *cmd;
        struct audio_format_info *a;
 
        for (i = 0; i < conf.writer_given; i++) {
        struct audio_format_info *a;
 
        for (i = 0; i < conf.writer_given; i++) {
@@ -915,12 +918,13 @@ static int parse_writer_args(void)
 
 static int parse_receiver_args(void)
 {
 
 static int parse_receiver_args(void)
 {
-       int i, ret, receiver_num;
-       char *cmd = NULL;
+       int i, ret;
+       const char *arg;
        struct audio_format_info *a;
 
        struct audio_format_info *a;
 
+       FOR_EACH_AUDIO_FORMAT(i)
+               afi[i].receiver_num = -1;
        for (i = conf.receiver_given - 1; i >= 0; i--) {
        for (i = conf.receiver_given - 1; i >= 0; i--) {
-               char *arg;
                int j, af_mask;
 
                ret = parse_stream_command(conf.receiver_arg[i], &arg);
                int j, af_mask;
 
                ret = parse_stream_command(conf.receiver_arg[i], &arg);
@@ -937,37 +941,27 @@ static int parse_receiver_args(void)
                         * config here. Since we are iterating backwards, the winning
                         * receiver arg is in fact the first one given.
                         */
                         * config here. Since we are iterating backwards, the winning
                         * receiver arg is in fact the first one given.
                         */
-                       if (a->receiver_conf)
-                               a->receiver->free_config(a->receiver_conf);
-                       a->receiver_conf = check_receiver_arg(arg, &receiver_num);
-                       ret = -E_RECV_SYNTAX;
-                       if (!a->receiver_conf)
-                               goto out;
-                       a->receiver = receivers + receiver_num;
+                       lls_free_parse_result(a->receiver_lpr, RECEIVER_CMD(a));
+                       a->receiver_num = check_receiver_arg(arg, &a->receiver_lpr);
                }
        }
        /*
                }
        }
        /*
-        * Use the first available receiver with no arguments for those audio
-        * formats for which no receiver was specified.
+        * Use the default receiver for those audio formats for which no
+        * receiver was specified.
         */
         */
-       cmd = para_strdup(receivers[0].name);
        FOR_EACH_AUDIO_FORMAT(i) {
        FOR_EACH_AUDIO_FORMAT(i) {
-               a = &afi[i];
-               if (a->receiver_conf)
+               a = afi + i;
+               if (a->receiver_num >= 0)
                        continue;
                        continue;
-               a->receiver_conf = check_receiver_arg(cmd, &receiver_num);
-               if (!a->receiver_conf)
-                       return -E_RECV_SYNTAX;
-               a->receiver = &receivers[receiver_num];
+               a->receiver_num = check_receiver_arg(NULL, &a->receiver_lpr);
        }
        FOR_EACH_AUDIO_FORMAT(i) {
                a = afi + i;
                PARA_INFO_LOG("receiving %s streams via %s receiver\n",
        }
        FOR_EACH_AUDIO_FORMAT(i) {
                a = afi + i;
                PARA_INFO_LOG("receiving %s streams via %s receiver\n",
-                       audio_formats[i], a->receiver->name);
+                       audio_formats[i], lls_command_name(RECEIVER_CMD(a)));
        }
        ret = 1;
 out:
        }
        ret = 1;
 out:
-       free(cmd);
        return ret;
 }
 
        return ret;
 }
 
@@ -977,6 +971,7 @@ static int init_default_filters(void)
 
        FOR_EACH_AUDIO_FORMAT(i) {
                struct audio_format_info *a = &afi[i];
 
        FOR_EACH_AUDIO_FORMAT(i) {
                struct audio_format_info *a = &afi[i];
+               const char *name = lls_command_name(RECEIVER_CMD(a));
                char *tmp;
                int j;
 
                char *tmp;
                int j;
 
@@ -986,8 +981,7 @@ static int init_default_filters(void)
                 * udp and dccp streams are fec-encoded, so add fecdec as the
                 * first filter.
                 */
                 * udp and dccp streams are fec-encoded, so add fecdec as the
                 * first filter.
                 */
-               if (strcmp(afi[i].receiver->name, "udp") == 0 ||
-                               strcmp(afi[i].receiver->name, "dccp") == 0) {
+               if (strcmp(name, "udp") == 0 || strcmp(name, "dccp") == 0) {
                        tmp = para_strdup("fecdec");
                        add_filter(i, tmp);
                        free(tmp);
                        tmp = para_strdup("fecdec");
                        add_filter(i, tmp);
                        free(tmp);
@@ -1020,7 +1014,7 @@ static int parse_filter_args(void)
        int i, j, ret, af_mask, num_matches;
 
        for (i = 0; i < conf.filter_given; i++) {
        int i, j, ret, af_mask, num_matches;
 
        for (i = 0; i < conf.filter_given; i++) {
-               char *arg;
+               const char *arg;
                ret = parse_stream_command(conf.filter_arg[i], &arg);
                if (ret < 0)
                        goto out;
                ret = parse_stream_command(conf.filter_arg[i], &arg);
                if (ret < 0)
                        goto out;
index 6087bac4334f3e1950e880adbca594993da77214..d5e52839f8998ab89db35b9f657be627d0a6fc0a 100644 (file)
@@ -511,12 +511,9 @@ if test -n "$CRYPTOLIB"; then
        audiod_cmdline_objs="$audiod_cmdline_objs
                audiod
                compress_filter
        audiod_cmdline_objs="$audiod_cmdline_objs
                audiod
                compress_filter
-               http_recv
-               dccp_recv
                file_write
                client
                amp_filter
                file_write
                client
                amp_filter
-               udp_recv
                prebuffer_filter
                sync_filter
        "
                prebuffer_filter
                sync_filter
        "
@@ -775,10 +772,6 @@ AC_DEFINE_UNQUOTED(FILTER_ARRAY, $array, array of supported filters)
 ########################################################################## recv
 recv_cmdline_objs="
        recv
 ########################################################################## recv
 recv_cmdline_objs="
        recv
-       http_recv
-       dccp_recv
-       udp_recv
-       afh_recv
 "
 
 recv_errlist_objs="
 "
 
 recv_errlist_objs="
@@ -792,7 +785,6 @@ recv_errlist_objs="
        fd
        sched
        stdout
        fd
        sched
        stdout
-       ggo
        udp_recv
        buffer_tree
        afh_recv
        udp_recv
        buffer_tree
        afh_recv
@@ -812,7 +804,6 @@ if test $HAVE_FAAD = yes -a $HAVE_MP4V2 = yes; then
        recv_errlist_objs="$recv_errlist_objs aac_afh aac_common"
 fi
 recv_objs="add_cmdline($recv_cmdline_objs) $recv_errlist_objs"
        recv_errlist_objs="$recv_errlist_objs aac_afh aac_common"
 fi
 recv_objs="add_cmdline($recv_cmdline_objs) $recv_errlist_objs"
-AC_SUBST(receivers, "http dccp udp afh")
 AC_SUBST(recv_objs, add_dot_o($recv_objs))
 ########################################################################### afh
 audio_format_handlers="mp3 wma"
 AC_SUBST(recv_objs, add_dot_o($recv_objs))
 ########################################################################### afh
 audio_format_handlers="mp3 wma"
@@ -889,10 +880,6 @@ play_errlist_objs="
        sync_filter
 "
 play_cmdline_objs="
        sync_filter
 "
 play_cmdline_objs="
-       http_recv
-       dccp_recv
-       udp_recv
-       afh_recv
        compress_filter
        amp_filter
        prebuffer_filter
        compress_filter
        amp_filter
        prebuffer_filter
index 253586e1f7ee4f90867a157757a34a227458047a..318969afe3c123c611638e3954c4556d29c82e14 100644 (file)
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "sched.h"
 #include "para.h"
 #include "error.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "string.h"
 #include "net.h"
 #include "fd.h"
 
 #include "buffer_tree.h"
 #include "recv.h"
 #include "string.h"
 #include "net.h"
 #include "fd.h"
 
-#include "dccp_recv.cmdline.h"
-
 static void dccp_recv_close(struct receiver_node *rn)
 {
        if (rn->fd > 0)
 static void dccp_recv_close(struct receiver_node *rn)
 {
        if (rn->fd > 0)
@@ -39,25 +38,56 @@ static void dccp_recv_close(struct receiver_node *rn)
        btr_pool_free(rn->btrp);
 }
 
        btr_pool_free(rn->btrp);
 }
 
+/* Check whether the host supports the requested 'ccid' arguments. */
+static int dccp_recv_ccid_support_check(const struct lls_parse_result *lpr)
+{
+       uint8_t *ccids;
+       int i, j, ret, nccids;
+       unsigned given = RECV_CMD_OPT_GIVEN(DCCP, CCID, lpr);
+
+       ret = dccp_available_ccids(&ccids);
+       if (ret < 0)
+               return ret;
+       nccids = ret;
+       for (i = 0; i < given; i++) {
+               uint32_t val = lls_uint32_val(i,
+                       RECV_CMD_OPT_RESULT(DCCP, CCID, lpr));
+               for (j = 0; j < nccids && ccids[j] != val; j++)
+                       ;
+               if (j == nccids) {
+                       PARA_ERROR_LOG("'CCID-%u' not supported on this host\n",
+                               val);
+                       return -ERRNO_TO_PARA_ERROR(EINVAL);
+               }
+       }
+       return 1;
+}
+
 static int dccp_recv_open(struct receiver_node *rn)
 {
 static int dccp_recv_open(struct receiver_node *rn)
 {
-       struct dccp_recv_args_info *conf = rn->conf;
+       struct lls_parse_result *lpr = rn->lpr;
        struct flowopts *fo = NULL;
        uint8_t *ccids = NULL;
        int fd, ret, i;
        struct flowopts *fo = NULL;
        uint8_t *ccids = NULL;
        int fd, ret, i;
+       const struct lls_opt_result *r_c = RECV_CMD_OPT_RESULT(DCCP, CCID, lpr);
+       const char *host = RECV_CMD_OPT_STRING_VAL(DCCP, HOST, lpr);
+       uint32_t port = RECV_CMD_OPT_UINT32_VAL(DCCP, PORT, lpr);
+       unsigned given;
 
 
+       ret = dccp_recv_ccid_support_check(lpr);
+       if (ret < 0)
+               return ret;
        /* Copy CCID preference list (u8 array required) */
        /* Copy CCID preference list (u8 array required) */
-       if (conf->ccid_given) {
-               ccids = para_malloc(conf->ccid_given);
-               fo    = flowopt_new();
-
-               for (i = 0; i < conf->ccid_given; i++)
-                       ccids[i] = conf->ccid_arg[i];
-
+       given = lls_opt_given(r_c);
+       if (given) {
+               ccids = para_malloc(given);
+               fo = flowopt_new();
+               for (i = 0; i < given; i++)
+                       ccids[i] = lls_int32_val(i, r_c);
                OPT_ADD(fo, SOL_DCCP, DCCP_SOCKOPT_CCID, ccids, i);
        }
 
                OPT_ADD(fo, SOL_DCCP, DCCP_SOCKOPT_CCID, ccids, i);
        }
 
-       fd = makesock(IPPROTO_DCCP, 0, conf->host_arg, conf->port_arg, fo);
+       fd = makesock(IPPROTO_DCCP, 0, host, port, fo);
        flowopt_cleanup(fo);
        free(ccids);
        if (fd < 0)
        flowopt_cleanup(fo);
        free(ccids);
        if (fd < 0)
@@ -83,42 +113,6 @@ err:
        return ret;
 }
 
        return ret;
 }
 
-/**
- * Check whether the host supports the requested 'ccid' arguments.
- * \param conf DCCP receiver arguments.
- * \return True if all CCIDs requested in \a conf are supported.
- */
-static bool dccp_recv_ccid_support_check(struct dccp_recv_args_info *conf)
-{
-       uint8_t *ccids;
-       int i, j, nccids;
-
-       nccids = dccp_available_ccids(&ccids);
-       if (nccids <= 0)
-               return false;
-
-       for (i = 0; i < conf->ccid_given; i++) {
-               for (j = 0; j < nccids && ccids[j] != conf->ccid_arg[i]; j++)
-                       ;
-               if (j == nccids) {
-                       PARA_ERROR_LOG("'CCID-%d' not supported on this host.\n",
-                                       conf->ccid_arg[i]);
-                       return false;
-               }
-       }
-       return true;
-}
-
-static void *dccp_recv_parse_config(int argc, char **argv)
-{
-       struct dccp_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-
-       dccp_recv_cmdline_parser(argc, argv, tmp);
-       if (!dccp_recv_ccid_support_check(tmp))
-               exit(EXIT_FAILURE);
-       return tmp;
-}
-
 static void dccp_recv_pre_select(struct sched *s, void *context)
 {
        struct receiver_node *rn = context;
 static void dccp_recv_pre_select(struct sched *s, void *context)
 {
        struct receiver_node *rn = context;
@@ -161,30 +155,9 @@ out:
        return ret;
 }
 
        return ret;
 }
 
-static void dccp_recv_free_config(void *conf)
-{
-       dccp_recv_cmdline_parser_free(conf);
-       free(conf);
-}
-
-/**
- * The init function of the dccp receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * Initialize all function pointers of \a r.
- */
-void dccp_recv_init(struct receiver *r)
-{
-       struct dccp_recv_args_info dummy;
-
-       dccp_recv_cmdline_parser_init(&dummy);
-       r->open = dccp_recv_open;
-       r->close = dccp_recv_close;
-       r->pre_select = dccp_recv_pre_select;
-       r->post_select = dccp_recv_post_select;
-       r->parse_config = dccp_recv_parse_config;
-       r->free_config = dccp_recv_free_config;
-       r->help = (struct ggo_help)DEFINE_GGO_HELP(dccp_recv);
-       dccp_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_dccp_user_data = {
+       .open = dccp_recv_open,
+       .close = dccp_recv_close,
+       .pre_select = dccp_recv_pre_select,
+       .post_select = dccp_recv_post_select,
+};
diff --git a/error.h b/error.h
index a4d79aba5573e348d88d7bf6bd11ee961555afa1..d10ac76abcaa669abb381b07325040338b85c100 100644 (file)
--- a/error.h
+++ b/error.h
        PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \
        PARA_ERROR(RECV_EOF, "end of file"), \
        PARA_ERROR(RECVMSG, "recvmsg() failed"), \
        PARA_ERROR(READ_PATTERN, "did not read expected pattern"), \
        PARA_ERROR(RECV_EOF, "end of file"), \
        PARA_ERROR(RECVMSG, "recvmsg() failed"), \
-       PARA_ERROR(RECV_SYNTAX, "recv syntax error"), \
        PARA_ERROR(REGEX, "regular expression error"), \
        PARA_ERROR(RESAMPLE_EOF, "resample filter: end of file"), \
        PARA_ERROR(RSA, "RSA error"), \
        PARA_ERROR(REGEX, "regular expression error"), \
        PARA_ERROR(RESAMPLE_EOF, "resample filter: end of file"), \
        PARA_ERROR(RSA, "RSA error"), \
index 2f334787200e4a0134df6a108a0c4dc8a7dd0775..d49cf2a853b3043edc09e5e419632b7cce2da6be 100644 (file)
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "http.h"
 #include "list.h"
 #include "sched.h"
 #include "para.h"
 #include "error.h"
 #include "http.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "buffer_tree.h"
 #include "recv.h"
-#include "http_recv.cmdline.h"
 #include "net.h"
 #include "string.h"
 #include "fd.h"
 #include "net.h"
 #include "string.h"
 #include "fd.h"
@@ -144,20 +144,13 @@ static void http_recv_close(struct receiver_node *rn)
        free(rn->private_data);
 }
 
        free(rn->private_data);
 }
 
-static void *http_recv_parse_config(int argc, char **argv)
-{
-       struct http_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-
-       http_recv_cmdline_parser(argc, argv, tmp);
-       return tmp;
-}
-
 static int http_recv_open(struct receiver_node *rn)
 {
        struct private_http_recv_data *phd;
 static int http_recv_open(struct receiver_node *rn)
 {
        struct private_http_recv_data *phd;
-       struct http_recv_args_info *conf = rn->conf;
-       int fd, ret = para_connect_simple(IPPROTO_TCP, conf->host_arg,
-                                                      conf->port_arg);
+       struct lls_parse_result *lpr = rn->lpr;
+       const char *r_i = RECV_CMD_OPT_STRING_VAL(HTTP, HOST, lpr);
+       uint32_t r_p = RECV_CMD_OPT_UINT32_VAL(HTTP, PORT, lpr);
+       int fd, ret = para_connect_simple(IPPROTO_TCP, r_i, r_p);
 
        if (ret < 0)
                return ret;
 
        if (ret < 0)
                return ret;
@@ -174,30 +167,9 @@ static int http_recv_open(struct receiver_node *rn)
        return 1;
 }
 
        return 1;
 }
 
-static void http_recv_free_config(void *conf)
-{
-       http_recv_cmdline_parser_free(conf);
-       free(conf);
-}
-
-/**
- * The init function of the http receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * This initializes all function pointers of \a r.
- */
-void http_recv_init(struct receiver *r)
-{
-       struct http_recv_args_info dummy;
-
-       http_recv_cmdline_parser_init(&dummy);
-       r->open = http_recv_open;
-       r->close = http_recv_close;
-       r->pre_select = http_recv_pre_select;
-       r->post_select = http_recv_post_select;
-       r->parse_config = http_recv_parse_config;
-       r->free_config = http_recv_free_config;
-       r->help = (struct ggo_help)DEFINE_GGO_HELP(http_recv);
-       http_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_http_user_data = {
+       .open = http_recv_open,
+       .close = http_recv_close,
+       .pre_select = http_recv_pre_select,
+       .post_select = http_recv_post_select,
+};
diff --git a/m4/gengetopt/afh_recv.m4 b/m4/gengetopt/afh_recv.m4
deleted file mode 100644 (file)
index 28a0a9e..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-args "--no-version --no-help"
-
-purpose "Make an audio stream from a local file"
-
-description "
-       The afh (audio format handler) receiver can be used to write
-       selected parts of the given audio file without decoding
-       the data.
-
-       The selected parts of the content of the audio file are passed
-       to the child nodes of the buffer tree. Only complete chunks
-       with respect of the underlying audio format are passed.
-"
-
-include(header.m4)
-<qu>
-option "filename" f
-#~~~~~~~~~~~~~~~~~~
-"file to open"
-string typestr = "filename"
-required
-
-option "begin-chunk" b
-#~~~~~~~~~~~~~~~~~~~~~
-"skip the beginning of the file"
-int typestr = "chunk_num"
-default = "0"
-optional
-details = "
-       The chunk_num argument must be between -num_chunks and
-       num_chunks - 1, inclusively, where num_chunks is the total
-       number of chunks of the audio file given by the argument to
-       --filename. If chunk_num is negative, the given number of
-       chunks are counted backwards from the end of the file. For
-       example --begin-chunk -100 instructs the afh receiver to
-       start output at chunk num_chunks - 100. This is useful for
-       selecting the last part of an audio file.
-"
-
-option "end-chunk" e
-#~~~~~~~~~~~~~~~~~~~
-"only write up to chunk chunk_num"
-int typestr = "chunk_num"
-optional
-details = "
-       For the chunk_num argument the same rules as for --begin-chunk
-       apply. The default is to write up to the last chunk.
-"
-
-option "just-in-time" j
-#~~~~~~~~~~~~~~~~~~~~~~
-"use timed writes"
-flag off
-details = "
-       Write the specified chunks of data 'just in time', i.e. the
-       write of each chunk is delayed until the time it is needed
-       by the decoder/player in order to guarantee an uninterrupted
-       audio stream. This may be useful for third-party software
-       that is capable of reading from stdin.
-"
-
-option "no-header" H
-#~~~~~~~~~~~~~~~~~~~
-"do not write an audio file header"
-flag off
-details = "
-       If an audio format needs information about the audio file
-       in a format-specific header in order to be understood by
-       the decoding software, a suitable header is automatically
-       send. This option changes the default behaviour, i.e. no
-       header is written.
-"
-
-</qu>
diff --git a/m4/gengetopt/dccp_recv.m4 b/m4/gengetopt/dccp_recv.m4
deleted file mode 100644 (file)
index 1ba3fb5..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-args "--no-version --no-help"
-
-purpose "Receive a DCCP audio stream"
-
-option "host" i
-"ip or host"
-string default="localhost"
-optional
-details="
-       Both IPv4 and IPv6 addresses are supported.
-"
-
-option "port" p
-"port to connect to"
-int
-default="8000"
-optional
-
-option "ccid" c
-"CCID preference(s) for this connection"
-int
-# restrict the maximum number of times this option can be passed
-optional multiple(-10)
-# currently known CCIDs:
-# - CCID-2 (RFC 4341),
-# - CCID-3 (RFC 4342),
-# - CCID-4 (RFC 5622),
-# - CCID-248 ... CCID-254 are experimental (RFC 4340, 19.5)
-values="2", "3", "4", "248", "249", "250", "251", "252", "253", "254"
-details="
-       When present exactly once, this option mandates the CCID for the
-       sender-receiver connection. If it is passed more than once, it sets
-       a preference list where the order of appearance signifies descending
-       priority. For example, passing 4, 2, 3 creates the preference list
-       (CCID-4, CCID-2, CCID-3), assigning CCID-4 highest preference.
-
-       The request is reconciled with the CCIDs on the server through the
-       'server-priority' mechanism of RFC 4340 6.3.1/10. The server CCIDs
-       can be listed by calling 'para_client si'.
-
-"
diff --git a/m4/gengetopt/http_recv.m4 b/m4/gengetopt/http_recv.m4
deleted file mode 100644 (file)
index 6db3ff0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-args "--no-version --no-help"
-
-purpose "Receive an HTTP audio stream"
-
-include(header.m4)
-
-<qu>
-option "host" i
-#~~~~~~~~~~~~~~
-"ip or host"
-string
-default="localhost"
-optional
-details="
-       Both IPv4 and IPv6 addresses are supported.
-"
-
-option "port" p
-#~~~~~~~~~~~~~~
-"tcp port to connect to"
-int default="8000"
-optional
-</qu>
diff --git a/m4/gengetopt/udp_recv.m4 b/m4/gengetopt/udp_recv.m4
deleted file mode 100644 (file)
index dcdad4f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-args "--no-version --no-help"
-
-purpose "Receive an UDP audio stream"
-
-option "host" i
-"ip or host to receive udp packets from"
-string default="224.0.1.38"
-optional
-details="
-       The default address resolves to DANTZ.MCAST.NET and activates
-       multicast.
-"
-
-option "port" p "udp port"
-int typestr="portnumber"
-default="8000"
-optional
-
-option "iface" I "receiving udp multicast interface"
-string
-optional
diff --git a/m4/lls/include/port.m4 b/m4/lls/include/port.m4
new file mode 100644 (file)
index 0000000..8dd63b6
--- /dev/null
@@ -0,0 +1,7 @@
+[option port]
+       short_opt = p
+       summary = TCP port to connect to
+       typestr = portnumber
+       arg_info = required_arg
+       arg_type = uint32
+       default_val = 8000
diff --git a/m4/lls/recv_cmd.suite.m4 b/m4/lls/recv_cmd.suite.m4
new file mode 100644 (file)
index 0000000..674a448
--- /dev/null
@@ -0,0 +1,102 @@
+[suite recv_cmd]
+caption = receivers
+[subcommand afh]
+       purpose = make an audio stream from a local file
+       [description]
+               The afh (audio format handler) receiver extracts selected parts of
+               the given audio file without decoding the file. Only complete chunks
+               with respect to the underlying audio format are extracted.
+       [/description]
+       [option filename]
+               short_opt = f
+               summary = file to open
+               typestr = filename
+               arg_info = required_arg
+               arg_type = string
+       [option begin-chunk]
+               short_opt = b
+               summary = skip the beginning of the file
+               typestr = chunk_num
+               arg_info = required_arg
+               arg_type = int32
+               [help]
+                       The argument must be an integer between -num_chunks and num_chunks -
+                       1, inclusively, where num_chunks is the total number of chunks. If
+                       chunk_num is negative, the given number of chunks are counted backwards
+                       from the end of the file. For example --begin-chunk -100 instructs
+                       the afh receiver to start at chunk num_chunks - 100. This is useful
+                       for cutting off the beginning of an audio file.
+               [/help]
+       [option end-chunk]
+               short_opt = e
+               summary = only write up to chunk chunk_num
+               typestr = chunk_num
+               arg_info = required_arg
+               arg_type = int32
+               [help]
+                       For the chunk_num argument the same rules as for --begin-chunk
+                       apply. The default is to write up to the last chunk.
+               [/help]
+       [option just-in-time]
+               short_opt = j
+               summary = use timed writes
+               [help]
+                       Write the specified data chunks 'just in time', i.e., delay the write
+                       until data is needed by the decoder/player for an uninterrupted audio
+                       stream. This may be useful for third-party software.
+               [/help]
+       [option no-header]
+               short_opt = h
+               summary = do not write an audio file header
+               [help]
+                       Some audio formats store information about the audio file in
+                       a format-specific header which is needed to decode any part of
+                       the file. For such formats the afh receiver generates a suitable
+                       header. This option changes the default behaviour, i.e. no header
+                       is written.
+               [/help]
+[subcommand http]
+       purpose = receive an audio stream over HTTP
+       m4_include(host.m4)
+       m4_include(port.m4)
+[subcommand dccp]
+       purpose = receive an audio stream over DCCP
+       m4_include(host.m4)
+       m4_include(port.m4)
+       [option ccid]
+               short_opt = c
+               summary = CCID preference(s) for this connection
+               typestr = id
+               arg_info = required_arg
+               arg_type = uint32
+               flag multiple
+               [help]
+                       When present exactly once, this option mandates the CCID for the
+                       sender-receiver connection. If it is passed more than once, it sets
+                       a preference list where the order of appearance signifies descending
+                       priority. For example, passing 4, 2, 3 creates the preference list
+                       (CCID-4, CCID-2, CCID-3), assigning CCID-4 highest preference.
+
+                       The request is reconciled with the CCIDs on the server through the
+                       'server-priority' mechanism of RFC 4340 6.3.1/10. The server CCIDs
+                       can be listed by calling 'para_client si'.
+               [/help]
+[subcommand udp]
+       purpose = receive an audio stream over UDP
+       [option host]
+               short_opt = i
+               summary = IP address or hostname
+               typestr = host
+               arg_info = required_arg
+               arg_type = string
+               default_val = 224.0.1.38
+               [help]
+                       The default address resolves to DANTZ.MCAST.NET and activates
+                       multicast.
+               [/help]
+       m4_include(port.m4)
+       [option iface]
+               summary = receiving udp multicast interface
+               typestr = iface-name
+               arg_info = required_arg
+               arg_type = string
index 687acaab5510dab25cc83a2e65b319359d85b3d0..38ed86c8eef2083cc89907cdbba4de619a8ccb0c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
 #!/usr/bin/env bash
 
-# Receivers, filters, writers are called "modules" in this script
+# filters, writers are called "modules" in this script
 print_modhelp()
 {
        local ggo="$1"
 print_modhelp()
 {
        local ggo="$1"
@@ -39,14 +39,6 @@ make_help()
                --set-package "para_$1" \
                < "$ggo"
 
                --set-package "para_$1" \
                < "$ggo"
 
-       if [[ "$target" == 'recv' || "$target" == 'audiod' ]]; then
-               for module in $RECEIVERS; do
-                       ggo="$GGO_DIR/${module}_recv.ggo"
-                       [[ ! -f "$ggo" ]] && continue
-                       printf "\nOptions for the $module receiver"
-                       print_modhelp "$ggo"
-               done
-       fi
        if [[ "$target" == 'filter' || "$target" == 'audiod' ]]; then
                for module in $FILTERS; do
                        ggo="$GGO_DIR/${module}_filter.ggo"
        if [[ "$target" == 'filter' || "$target" == 'audiod' ]]; then
                for module in $FILTERS; do
                        ggo="$GGO_DIR/${module}_filter.ggo"
diff --git a/play.c b/play.c
index 1ab4010160cac7e22988111d361de5e745dcd75c..4dab1cad58b3a989e96072c95e153b08cd18e24f 100644 (file)
--- a/play.c
+++ b/play.c
@@ -11,6 +11,7 @@
 #include <inttypes.h>
 #include <lopsub.h>
 
 #include <inttypes.h>
 #include <lopsub.h>
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "list.h"
 #include "play.cmdline.h"
 #include "para.h"
 #include "list.h"
 #include "play.cmdline.h"
@@ -110,14 +111,6 @@ struct play_command_info {
                .handler = com_ ## _cmd \
        };
 
                .handler = com_ ## _cmd \
        };
 
-/* Activate the afh receiver. */
-extern void afh_recv_init(struct receiver *r);
-#undef AFH_RECEIVER
-/** Initialization code for a receiver struct. */
-#define AFH_RECEIVER {.name = "afh", .init = afh_recv_init},
-/** This expands to the array of all receivers. */
-DEFINE_RECEIVER_ARRAY;
-
 static int loglevel = LL_WARNING;
 
 /** The log function which writes log messages to stderr. */
 static int loglevel = LL_WARNING;
 
 /** The log function which writes log messages to stderr. */
@@ -131,22 +124,9 @@ static struct play_args_info conf;
 
 static struct sched sched = {.max_fileno = 0};
 static struct play_task play_task;
 
 static struct sched sched = {.max_fileno = 0};
 static struct play_task play_task;
-static struct receiver *afh_recv;
 
 
-static void check_afh_receiver_or_die(void)
-{
-       int i;
-
-       FOR_EACH_RECEIVER(i) {
-               struct receiver *r = receivers + i;
-               if (strcmp(r->name, "afh"))
-                       continue;
-               afh_recv = r;
-               return;
-       }
-       PARA_EMERG_LOG("fatal: afh receiver not found\n");
-       exit(EXIT_FAILURE);
-}
+#define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite))
+#define AFH_RECV ((struct receiver *)lls_user_data(AFH_RECV_CMD))
 
 __noreturn static void print_help_and_die(void)
 {
 
 __noreturn static void print_help_and_die(void)
 {
@@ -242,12 +222,13 @@ static long unsigned get_play_time(struct play_task *pt)
        return result;
 }
 
        return result;
 }
 
+
 static void wipe_receiver_node(struct play_task *pt)
 {
        PARA_NOTICE_LOG("cleaning up receiver node\n");
        btr_remove_node(&pt->rn.btrn);
 static void wipe_receiver_node(struct play_task *pt)
 {
        PARA_NOTICE_LOG("cleaning up receiver node\n");
        btr_remove_node(&pt->rn.btrn);
-       afh_recv->close(&pt->rn);
-       afh_recv->free_config(pt->rn.conf);
+       AFH_RECV->close(&pt->rn);
+       lls_free_parse_result(pt->rn.lpr, AFH_RECV_CMD);
        memset(&pt->rn, 0, sizeof(struct receiver_node));
 }
 
        memset(&pt->rn, 0, sizeof(struct receiver_node));
 }
 
@@ -320,25 +301,26 @@ static void shuffle(char **base, size_t num)
 static struct btr_node *new_recv_btrn(struct receiver_node *rn)
 {
        return btr_new_node(&(struct btr_node_description)
 static struct btr_node *new_recv_btrn(struct receiver_node *rn)
 {
        return btr_new_node(&(struct btr_node_description)
-               EMBRACE(.name = afh_recv->name, .context = rn,
-                       .handler = afh_recv->execute));
+               EMBRACE(.name = lls_command_name(AFH_RECV_CMD), .context = rn,
+                       .handler = AFH_RECV->execute));
 }
 
 static int open_new_file(struct play_task *pt)
 {
        int ret;
 }
 
 static int open_new_file(struct play_task *pt)
 {
        int ret;
-       char *tmp, *path = conf.inputs[pt->next_file], *afh_recv_conf[] =
-               {"play", "-f", path, "-b", "0", NULL};
+       char *tmp, *path = conf.inputs[pt->next_file], *errctx = NULL,
+               *argv[] = {"play", "-f", path, "-b", "0", NULL};
 
        PARA_NOTICE_LOG("next file: %s\n", path);
        wipe_receiver_node(pt);
        pt->start_chunk = 0;
        pt->rn.btrn = new_recv_btrn(&pt->rn);
 
        PARA_NOTICE_LOG("next file: %s\n", path);
        wipe_receiver_node(pt);
        pt->start_chunk = 0;
        pt->rn.btrn = new_recv_btrn(&pt->rn);
-       pt->rn.conf = afh_recv->parse_config(ARRAY_SIZE(afh_recv_conf) - 1,
-               afh_recv_conf);
-       assert(pt->rn.conf);
-       pt->rn.receiver = afh_recv;
-       ret = afh_recv->open(&pt->rn);
+       ret = lls(lls_parse(ARRAY_SIZE(argv) - 1, argv, AFH_RECV_CMD,
+               &pt->rn.lpr, &errctx));
+       free(tmp);
+       assert(ret >= 0);
+       pt->rn.receiver = AFH_RECV;
+       ret = AFH_RECV->open(&pt->rn);
        if (ret < 0) {
                PARA_ERROR_LOG("could not open %s\n", path);
                goto fail;
        if (ret < 0) {
                PARA_ERROR_LOG("could not open %s\n", path);
                goto fail;
@@ -420,9 +402,9 @@ static int load_file(struct play_task *pt)
        /* success, register tasks */
        pt->rn.task = task_register(
                &(struct task_info) {
        /* success, register tasks */
        pt->rn.task = task_register(
                &(struct task_info) {
-                       .name = afh_recv->name,
-                       .pre_select = afh_recv->pre_select,
-                       .post_select = afh_recv->post_select,
+                       .name = lls_command_name(AFH_RECV_CMD),
+                       .pre_select = AFH_RECV->pre_select,
+                       .post_select = AFH_RECV->post_select,
                        .context = &pt->rn
                }, &sched);
        sprintf(buf, "%s decoder", af);
                        .context = &pt->rn
                }, &sched);
        sprintf(buf, "%s decoder", af);
@@ -1287,8 +1269,7 @@ int main(int argc, char *argv[])
        parse_config_or_die(argc, argv);
        if (conf.inputs_num == 0)
                print_help_and_die();
        parse_config_or_die(argc, argv);
        if (conf.inputs_num == 0)
                print_help_and_die();
-       check_afh_receiver_or_die();
-
+       AFH_RECV->init();
        session_open(pt);
        if (conf.randomize_given)
                shuffle(conf.inputs, conf.inputs_num);
        session_open(pt);
        if (conf.randomize_given)
                shuffle(conf.inputs, conf.inputs_num);
diff --git a/recv.c b/recv.c
index 9de3033fee92925a4cd1446c8895f59055c82486..abebbfc2dfd80a0d2373f7c0431395c03656433f 100644 (file)
--- a/recv.c
+++ b/recv.c
@@ -8,11 +8,13 @@
 
 #include <regex.h>
 #include <sys/types.h>
 
 #include <regex.h>
 #include <sys/types.h>
+#include <inttypes.h>
+#include <lopsub.h>
 
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "list.h"
 #include "sched.h"
 #include "para.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "recv.cmdline.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "recv.cmdline.h"
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
 
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
 
-extern void afh_recv_init(struct receiver *r);
-#undef AFH_RECEIVER
-#define AFH_RECEIVER {.name = "afh", .init = afh_recv_init},
-DEFINE_RECEIVER_ARRAY;
-
 /** The gengetopt args info struct. */
 static struct recv_args_info conf;
 
 /** The gengetopt args info struct. */
 static struct recv_args_info conf;
 
@@ -39,12 +36,13 @@ INIT_STDERR_LOGGING(loglevel);
 
 __noreturn static void print_help_and_die(void)
 {
 
 __noreturn static void print_help_and_die(void)
 {
-       struct ggo_help h = DEFINE_GGO_HELP(recv);
        bool d = conf.detailed_help_given;
        bool d = conf.detailed_help_given;
-
-       ggo_print_help(&h, d? GPH_STANDARD_FLAGS_DETAILED : GPH_STANDARD_FLAGS);
-       print_receiver_helps(d? GPH_MODULE_FLAGS_DETAILED : GPH_MODULE_FLAGS);
-       exit(0);
+       if (d)
+               recv_cmdline_parser_print_detailed_help();
+       else
+               recv_cmdline_parser_print_help();
+       print_receiver_helps(d);
+       exit(EXIT_SUCCESS);
 }
 
 /**
 }
 
 /**
@@ -60,12 +58,15 @@ __noreturn static void print_help_and_die(void)
  */
 int main(int argc, char *argv[])
 {
  */
 int main(int argc, char *argv[])
 {
-       int ret, r_opened = 0, receiver_num;
-       struct receiver *r = NULL;
+       int ret;
+       bool r_opened = false;
+       const struct receiver *r = NULL;
        struct receiver_node rn;
        struct stdout_task sot = {.btrn = NULL};
        static struct sched s;
        struct task_info ti;
        struct receiver_node rn;
        struct stdout_task sot = {.btrn = NULL};
        static struct sched s;
        struct task_info ti;
+       const struct lls_command *cmd;
+       struct lls_parse_result *receiver_lpr; /* receiver specific options */
 
        recv_cmdline_parser(argc, argv, &conf);
        loglevel = get_loglevel_by_name(conf.loglevel_arg);
 
        recv_cmdline_parser(argc, argv, &conf);
        loglevel = get_loglevel_by_name(conf.loglevel_arg);
@@ -75,26 +76,25 @@ int main(int argc, char *argv[])
                print_help_and_die();
 
        memset(&rn, 0, sizeof(struct receiver_node));
                print_help_and_die();
 
        memset(&rn, 0, sizeof(struct receiver_node));
-       rn.conf = check_receiver_arg(conf.receiver_arg, &receiver_num);
-       if (!rn.conf) {
-               PARA_EMERG_LOG("invalid receiver specifier\n");
-               ret = -E_RECV_SYNTAX;
+       ret = check_receiver_arg(conf.receiver_arg, &receiver_lpr);
+       if (ret < 0)
                goto out;
                goto out;
-       }
-       r = &receivers[receiver_num];
+       cmd = lls_cmd(ret, recv_cmd_suite);
+       r = lls_user_data(cmd);
        rn.receiver = r;
        rn.receiver = r;
+       rn.lpr = receiver_lpr;
        rn.btrn = btr_new_node(&(struct btr_node_description)
        rn.btrn = btr_new_node(&(struct btr_node_description)
-               EMBRACE(.name = r->name));
+               EMBRACE(.name = lls_command_name(cmd)));
        ret = r->open(&rn);
        if (ret < 0)
        ret = r->open(&rn);
        if (ret < 0)
-               goto out;
-       r_opened = 1;
+               goto free_receiver_lpr;
+       r_opened = true;
 
        sot.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.parent = rn.btrn, .name = "stdout"));
        stdout_task_register(&sot, &s);
 
 
        sot.btrn = btr_new_node(&(struct btr_node_description)
                EMBRACE(.parent = rn.btrn, .name = "stdout"));
        stdout_task_register(&sot, &s);
 
-       ti.name = r->name;
+       ti.name = lls_command_name(cmd);
        ti.pre_select = r->pre_select;
        ti.post_select = r->post_select;
        ti.context = &rn;
        ti.pre_select = r->pre_select;
        ti.post_select = r->post_select;
        ti.context = &rn;
@@ -104,13 +104,16 @@ int main(int argc, char *argv[])
        s.default_timeout.tv_usec = 0;
        ret = schedule(&s);
        sched_shutdown(&s);
        s.default_timeout.tv_usec = 0;
        ret = schedule(&s);
        sched_shutdown(&s);
+       r->close(&rn);
+       btr_remove_node(&sot.btrn);
+       btr_remove_node(&rn.btrn);
+free_receiver_lpr:
+       lls_free_parse_result(receiver_lpr, cmd);
 out:
        if (r_opened)
                r->close(&rn);
        btr_remove_node(&rn.btrn);
        btr_remove_node(&sot.btrn);
 out:
        if (r_opened)
                r->close(&rn);
        btr_remove_node(&rn.btrn);
        btr_remove_node(&sot.btrn);
-       if (rn.conf)
-               r->free_config(rn.conf);
 
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
 
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
diff --git a/recv.h b/recv.h
index 1a0de659e92be1d6f68838c3408b8859c4278a43..68978a38c90f2dada11f21d0b55b8a078e4b4bef 100644 (file)
--- a/recv.h
+++ b/recv.h
  */
 struct receiver_node {
        /** Points to the corresponding receiver. */
  */
 struct receiver_node {
        /** Points to the corresponding receiver. */
-       struct receiver *receiver;
+       const struct receiver *receiver;
        /** Receiver-specific data. */
        void *private_data;
        /** Receiver-specific data. */
        void *private_data;
-       /** Pointer to the configuration data for this instance. */
-       void *conf;
+       /** The parsed command line options for this instance. */
+       struct lls_parse_result *lpr;
        /** The task associated with this instance. */
        struct task *task;
        /** The receiver node is always the root of the buffer tree. */
        /** The task associated with this instance. */
        struct task *task;
        /** The receiver node is always the root of the buffer tree. */
@@ -44,34 +44,13 @@ struct receiver_node {
  */
 struct receiver {
        /**
  */
 struct receiver {
        /**
-        * The name of the receiver.
-        */
-       const char *name;
-       /**
-        * The receiver init function.
+        * The optional receiver init function.
         *
         *
-        * It must fill in all other function pointers and is assumed to succeed.
+        * Performs any initialization needed before the receiver can be opened.
         *
         * \sa http_recv_init udp_recv_init.
         */
         *
         * \sa http_recv_init udp_recv_init.
         */
-       void (*init)(struct receiver *r);
-       /**
-        * The command line parser of the receiver.
-        *
-        * It should check whether the command line options given by \a argc
-        * and \a argv are valid.  On success, it should return a pointer to
-        * the receiver-specific configuration data determined by \a argc and
-        * \a argv.  Note that this might be called more than once with
-        * different values of \a argc and \a argv.
-        */
-       void *(*parse_config)(int argc, char **argv);
-       /**
-        * Deallocate the configuration structure of a receiver node.
-        *
-        * This calls the receiver-specific cleanup function generated by
-        * gengetopt.
-        */
-       void (*free_config)(void *conf);
+       void (*init)(void);
        /**
         * Open one instance of the receiver.
         *
        /**
         * Open one instance of the receiver.
         *
@@ -117,8 +96,6 @@ struct receiver {
         */
        int (*post_select)(struct sched *s, void *context);
 
         */
        int (*post_select)(struct sched *s, void *context);
 
-       /** The two help texts of this receiver. */
-       struct ggo_help help;
        /**
         * Answer a buffer tree query.
         *
        /**
         * Answer a buffer tree query.
         *
@@ -128,31 +105,23 @@ struct receiver {
        btr_command_handler execute;
 };
 
        btr_command_handler execute;
 };
 
-/** Define an array of all available receivers. */
-#define DEFINE_RECEIVER_ARRAY struct receiver receivers[] = { \
-       HTTP_RECEIVER \
-       DCCP_RECEIVER \
-       UDP_RECEIVER \
-       AFH_RECEIVER \
-       {.name = NULL}};
+#define RECV_CMD(_num) (lls_cmd(_num, recv_cmd_suite))
+
+#define RECV_CMD_OPT_RESULT(_recv, _opt, _lpr) \
+       (lls_opt_result(LSG_RECV_CMD_ ## _recv ## _OPT_ ## _opt, _lpr))
+#define RECV_CMD_OPT_GIVEN(_recv, _opt, _lpr) \
+       (lls_opt_given(RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
+#define RECV_CMD_OPT_STRING_VAL(_recv, _opt, _lpr) \
+       (lls_string_val(0, RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
+#define RECV_CMD_OPT_UINT32_VAL(_recv, _opt, _lpr) \
+       (lls_uint32_val(0, RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
+#define RECV_CMD_OPT_INT32_VAL(_recv, _opt, _lpr) \
+       (lls_int32_val(0, RECV_CMD_OPT_RESULT(_recv, _opt, _lpr)))
 
 /** Iterate over all available receivers. */
 
 /** Iterate over all available receivers. */
-#define FOR_EACH_RECEIVER(i) for (i = 0; receivers[i].name; i++)
+#define FOR_EACH_RECEIVER(i) for (i = 1; lls_cmd(i, recv_cmd_suite); i++)
 
 void recv_init(void);
 
 void recv_init(void);
-void *check_receiver_arg(char *ra, int *receiver_num);
-void print_receiver_helps(unsigned flags);
+int check_receiver_arg(const char *ra, struct lls_parse_result **lprp);
+void print_receiver_helps(bool detailed);
 int generic_recv_pre_select(struct sched *s, struct receiver_node *rn);
 int generic_recv_pre_select(struct sched *s, struct receiver_node *rn);
-
-/** \cond receiver */
-extern void http_recv_init(struct receiver *r);
-#define HTTP_RECEIVER {.name = "http", .init = http_recv_init},
-extern void dccp_recv_init(struct receiver *r);
-#define DCCP_RECEIVER {.name = "dccp", .init = dccp_recv_init},
-extern void udp_recv_init(struct receiver *r);
-#define UDP_RECEIVER {.name = "udp", .init = udp_recv_init},
-#define AFH_RECEIVER /* not active by default */
-
-extern struct receiver receivers[];
-/** \endcond receiver */
-
index 59630dfcc5f5f6fc5cfa973fd25c4476366b6b92..7bb775fe214af8880bc1244743760b59a2188e46 100644 (file)
@@ -7,11 +7,14 @@
 /** \file recv_common.c common functions of para_recv and para_audiod */
 
 #include <regex.h>
 /** \file recv_common.c common functions of para_recv and para_audiod */
 
 #include <regex.h>
+#include <inttypes.h>
+#include <lopsub.h>
 
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "para.h"
+#include "error.h"
 #include "list.h"
 #include "sched.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "string.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "string.h"
@@ -23,92 +26,93 @@ void recv_init(void)
 {
        int i;
 
 {
        int i;
 
-       FOR_EACH_RECEIVER(i)
-               receivers[i].init(&receivers[i]);
-}
-
-static void *parse_receiver_args(int receiver_num, char *options)
-{
-       struct receiver *r = &receivers[receiver_num];
-       char **argv;
-       int argc;
-       void *conf;
-
-       if (options) {
-               argc = create_shifted_argv(options, " \t", &argv);
-               if (argc < 0)
-                       return NULL;
-       } else {
-               argc = 1;
-               argv = para_malloc(2 * sizeof(char*));
-               argv[1] = NULL;
+       FOR_EACH_RECEIVER(i) {
+               const struct lls_command *cmd = RECV_CMD(i);
+               const struct receiver *r = lls_user_data(cmd);
+               if (r && r->init)
+                       r->init();
        }
        }
-       argv[0] = make_message("%s_recv", r->name);
-       conf = r->parse_config(argc, argv);
-       free_argv(argv);
-       return conf;
 }
 
 /**
  * Check if the given string is a valid receiver specifier.
  *
 }
 
 /**
  * Check if the given string is a valid receiver specifier.
  *
- * \param \ra string of the form receiver_name:options
- * \param receiver_num contains the number of the receiver upon success
+ * \param \ra string of the form receiver_name [options...]
+ * \param lprp Filled in on success, undefined else.
  *
  * This function checks whether \a ra starts with the name of a receiver,
  * optionally followed by options for that receiver. If a valid receiver name
  * was found the remaining part of \a ra is passed to the receiver's config
  * parser.
  *
  *
  * This function checks whether \a ra starts with the name of a receiver,
  * optionally followed by options for that receiver. If a valid receiver name
  * was found the remaining part of \a ra is passed to the receiver's config
  * parser.
  *
- * \return On success, a pointer to the receiver-specific gengetopt args info
- * struct is returned and \a receiver_num contains the number of the receiver.
- * On errors, the function returns \p NULL.
+ * If a NULL pointer or an empty string is passed as the first argument, the
+ * hhtp receiver with no options is assumed.
+ *
+ * \return On success the number of the receiver is returned. On errors, the
+ * function calls exit(EXIT_FAILURE).
  */
  */
-void *check_receiver_arg(char *ra, int *receiver_num)
+int check_receiver_arg(const char *ra, struct lls_parse_result **lprp)
 {
 {
-       int j;
+       int ret, argc, receiver_num;
+       char *errctx = NULL, **argv;
+       const struct lls_command *cmd;
 
 
-       PARA_DEBUG_LOG("checking %s\n", ra);
-       for (j = 0; receivers[j].name; j++) {
-               const char *name = receivers[j].name;
-               size_t len = strlen(name);
-               char c;
-               if (strlen(ra) < len)
-                       continue;
-               if (strncmp(name, ra, len))
-                       continue;
-               c = ra[len];
-               if (c && c != ' ')
-                       continue;
-               if (c && !receivers[j].parse_config)
-                       return NULL;
-               *receiver_num = j;
-               return parse_receiver_args(j, c? ra + len + 1: NULL);
+       *lprp = NULL;
+       if (!ra || !*ra) {
+               argc = 1;
+               argv = para_malloc(2 * sizeof(char*));
+               argv[0] = para_strdup("http");
+               argv[1] = NULL;
+       } else {
+               ret = create_argv(ra, " \t\n", &argv);
+               if (ret < 0) {
+                       PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+                       exit(EXIT_FAILURE);
+               }
+               argc = ret;
        }
        }
-       PARA_ERROR_LOG("receiver not found\n");
-       return NULL;
+       ret = lls(lls_lookup_subcmd(argv[0], recv_cmd_suite, &errctx));
+       if (ret < 0) {
+               PARA_EMERG_LOG("%s: %s\n", errctx? errctx : argv[0],
+                       para_strerror(-ret));
+               exit(EXIT_FAILURE);
+       }
+       receiver_num = ret;
+       cmd = RECV_CMD(receiver_num);
+       ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
+       if (ret < 0) {
+               if (errctx)
+                       PARA_ERROR_LOG("%s\n", errctx);
+               PARA_EMERG_LOG("%s\n", para_strerror(-ret));
+               exit(EXIT_FAILURE);
+       }
+       ret = receiver_num;
+       free_argv(argv);
+       return ret;
 }
 
 /**
  * Print out the help texts to all receivers.
  *
 }
 
 /**
  * Print out the help texts to all receivers.
  *
- * \param flags Passed to \ref ggo_print_help().
+ * \param detailed Whether to print the short or the detailed help.
  */
  */
-void print_receiver_helps(unsigned flags)
+void print_receiver_helps(bool detailed)
 {
        int i;
 
 {
        int i;
 
-       printf_or_die("\nAvailable receivers: ");
-       FOR_EACH_RECEIVER(i)
-               printf_or_die("%s%s", i? " " : "", receivers[i].name);
-       printf_or_die("\n");
+       printf("\nAvailable receivers: ");
+       FOR_EACH_RECEIVER(i) {
+               const struct lls_command *cmd = RECV_CMD(i);
+               printf("%s%s", i? " " : "", lls_command_name(cmd));
+       }
+       printf("\n\n");
        FOR_EACH_RECEIVER(i) {
        FOR_EACH_RECEIVER(i) {
-               struct receiver *r = receivers + i;
-               if (!r->help.short_help)
+               const struct lls_command *cmd = RECV_CMD(i);
+               char *help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
+               if (!help)
                        continue;
                        continue;
-               printf_or_die("\n%s: %s", r->name,
-                       r->help.purpose);
-               ggo_print_help(&r->help, flags);
+               printf("%s\n", help);
+               free(help);
        }
 }
 
        }
 }
 
index 8f966cd5c48ea27ff14bedb03577cbf1f0d9bc6e..ad9fa4c79090f926a401d347c8e8414cea30fbf4 100755 (executable)
@@ -25,7 +25,7 @@ grep_man()
 # in the man pages
 
 regex="$rfw_regex"
 # in the man pages
 
 regex="$rfw_regex"
-test_expect_success 'para_recv: receiver options' "grep_man '$regex' recv"
+test_expect_success 'para_recv: receiver options' "grep_man 'RECEIVERS' recv"
 test_expect_success 'para_filter: filter options' "grep_man '$regex' filter"
 test_expect_success 'para_write: writer options' "grep_man '$regex' write"
 test_require_objects "audiod"
 test_expect_success 'para_filter: filter options' "grep_man '$regex' filter"
 test_expect_success 'para_write: writer options' "grep_man '$regex' write"
 test_require_objects "audiod"
@@ -33,7 +33,7 @@ if [[ -n "$result" ]]; then
        test_skip 'para_audiod' "missing object(s): $result"
 else
        test_expect_success 'para_audiod: receivers' \
        test_skip 'para_audiod' "missing object(s): $result"
 else
        test_expect_success 'para_audiod: receivers' \
-               "grep_man 'Options for the http receiver' audiod"
+               "grep_man 'RECEIVERS' audiod"
        test_expect_success 'para_audiod: filters' \
                "grep_man 'Options for the compress filter' audiod"
        test_expect_success 'para_audiod: writers' \
        test_expect_success 'para_audiod: filters' \
                "grep_man 'Options for the compress filter' audiod"
        test_expect_success 'para_audiod: writers' \
index b803b4976b52d0e89fdae2c3ee7edbdb8a0a311b..a5dfc8794f6bab030a2c29c7d48e42961c9c9e02 100644 (file)
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include <sys/un.h>
 #include <netdb.h>
+#include <lopsub.h>
 
 
+#include "recv_cmd.lsg.h"
 #include "para.h"
 #include "error.h"
 #include "portable_io.h"
 #include "list.h"
 #include "sched.h"
 #include "para.h"
 #include "error.h"
 #include "portable_io.h"
 #include "list.h"
 #include "sched.h"
-#include "ggo.h"
 #include "buffer_tree.h"
 #include "recv.h"
 #include "buffer_tree.h"
 #include "recv.h"
-#include "udp_recv.cmdline.h"
 #include "string.h"
 #include "net.h"
 #include "fd.h"
 #include "string.h"
 #include "net.h"
 #include "fd.h"
@@ -103,13 +103,6 @@ static void udp_recv_close(struct receiver_node *rn)
        btr_pool_free(rn->btrp);
 }
 
        btr_pool_free(rn->btrp);
 }
 
-static void *udp_recv_parse_config(int argc, char **argv)
-{
-       struct udp_recv_args_info *tmp = para_calloc(sizeof(*tmp));
-       udp_recv_cmdline_parser(argc, argv, tmp);
-       return tmp;
-}
-
 /*
  * Perform AF-independent joining of multicast receive addresses.
  *
 /*
  * Perform AF-independent joining of multicast receive addresses.
  *
@@ -173,58 +166,33 @@ err:
 
 static int udp_recv_open(struct receiver_node *rn)
 {
 
 static int udp_recv_open(struct receiver_node *rn)
 {
-       struct udp_recv_args_info *c = rn->conf;
-       char  *iface = c->iface_given ? c->iface_arg : NULL;
+       struct lls_parse_result *lpr = rn->lpr;
+       const char *iface = RECV_CMD_OPT_STRING_VAL(UDP, IFACE, lpr);
+       const char *host = RECV_CMD_OPT_STRING_VAL(UDP, HOST, lpr);
+       uint32_t port = RECV_CMD_OPT_UINT32_VAL(UDP, PORT, lpr);
        int ret;
 
        int ret;
 
-       ret = makesock(IPPROTO_UDP, 1, c->host_arg, c->port_arg, NULL);
+       ret = makesock(IPPROTO_UDP, 1, host, port, NULL);
        if (ret < 0)
        if (ret < 0)
-               goto err;
+               return ret;
        rn->fd = ret;
        rn->fd = ret;
-
        ret = mcast_receiver_setup(rn->fd, iface);
        ret = mcast_receiver_setup(rn->fd, iface);
-       if (ret < 0) {
-               close(rn->fd);
+       if (ret < 0)
                goto err;
                goto err;
-       }
-
        ret = mark_fd_nonblocking(rn->fd);
        ret = mark_fd_nonblocking(rn->fd);
-       if (ret < 0) {
-               close(rn->fd);
+       if (ret < 0)
                goto err;
                goto err;
-       }
-       PARA_INFO_LOG("receiving from %s:%d, fd=%d\n", c->host_arg,
-               c->port_arg, rn->fd);
+       PARA_INFO_LOG("receiving from %s:%u, fd=%d\n", host, port, rn->fd);
        rn->btrp = btr_pool_new("udp_recv", 320 * 1024);
        return rn->fd;
 err:
        rn->btrp = btr_pool_new("udp_recv", 320 * 1024);
        return rn->fd;
 err:
+       close(rn->fd);
        return ret;
 }
 
        return ret;
 }
 
-static void udp_recv_free_config(void *conf)
-{
-       udp_recv_cmdline_parser_free(conf);
-       free(conf);
-}
-
-/**
- * The init function of the udp receiver.
- *
- * \param r Pointer to the receiver struct to initialize.
- *
- * Initialize all function pointers of \a r.
- */
-void udp_recv_init(struct receiver *r)
-{
-       struct udp_recv_args_info dummy;
-
-       udp_recv_cmdline_parser_init(&dummy);
-       r->open = udp_recv_open;
-       r->close = udp_recv_close;
-       r->pre_select = udp_recv_pre_select;
-       r->post_select = udp_recv_post_select;
-       r->parse_config = udp_recv_parse_config;
-       r->free_config = udp_recv_free_config;
-       r->help = (struct ggo_help)DEFINE_GGO_HELP(udp_recv);
-       udp_recv_cmdline_parser_free(&dummy);
-}
+const struct receiver lsg_recv_cmd_com_udp_user_data = {
+       .open = udp_recv_open,
+       .close = udp_recv_close,
+       .pre_select = udp_recv_pre_select,
+       .post_select = udp_recv_post_select,
+};