gui: Remove --timeout.
[paraslash.git] / write_common.c
1 /*
2  * Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file write_common.c common functions of para_audiod and para_write */
8
9 #include <regex.h>
10 #include <lopsub.h>
11
12 #include "write_cmd.lsg.h"
13 #include "para.h"
14 #include "string.h"
15 #include "list.h"
16 #include "sched.h"
17 #include "buffer_tree.h"
18 #include "write.h"
19 #include "error.h"
20
21 /** Loop over all writers. */
22 #define FOR_EACH_WRITER(i) for (i = 1; lls_cmd(i, write_cmd_suite); i++)
23
24
25 static inline bool writer_supported(int wid)
26 {
27         return lls_user_data(WRITE_CMD(wid));
28 }
29
30 /* simply return the first available writer */
31 static int default_writer_id(void)
32 {
33         int i;
34
35         FOR_EACH_WRITER(i)
36                 if (writer_supported(i))
37                         return i;
38         assert(0); /* the file writer should always be available */
39 }
40
41 /**
42  * Return the writer structure from a writer ID.
43  *
44  * \param wid If non-positive, a pointer to the default writer is returned.
45  *
46  * \return Pointer to a (constant) struct writer.
47  */
48 const struct writer *writer_get(int wid)
49 {
50         if (wid < 0)
51                 wid = default_writer_id();
52         return lls_user_data(WRITE_CMD(wid));
53 }
54
55 /**
56  * Return name of the writer identified by a writer ID.
57  *
58  * \param wid If non-positive, the name of the default writer is returned.
59  *
60  * \return The returned buffer must not be freed by the caller.
61  */
62 const char *writer_name(int wid)
63 {
64         if (wid <= 0)
65                 wid = default_writer_id();
66         return lls_command_name(WRITE_CMD(wid));
67 }
68
69 /**
70  * Check if the given string is a valid command line for any writer.
71  *
72  * \param wa String of the form writer_name options.
73  * \param lprp Contains the parsed command line on success.
74  *
75  * If wa is \p NULL, the (configuration-dependent) default writer is assumed.
76  * Otherwise, the function checks whether \a wa starts with the name of a
77  * supported writer. If a valid writer name was found, the rest of the command
78  * line is passed to the config parser of this writer.
79  *
80  * \return On success, the positive writer ID is returned. Otherwise the
81  * function prints an error message and calls exit().
82  */
83 int check_writer_arg_or_die(const char *wa, struct lls_parse_result **lprp)
84 {
85         int ret, writer_num, argc;
86         char **argv = NULL, *errctx = NULL;
87         const struct lls_command *cmd;
88
89         if (!wa || !*wa) {
90                 writer_num = default_writer_id();
91                 cmd = WRITE_CMD(writer_num);
92                 argv = para_malloc(2 * sizeof(char *));
93                 argc = 1;
94                 argv[0] = para_strdup(lls_command_name(cmd));
95                 argv[1] = NULL;
96                 goto parse;
97         }
98         ret = create_argv(wa, " \t\n", &argv);
99         if (ret < 0)
100                 goto fail;
101         argc = ret;
102         ret = lls(lls_lookup_subcmd(argv[0], write_cmd_suite, &errctx));
103         if (ret < 0)
104                 goto free_argv;
105         writer_num = ret;
106         cmd = WRITE_CMD(writer_num);
107         if (!writer_supported(writer_num)) {
108                 ret = -ERRNO_TO_PARA_ERROR(EINVAL);
109                 errctx = make_message("%s writer is not supported",
110                         lls_command_name(cmd));
111                 goto free_argv;
112         }
113 parse:
114         ret = lls(lls_parse(argc, argv, cmd, lprp, &errctx));
115         if (ret >= 0)
116                 ret = writer_num;
117 free_argv:
118         free_argv(argv);
119         if (ret >= 0)
120                 return ret;
121 fail:
122         if (errctx)
123                 PARA_ERROR_LOG("%s\n", errctx);
124         free(errctx);
125         PARA_EMERG_LOG("%s\n", para_strerror(-ret));
126         exit(EXIT_FAILURE);
127 }
128
129 /**
130  * Open a writer node and register the corresponding task.
131  *
132  * \param wn The writer node to open.
133  * \param parent The parent btr node (the source for the writer node).
134  * \param s The scheduler instance to register the task to.
135  */
136 void register_writer_node(struct writer_node *wn, struct btr_node *parent,
137                 struct sched *s)
138 {
139         const struct writer *w = writer_get(wn->wid);
140
141         wn->btrn = btr_new_node(&(struct btr_node_description)
142                 EMBRACE(.name = writer_name(wn->wid), .parent = parent,
143                 .handler = w->execute, .context = wn));
144         wn->task = task_register(&(struct task_info) {
145                 .name = writer_name(wn->wid),
146                 .pre_select = w->pre_select,
147                 .post_select = w->post_select,
148                 .context = wn,
149         }, s);
150 }
151
152 /**
153  * Print the help text of all writers to stdout.
154  *
155  * \param detailed Whether to print the short or the detailed help.
156  */
157 void print_writer_helps(bool detailed)
158 {
159         int i;
160
161         printf("\nAvailable writers: ");
162         FOR_EACH_WRITER(i) {
163                 if (!writer_supported(i))
164                         continue;
165                 printf("%s%s", i? " " : "", writer_name(i));
166         }
167         printf("\n");
168         FOR_EACH_WRITER(i) {
169                 const struct lls_command *cmd = WRITE_CMD(i);
170                 char *help;
171                 if (!writer_supported(i))
172                         continue;
173                 help = detailed? lls_long_help(cmd) : lls_short_help(cmd);
174                 if (!help)
175                         continue;
176                 printf("%s\n", help);
177                 free(help);
178         }
179 }
180
181 static void get_btr_value(struct btr_node *btrn, const char *cmd,
182                 int32_t *result)
183 {
184         char *buf = NULL;
185         int ret = btr_exec_up(btrn, cmd, &buf);
186
187         if (ret < 0) {
188                 /*
189                  * This really should not happen. It means one of our parent
190                  * nodes died unexpectedly. Proceed with fingers crossed.
191                  */
192                 PARA_CRIT_LOG("cmd %s: %s\n", cmd, para_strerror(-ret));
193                 *result = 0;
194                 return;
195         }
196         ret = para_atoi32(buf, result);
197         assert(ret >= 0);
198         free(buf);
199 }
200
201 /**
202  * Ask parent btr nodes for the sample rate of the current stream.
203  *
204  * \param btrn Where to start the search.
205  * \param result Filled in by this function.
206  *
207  * This function is assumed to succeed and terminates on errors.
208  */
209 void get_btr_sample_rate(struct btr_node *btrn, int32_t *result)
210 {
211         get_btr_value(btrn, "sample_rate", result);
212 }
213
214 /**
215  * Ask parent btr nodes for the channel count of the current stream.
216  *
217  * \param btrn See \ref get_btr_sample_rate.
218  * \param result See \ref get_btr_sample_rate.
219  */
220 void get_btr_channels(struct btr_node *btrn, int32_t *result)
221 {
222         get_btr_value(btrn, "channels", result);
223 }
224
225 /**
226  * Ask parent btr nodes for the number of bits per sample and the byte sex.
227  *
228  * \param btrn See \ref get_btr_sample_rate.
229  * \param result Contains the sample format as an enum sample_format type.
230  */
231 void get_btr_sample_format(struct btr_node *btrn, int32_t *result)
232 {
233         get_btr_value(btrn, "sample_format", result);
234 }