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