Remove ->init() of struct receiver.
[paraslash.git] / filter.c
1 /* Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file filter.c The stand-alone filter program. */
4
5 #include <regex.h>
6 #include <lopsub.h>
7
8 #include "filter.lsg.h"
9 #include "filter_cmd.lsg.h"
10 #include "para.h"
11 #include "list.h"
12 #include "lsu.h"
13 #include "sched.h"
14 #include "buffer_tree.h"
15 #include "filter.h"
16 #include "string.h"
17 #include "stdin.h"
18 #include "stdout.h"
19 #include "error.h"
20 #include "fd.h"
21 #include "version.h"
22
23 /** Array of error strings. */
24 DEFINE_PARA_ERRLIST;
25 static struct lls_parse_result *lpr; /* command line options */
26
27 #define CMD_PTR (lls_cmd(0, filter_suite))
28 #define OPT_RESULT(_name) \
29         (lls_opt_result(LSG_FILTER_PARA_FILTER_OPT_ ## _name, lpr))
30 #define OPT_GIVEN(_name) (lls_opt_given(OPT_RESULT(_name)))
31 #define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
32
33 /** The list of all status items used by para_{server,audiod,gui}. */
34 const char *status_item_list[] = {STATUS_ITEMS};
35
36 /**
37  * Dummy version which only contains NULL pointers.
38  *
39  * This is used by the amp filter which first tries to obtain the amplification
40  * value from an element in this array.
41  */
42 char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
43
44 /** The task that reads from stdin. */
45 static struct stdin_task stdin_task_struct;
46 /** pointer to the stdin task. */
47 static struct stdin_task *sit = &stdin_task_struct;
48
49 /** The task that writes converted data to stdout. */
50 static struct stdout_task stdout_task_struct;
51 /** Pointer to the stdout task. */
52 static struct stdout_task *sot = &stdout_task_struct;
53
54 static int loglevel;
55 INIT_STDERR_LOGGING(loglevel);
56
57 static void handle_help_flag(void)
58 {
59         char *help;
60
61         if (OPT_GIVEN(DETAILED_HELP))
62                 help = lls_long_help(CMD_PTR);
63         else if (OPT_GIVEN(HELP))
64                 help = lls_short_help(CMD_PTR);
65         else
66                 return;
67         printf("%s\n", help);
68         free(help);
69         print_filter_helps(OPT_GIVEN(DETAILED_HELP));
70         exit(EXIT_SUCCESS);
71 }
72
73 static int parse_config(void)
74 {
75         int ret;
76
77         version_handle_flag("filter", OPT_GIVEN(VERSION));
78         handle_help_flag();
79         ret = lsu_merge_config_file_options(NULL, "filter.conf",
80                 &lpr, CMD_PTR, filter_suite, 0 /* default flags */);
81         if (ret < 0)
82                 return ret;
83         loglevel = OPT_UINT32_VAL(LOGLEVEL);
84         if (!OPT_GIVEN(FILTER)) {
85                 print_filter_list();
86                 exit(EXIT_SUCCESS);
87         }
88         return 1;
89 }
90
91 /**
92  * The main function of para_filter.
93  *
94  * Para_filter reads data from stdin, converts it by using a chain
95  * of filters (specified on the command line) and writes the resulting
96  * data to stdout.
97  *
98  * \param argc Number of command line options.
99  * \param argv Vector of arguments.
100  *
101  * \return \a EXIT_SUCCESS on success, EXIT_FAILURE on errors.
102  */
103 int main(int argc, char *argv[])
104 {
105         static struct sched s;
106         int i, ret;
107         const struct filter *f;
108         struct btr_node *parent;
109         struct filter_node **fns;
110         struct lls_parse_result *filter_lpr; /* per-filter options */
111         char *errctx;
112
113         ret = lls(lls_parse(argc, argv, CMD_PTR, &lpr, &errctx));
114         if (ret < 0)
115                 goto out;
116         ret = parse_config();
117         if (ret < 0)
118                 goto free_lpr;
119         sit->btrn = btr_new_node(&(struct btr_node_description)
120                 EMBRACE(.name = "stdin"));
121         stdin_task_register(sit, &s);
122
123         fns = para_malloc(OPT_GIVEN(FILTER) * sizeof(*fns));
124         for (i = 0, parent = sit->btrn; i < OPT_GIVEN(FILTER); i++) {
125                 const char *fa = lls_string_val(i, OPT_RESULT(FILTER));
126                 const char *name;
127                 struct filter_node *fn;
128                 struct task_info ti;
129
130                 fn = fns[i] = para_calloc(sizeof(*fn));
131                 fn->filter_num = filter_setup(fa, &fn->conf, &filter_lpr);
132                 name = filter_name(fn->filter_num);
133                 fn->lpr = filter_lpr;
134                 PARA_DEBUG_LOG("filter #%d: %s\n", i, name);
135                 f = filter_get(fn->filter_num);
136                 fn->btrn = btr_new_node(&(struct btr_node_description)
137                         EMBRACE(.name = name, .parent = parent,
138                         .handler = f->execute, .context = fn));
139                 ti.name = name;
140                 ti.pre_select = f->pre_select;
141                 ti.post_select = f->post_select;
142                 ti.context = fn;
143                 if (f->open)
144                         f->open(fn);
145                 fn->task = task_register(&ti, &s);
146                 parent = fn->btrn;
147         }
148         sot->btrn = btr_new_node(&(struct btr_node_description)
149                 EMBRACE(.name = "stdout", .parent = parent));
150         stdout_task_register(sot, &s);
151
152         s.default_timeout.tv_sec = 1;
153         s.default_timeout.tv_usec = 0;
154         btr_log_tree(sit->btrn, LL_INFO);
155         ret = schedule(&s);
156         sched_shutdown(&s);
157         for (i--; i >= 0; i--) {
158                 struct filter_node *fn = fns[i];
159
160                 f = filter_get(fn->filter_num);
161                 if (f->close)
162                         f->close(fn);
163                 btr_remove_node(&fn->btrn);
164                 if (f->teardown)
165                         f->teardown(fn->lpr, fn->conf);
166                 free(fn);
167         }
168         free(fns);
169         btr_remove_node(&sit->btrn);
170         btr_remove_node(&sot->btrn);
171 free_lpr:
172         lls_free_parse_result(lpr, CMD_PTR);
173 out:
174         if (ret < 0) {
175                 if (errctx)
176                         PARA_ERROR_LOG("%s\n", errctx);
177                 free(errctx);
178                 PARA_ERROR_LOG("%s\n", para_strerror(-ret));
179         }
180         exit(ret < 0? EXIT_FAILURE : EXIT_SUCCESS);
181 }