]> code.delx.au - pulseaudio/blob - src/pulsecore/cli-command.c
minor reformatting
[pulseaudio] / src / pulsecore / cli-command.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
13
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <unistd.h>
35
36 #include <pulse/xmalloc.h>
37
38 #include <pulsecore/module.h>
39 #include <pulsecore/sink.h>
40 #include <pulsecore/source.h>
41 #include <pulsecore/client.h>
42 #include <pulsecore/sink-input.h>
43 #include <pulsecore/source-output.h>
44 #include <pulsecore/tokenizer.h>
45 #include <pulsecore/strbuf.h>
46 #include <pulsecore/namereg.h>
47 #include <pulsecore/cli-text.h>
48 #include <pulsecore/core-scache.h>
49 #include <pulsecore/sample-util.h>
50 #include <pulsecore/sound-file.h>
51 #include <pulsecore/play-memchunk.h>
52 #include <pulsecore/autoload.h>
53 #include <pulsecore/sound-file-stream.h>
54 #include <pulsecore/props.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/core-error.h>
57
58 #include "cli-command.h"
59
60 struct command {
61 const char *name;
62 int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail);
63 const char *help;
64 unsigned args;
65 };
66
67 #define META_INCLUDE ".include"
68 #define META_FAIL ".fail"
69 #define META_NOFAIL ".nofail"
70 #define META_IFEXISTS ".ifexists"
71 #define META_ELSE ".else"
72 #define META_ENDIF ".endif"
73
74 enum {
75 IFSTATE_NONE = -1,
76 IFSTATE_FALSE = 0,
77 IFSTATE_TRUE = 1,
78 };
79
80 /* Prototypes for all available commands */
81 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
82 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
83 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
84 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
85 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
86 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
87 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
88 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
89 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
90 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
91 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
92 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
93 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
94 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
95 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
96 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
97 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
98 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
99 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
100 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
101 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
102 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
103 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
104 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
105 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
106 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
107 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
108 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
109 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
110 static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
111 static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
112 static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
113 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
114 static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
115 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
116 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
117 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
118 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
119 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
120 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
121
122 /* A method table for all available commands */
123
124 static const struct command commands[] = {
125 { "exit", pa_cli_command_exit, "Terminate the daemon", 1 },
126 { "help", pa_cli_command_help, "Show this help", 1 },
127 { "list-modules", pa_cli_command_modules, "List loaded modules", 1 },
128 { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 },
129 { "list-sources", pa_cli_command_sources, "List loaded sources", 1 },
130 { "list-clients", pa_cli_command_clients, "List loaded clients", 1 },
131 { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 },
132 { "list-source-outputs", pa_cli_command_source_outputs, "List source outputs", 1 },
133 { "stat", pa_cli_command_stat, "Show memory block statistics", 1 },
134 { "info", pa_cli_command_info, "Show comprehensive status", 1 },
135 { "ls", pa_cli_command_info, NULL, 1 },
136 { "list", pa_cli_command_info, NULL, 1 },
137 { "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3},
138 { "unload-module", pa_cli_command_unload, "Unload a module (args: index)", 2},
139 { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3},
140 { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index, volume)", 3},
141 { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3},
142 { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, bool)", 3},
143 { "set-sink-input-mute", pa_cli_command_sink_input_mute, "Set the mute switch of a sink input (args: index, bool)", 3},
144 { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, bool)", 3},
145 { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2},
146 { "set-default-source", pa_cli_command_source_default, "Set the default source (args: index|name)", 2},
147 { "kill-client", pa_cli_command_kill_client, "Kill a client (args: index)", 2},
148 { "kill-sink-input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2},
149 { "kill-source-output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
150 { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1},
151 { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3},
152 { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2},
153 { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3},
154 { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3},
155 { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
156 { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3},
157 { "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1},
158 { "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4},
159 { "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4},
160 { "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2},
161 { "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2},
162 { "dump", pa_cli_command_dump, "Dump daemon configuration", 1},
163 { "list-props", pa_cli_command_list_props, NULL, 1},
164 { "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3},
165 { "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
166 { "vacuum", pa_cli_command_vacuum, NULL, 1},
167 { "suspend-sink", pa_cli_command_suspend_sink, "Suspend sink (args: index|name, bool)", 3},
168 { "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3},
169 { "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2},
170 { NULL, NULL, NULL, 0 }
171 };
172
173 static const char whitespace[] = " \t\n\r";
174 static const char linebreak[] = "\n\r";
175
176 static uint32_t parse_index(const char *n) {
177 uint32_t idx;
178
179 if (pa_atou(n, &idx) < 0)
180 return (uint32_t) PA_IDXSET_INVALID;
181
182 return idx;
183 }
184
185 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
186 assert(c && c->mainloop && t);
187 c->mainloop->quit(c->mainloop, 0);
188 return 0;
189 }
190
191 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
192 const struct command*command;
193 assert(c && t && buf);
194
195 pa_strbuf_puts(buf, "Available commands:\n");
196
197 for (command = commands; command->name; command++)
198 if (command->help)
199 pa_strbuf_printf(buf, " %-25s %s\n", command->name, command->help);
200 return 0;
201 }
202
203 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
204 char *s;
205 assert(c && t);
206 s = pa_module_list_to_string(c);
207 assert(s);
208 pa_strbuf_puts(buf, s);
209 pa_xfree(s);
210 return 0;
211 }
212
213 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
214 char *s;
215 assert(c && t);
216 s = pa_client_list_to_string(c);
217 assert(s);
218 pa_strbuf_puts(buf, s);
219 pa_xfree(s);
220 return 0;
221 }
222
223 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
224 char *s;
225 assert(c && t);
226 s = pa_sink_list_to_string(c);
227 assert(s);
228 pa_strbuf_puts(buf, s);
229 pa_xfree(s);
230 return 0;
231 }
232
233 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
234 char *s;
235 assert(c && t);
236 s = pa_source_list_to_string(c);
237 assert(s);
238 pa_strbuf_puts(buf, s);
239 pa_xfree(s);
240 return 0;
241 }
242
243 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
244 char *s;
245 assert(c && t);
246 s = pa_sink_input_list_to_string(c);
247 assert(s);
248 pa_strbuf_puts(buf, s);
249 pa_xfree(s);
250 return 0;
251 }
252
253 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
254 char *s;
255 assert(c && t);
256 s = pa_source_output_list_to_string(c);
257 assert(s);
258 pa_strbuf_puts(buf, s);
259 pa_xfree(s);
260 return 0;
261 }
262
263 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
264 char s[256];
265 const pa_mempool_stat *stat;
266 unsigned k;
267 const char *def_sink, *def_source;
268
269 static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = {
270 [PA_MEMBLOCK_POOL] = "POOL",
271 [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL",
272 [PA_MEMBLOCK_APPENDED] = "APPENDED",
273 [PA_MEMBLOCK_USER] = "USER",
274 [PA_MEMBLOCK_FIXED] = "FIXED",
275 [PA_MEMBLOCK_IMPORTED] = "IMPORTED",
276 };
277
278 assert(c);
279 assert(t);
280
281 stat = pa_mempool_get_stat(c->mempool);
282
283 pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n",
284 (unsigned) pa_atomic_load(&stat->n_allocated),
285 pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->allocated_size)));
286
287 pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n",
288 (unsigned) pa_atomic_load(&stat->n_accumulated),
289 pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->accumulated_size)));
290
291 pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n",
292 (unsigned) pa_atomic_load(&stat->n_imported),
293 pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->imported_size)));
294
295 pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n",
296 (unsigned) pa_atomic_load(&stat->n_exported),
297 pa_bytes_snprint(s, sizeof(s), (size_t) pa_atomic_load(&stat->exported_size)));
298
299 pa_strbuf_printf(buf, "Total sample cache size: %s.\n",
300 pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)));
301
302 pa_strbuf_printf(buf, "Default sample spec: %s\n",
303 pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec));
304
305 def_sink = pa_namereg_get_default_sink_name(c);
306 def_source = pa_namereg_get_default_source_name(c);
307 pa_strbuf_printf(buf, "Default sink name: %s\n"
308 "Default source name: %s\n",
309 def_sink ? def_sink : "none",
310 def_source ? def_source : "none");
311
312 for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++)
313 pa_strbuf_printf(buf,
314 "Memory blocks of type %s: %u allocated/%u accumulated.\n",
315 type_table[k],
316 (unsigned) pa_atomic_load(&stat->n_allocated_by_type[k]),
317 (unsigned) pa_atomic_load(&stat->n_accumulated_by_type[k]));
318
319 return 0;
320 }
321
322 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
323 assert(c && t);
324 pa_cli_command_stat(c, t, buf, fail);
325 pa_cli_command_modules(c, t, buf, fail);
326 pa_cli_command_sinks(c, t, buf, fail);
327 pa_cli_command_sources(c, t, buf, fail);
328 pa_cli_command_clients(c, t, buf, fail);
329 pa_cli_command_sink_inputs(c, t, buf, fail);
330 pa_cli_command_source_outputs(c, t, buf, fail);
331 pa_cli_command_scache_list(c, t, buf, fail);
332 pa_cli_command_autoload_list(c, t, buf, fail);
333 return 0;
334 }
335
336 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
337 pa_module *m;
338 const char *name;
339 assert(c && t);
340
341 if (!(name = pa_tokenizer_get(t, 1))) {
342 pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
343 return -1;
344 }
345
346 if (!(m = pa_module_load(c, name, pa_tokenizer_get(t, 2)))) {
347 pa_strbuf_puts(buf, "Module load failed.\n");
348 return -1;
349 }
350
351 return 0;
352 }
353
354 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
355 pa_module *m;
356 uint32_t idx;
357 const char *i;
358 char *e;
359 assert(c && t);
360
361 if (!(i = pa_tokenizer_get(t, 1))) {
362 pa_strbuf_puts(buf, "You need to specify the module index.\n");
363 return -1;
364 }
365
366 idx = (uint32_t) strtoul(i, &e, 10);
367 if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) {
368 pa_strbuf_puts(buf, "Invalid module index.\n");
369 return -1;
370 }
371
372 pa_module_unload_request(m);
373 return 0;
374 }
375
376 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
377 const char *n, *v;
378 pa_sink *sink;
379 uint32_t volume;
380 pa_cvolume cvolume;
381
382 if (!(n = pa_tokenizer_get(t, 1))) {
383 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
384 return -1;
385 }
386
387 if (!(v = pa_tokenizer_get(t, 2))) {
388 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
389 return -1;
390 }
391
392 if (pa_atou(v, &volume) < 0) {
393 pa_strbuf_puts(buf, "Failed to parse volume.\n");
394 return -1;
395 }
396
397 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
398 pa_strbuf_puts(buf, "No sink found by this name or index.\n");
399 return -1;
400 }
401
402 pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
403 pa_sink_set_volume(sink, &cvolume);
404 return 0;
405 }
406
407 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
408 const char *n, *v;
409 pa_sink_input *si;
410 pa_volume_t volume;
411 pa_cvolume cvolume;
412 uint32_t idx;
413
414 if (!(n = pa_tokenizer_get(t, 1))) {
415 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
416 return -1;
417 }
418
419 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
420 pa_strbuf_puts(buf, "Failed to parse index.\n");
421 return -1;
422 }
423
424 if (!(v = pa_tokenizer_get(t, 2))) {
425 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
426 return -1;
427 }
428
429 if (pa_atou(v, &volume) < 0) {
430 pa_strbuf_puts(buf, "Failed to parse volume.\n");
431 return -1;
432 }
433
434 if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
435 pa_strbuf_puts(buf, "No sink input found with this index.\n");
436 return -1;
437 }
438
439 pa_cvolume_set(&cvolume, si->sample_spec.channels, volume);
440 pa_sink_input_set_volume(si, &cvolume);
441 return 0;
442 }
443
444 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
445 const char *n, *v;
446 pa_source *source;
447 uint32_t volume;
448 pa_cvolume cvolume;
449
450 if (!(n = pa_tokenizer_get(t, 1))) {
451 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
452 return -1;
453 }
454
455 if (!(v = pa_tokenizer_get(t, 2))) {
456 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
457 return -1;
458 }
459
460 if (pa_atou(v, &volume) < 0) {
461 pa_strbuf_puts(buf, "Failed to parse volume.\n");
462 return -1;
463 }
464
465 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
466 pa_strbuf_puts(buf, "No source found by this name or index.\n");
467 return -1;
468 }
469
470 pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
471 pa_source_set_volume(source, &cvolume);
472 return 0;
473 }
474
475 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
476 const char *n, *m;
477 pa_sink *sink;
478 int mute;
479
480 if (!(n = pa_tokenizer_get(t, 1))) {
481 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
482 return -1;
483 }
484
485 if (!(m = pa_tokenizer_get(t, 2))) {
486 pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
487 return -1;
488 }
489
490 if (pa_atoi(m, &mute) < 0) {
491 pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
492 return -1;
493 }
494
495 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
496 pa_strbuf_puts(buf, "No sink found by this name or index.\n");
497 return -1;
498 }
499
500 pa_sink_set_mute(sink, mute);
501 return 0;
502 }
503
504 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
505 const char *n, *m;
506 pa_source *source;
507 int mute;
508
509 if (!(n = pa_tokenizer_get(t, 1))) {
510 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
511 return -1;
512 }
513
514 if (!(m = pa_tokenizer_get(t, 2))) {
515 pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
516 return -1;
517 }
518
519 if (pa_atoi(m, &mute) < 0) {
520 pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
521 return -1;
522 }
523
524 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
525 pa_strbuf_puts(buf, "No sink found by this name or index.\n");
526 return -1;
527 }
528
529 pa_source_set_mute(source, mute);
530 return 0;
531 }
532
533 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
534 const char *n, *v;
535 pa_sink_input *si;
536 uint32_t idx;
537 int mute;
538
539 if (!(n = pa_tokenizer_get(t, 1))) {
540 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
541 return -1;
542 }
543
544 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
545 pa_strbuf_puts(buf, "Failed to parse index.\n");
546 return -1;
547 }
548
549 if (!(v = pa_tokenizer_get(t, 2))) {
550 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
551 return -1;
552 }
553
554 if (pa_atoi(v, &mute) < 0) {
555 pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
556 return -1;
557 }
558
559 if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
560 pa_strbuf_puts(buf, "No sink input found with this index.\n");
561 return -1;
562 }
563
564 pa_sink_input_set_mute(si, mute);
565 return 0;
566 }
567
568 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
569 const char *n;
570 assert(c && t);
571
572 if (!(n = pa_tokenizer_get(t, 1))) {
573 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
574 return -1;
575 }
576
577 pa_namereg_set_default(c, n, PA_NAMEREG_SINK);
578 return 0;
579 }
580
581 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
582 const char *n;
583 assert(c && t);
584
585 if (!(n = pa_tokenizer_get(t, 1))) {
586 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
587 return -1;
588 }
589
590 pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE);
591 return 0;
592 }
593
594 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
595 const char *n;
596 pa_client *client;
597 uint32_t idx;
598 assert(c && t);
599
600 if (!(n = pa_tokenizer_get(t, 1))) {
601 pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
602 return -1;
603 }
604
605 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
606 pa_strbuf_puts(buf, "Failed to parse index.\n");
607 return -1;
608 }
609
610 if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
611 pa_strbuf_puts(buf, "No client found by this index.\n");
612 return -1;
613 }
614
615 pa_client_kill(client);
616 return 0;
617 }
618
619 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
620 const char *n;
621 pa_sink_input *sink_input;
622 uint32_t idx;
623 assert(c && t);
624
625 if (!(n = pa_tokenizer_get(t, 1))) {
626 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
627 return -1;
628 }
629
630 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
631 pa_strbuf_puts(buf, "Failed to parse index.\n");
632 return -1;
633 }
634
635 if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
636 pa_strbuf_puts(buf, "No sink input found by this index.\n");
637 return -1;
638 }
639
640 pa_sink_input_kill(sink_input);
641 return 0;
642 }
643
644 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
645 const char *n;
646 pa_source_output *source_output;
647 uint32_t idx;
648 assert(c && t);
649
650 if (!(n = pa_tokenizer_get(t, 1))) {
651 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
652 return -1;
653 }
654
655 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
656 pa_strbuf_puts(buf, "Failed to parse index.\n");
657 return -1;
658 }
659
660 if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
661 pa_strbuf_puts(buf, "No source output found by this index.\n");
662 return -1;
663 }
664
665 pa_source_output_kill(source_output);
666 return 0;
667 }
668
669 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
670 char *s;
671 assert(c && t);
672 s = pa_scache_list_to_string(c);
673 assert(s);
674 pa_strbuf_puts(buf, s);
675 pa_xfree(s);
676 return 0;
677 }
678
679 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
680 const char *n, *sink_name;
681 pa_sink *sink;
682 assert(c && t && buf && fail);
683
684 if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
685 pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
686 return -1;
687 }
688
689 if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) {
690 pa_strbuf_puts(buf, "No sink by that name.\n");
691 return -1;
692 }
693
694 if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) {
695 pa_strbuf_puts(buf, "Failed to play sample.\n");
696 return -1;
697 }
698
699 return 0;
700 }
701
702 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
703 const char *n;
704 assert(c && t && buf && fail);
705
706 if (!(n = pa_tokenizer_get(t, 1))) {
707 pa_strbuf_puts(buf, "You need to specify a sample name.\n");
708 return -1;
709 }
710
711 if (pa_scache_remove_item(c, n) < 0) {
712 pa_strbuf_puts(buf, "Failed to remove sample.\n");
713 return -1;
714 }
715
716 return 0;
717 }
718
719 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
720 const char *fname, *n;
721 int r;
722 assert(c && t && buf && fail);
723
724 if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
725 pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
726 return -1;
727 }
728
729 if (strstr(pa_tokenizer_get(t, 0), "lazy"))
730 r = pa_scache_add_file_lazy(c, n, fname, NULL);
731 else
732 r = pa_scache_add_file(c, n, fname, NULL);
733
734 if (r < 0)
735 pa_strbuf_puts(buf, "Failed to load sound file.\n");
736
737 return 0;
738 }
739
740 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
741 const char *pname;
742 assert(c && t && buf && fail);
743
744 if (!(pname = pa_tokenizer_get(t, 1))) {
745 pa_strbuf_puts(buf, "You need to specify a path name.\n");
746 return -1;
747 }
748
749 if (pa_scache_add_directory_lazy(c, pname) < 0) {
750 pa_strbuf_puts(buf, "Failed to load directory.\n");
751 return -1;
752 }
753
754 return 0;
755 }
756
757 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
758 const char *fname, *sink_name;
759 pa_sink *sink;
760 assert(c && t && buf && fail);
761
762 if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
763 pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
764 return -1;
765 }
766
767 if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) {
768 pa_strbuf_puts(buf, "No sink by that name.\n");
769 return -1;
770 }
771
772
773 return pa_play_file(sink, fname, NULL);
774 }
775
776 static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
777 const char *a, *b;
778 assert(c && t && buf && fail);
779
780 if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) {
781 pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n");
782 return -1;
783 }
784
785 pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL);
786
787 return 0;
788 }
789
790 static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
791 const char *name;
792 assert(c && t && buf && fail);
793
794 if (!(name = pa_tokenizer_get(t, 1))) {
795 pa_strbuf_puts(buf, "You need to specify a device name\n");
796 return -1;
797 }
798
799 if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) {
800 pa_strbuf_puts(buf, "Failed to remove autload entry\n");
801 return -1;
802 }
803
804 return 0;
805 }
806
807 static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
808 char *s;
809 assert(c && t);
810 s = pa_autoload_list_to_string(c);
811 assert(s);
812 pa_strbuf_puts(buf, s);
813 pa_xfree(s);
814 return 0;
815 }
816
817 static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
818 assert(c && t);
819 pa_property_dump(c, buf);
820 return 0;
821 }
822
823 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
824 assert(c);
825 assert(t);
826
827 pa_mempool_vacuum(c->mempool);
828
829 return 0;
830 }
831
832 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
833 const char *n, *k;
834 pa_sink_input *si;
835 pa_sink *sink;
836 uint32_t idx;
837
838 if (!(n = pa_tokenizer_get(t, 1))) {
839 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
840 return -1;
841 }
842
843 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
844 pa_strbuf_puts(buf, "Failed to parse index.\n");
845 return -1;
846 }
847
848 if (!(k = pa_tokenizer_get(t, 2))) {
849 pa_strbuf_puts(buf, "You need to specify a sink.\n");
850 return -1;
851 }
852
853 if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
854 pa_strbuf_puts(buf, "No sink input found with this index.\n");
855 return -1;
856 }
857
858 if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK, 1))) {
859 pa_strbuf_puts(buf, "No sink found by this name or index.\n");
860 return -1;
861 }
862
863 if (pa_sink_input_move_to(si, sink, 0) < 0) {
864 pa_strbuf_puts(buf, "Moved failed.\n");
865 return -1;
866 }
867 return 0;
868 }
869
870 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
871 const char *n, *k;
872 pa_source_output *so;
873 pa_source *source;
874 uint32_t idx;
875
876 if (!(n = pa_tokenizer_get(t, 1))) {
877 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
878 return -1;
879 }
880
881 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
882 pa_strbuf_puts(buf, "Failed to parse index.\n");
883 return -1;
884 }
885
886 if (!(k = pa_tokenizer_get(t, 2))) {
887 pa_strbuf_puts(buf, "You need to specify a source.\n");
888 return -1;
889 }
890
891 if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
892 pa_strbuf_puts(buf, "No source output found with this index.\n");
893 return -1;
894 }
895
896 if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE, 1))) {
897 pa_strbuf_puts(buf, "No source found by this name or index.\n");
898 return -1;
899 }
900
901 if (pa_source_output_move_to(so, source) < 0) {
902 pa_strbuf_puts(buf, "Moved failed.\n");
903 return -1;
904 }
905 return 0;
906 }
907
908 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
909 const char *n, *m;
910 pa_sink *sink;
911 int suspend;
912
913 if (!(n = pa_tokenizer_get(t, 1))) {
914 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
915 return -1;
916 }
917
918 if (!(m = pa_tokenizer_get(t, 2))) {
919 pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
920 return -1;
921 }
922
923 if (pa_atoi(m, &suspend) < 0) {
924 pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
925 return -1;
926 }
927
928 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
929 pa_strbuf_puts(buf, "No sink found by this name or index.\n");
930 return -1;
931 }
932
933 pa_sink_suspend(sink, suspend);
934 return 0;
935 }
936
937 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
938 const char *n, *m;
939 pa_source *source;
940 int suspend;
941
942 if (!(n = pa_tokenizer_get(t, 1))) {
943 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
944 return -1;
945 }
946
947 if (!(m = pa_tokenizer_get(t, 2))) {
948 pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
949 return -1;
950 }
951
952 if (pa_atoi(m, &suspend) < 0) {
953 pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
954 return -1;
955 }
956
957 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
958 pa_strbuf_puts(buf, "No source found by this name or index.\n");
959 return -1;
960 }
961
962 pa_source_suspend(source, suspend);
963 return 0;
964 }
965
966 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
967 const char *m;
968 int suspend;
969 int ret;
970
971 if (!(m = pa_tokenizer_get(t, 1))) {
972 pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
973 return -1;
974 }
975
976 if (pa_atoi(m, &suspend) < 0) {
977 pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
978 return -1;
979 }
980
981 ret = - (pa_sink_suspend_all(c, suspend) < 0);
982 if (pa_source_suspend_all(c, suspend) < 0)
983 ret = -1;
984
985 if (ret < 0)
986 pa_strbuf_puts(buf, "Failed to resume/suspend all sinks/sources.\n");
987
988 return 0;
989 }
990
991 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
992 pa_module *m;
993 pa_sink *sink;
994 pa_source *source;
995 int nl;
996 const char *p;
997 uint32_t idx;
998 char txt[256];
999 time_t now;
1000 void *i;
1001 pa_autoload_entry *a;
1002
1003 assert(c && t);
1004
1005 time(&now);
1006
1007 #ifdef HAVE_CTIME_R
1008 pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
1009 #else
1010 pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
1011 #endif
1012
1013 for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) {
1014 if (m->auto_unload)
1015 continue;
1016
1017 pa_strbuf_printf(buf, "load-module %s", m->name);
1018
1019 if (m->argument)
1020 pa_strbuf_printf(buf, " %s", m->argument);
1021
1022 pa_strbuf_puts(buf, "\n");
1023 }
1024
1025 nl = 0;
1026
1027 for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
1028 if (sink->module && sink->module->auto_unload)
1029 continue;
1030
1031 if (!nl) {
1032 pa_strbuf_puts(buf, "\n");
1033 nl = 1;
1034 }
1035
1036 pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink)));
1037 pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink));
1038 }
1039
1040 for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
1041 if (source->module && source->module->auto_unload)
1042 continue;
1043
1044 if (!nl) {
1045 pa_strbuf_puts(buf, "\n");
1046 nl = 1;
1047 }
1048
1049 pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source)));
1050 pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source));
1051 }
1052
1053
1054 if (c->autoload_hashmap) {
1055 nl = 0;
1056
1057 i = NULL;
1058 while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) {
1059
1060 if (!nl) {
1061 pa_strbuf_puts(buf, "\n");
1062 nl = 1;
1063 }
1064
1065 pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module);
1066
1067 if (a->argument)
1068 pa_strbuf_printf(buf, " %s", a->argument);
1069
1070 pa_strbuf_puts(buf, "\n");
1071 }
1072 }
1073
1074 nl = 0;
1075
1076 if ((p = pa_namereg_get_default_sink_name(c))) {
1077 if (!nl) {
1078 pa_strbuf_puts(buf, "\n");
1079 nl = 1;
1080 }
1081 pa_strbuf_printf(buf, "set-default-sink %s\n", p);
1082 }
1083
1084 if ((p = pa_namereg_get_default_source_name(c))) {
1085 if (!nl) {
1086 pa_strbuf_puts(buf, "\n");
1087 nl = 1;
1088 }
1089 pa_strbuf_printf(buf, "set-default-source %s\n", p);
1090 }
1091
1092 pa_strbuf_puts(buf, "\n### EOF\n");
1093
1094 return 0;
1095 }
1096
1097 int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, int *fail, int *ifstate) {
1098 const char *cs;
1099
1100 cs = s+strspn(s, whitespace);
1101
1102 if (*cs == '#' || !*cs)
1103 return 0;
1104 else if (*cs == '.') {
1105 if (!strcmp(cs, META_ELSE)) {
1106 if (!ifstate || *ifstate == IFSTATE_NONE) {
1107 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1108 return -1;
1109 } else if (*ifstate == IFSTATE_TRUE)
1110 *ifstate = IFSTATE_FALSE;
1111 else
1112 *ifstate = IFSTATE_TRUE;
1113 return 0;
1114 } else if (!strcmp(cs, META_ENDIF)) {
1115 if (!ifstate || *ifstate == IFSTATE_NONE) {
1116 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1117 return -1;
1118 } else
1119 *ifstate = IFSTATE_NONE;
1120 return 0;
1121 }
1122 if (ifstate && *ifstate == IFSTATE_FALSE)
1123 return 0;
1124 if (!strcmp(cs, META_FAIL))
1125 *fail = 1;
1126 else if (!strcmp(cs, META_NOFAIL))
1127 *fail = 0;
1128 else {
1129 size_t l;
1130 l = strcspn(cs, whitespace);
1131
1132 if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
1133 const char *filename = cs+l+strspn(cs+l, whitespace);
1134 if (pa_cli_command_execute_file(c, filename, buf, fail) < 0)
1135 if (*fail)
1136 return -1;
1137 } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
1138 if (!ifstate) {
1139 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1140 return -1;
1141 } else if (*ifstate != IFSTATE_NONE) {
1142 pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs);
1143 return -1;
1144 } else {
1145 const char *filename = cs+l+strspn(cs+l, whitespace);
1146
1147 *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
1148 }
1149 } else {
1150 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
1151 if (*fail) return -1;
1152 }
1153 }
1154 } else {
1155 const struct command*command;
1156 int unknown = 1;
1157 size_t l;
1158
1159 if (ifstate && *ifstate == IFSTATE_FALSE)
1160 return 0;
1161
1162
1163 l = strcspn(cs, whitespace);
1164
1165 for (command = commands; command->name; command++)
1166 if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
1167 int ret;
1168 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
1169 assert(t);
1170 ret = command->proc(c, t, buf, fail);
1171 pa_tokenizer_free(t);
1172 unknown = 0;
1173
1174 if (ret < 0 && *fail)
1175 return -1;
1176
1177 break;
1178 }
1179
1180 if (unknown) {
1181 pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
1182 if (*fail)
1183 return -1;
1184 }
1185 }
1186
1187 return 0;
1188 }
1189
1190 int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) {
1191 return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL);
1192 }
1193
1194 int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) {
1195 char line[256];
1196 FILE *f = NULL;
1197 int ifstate = IFSTATE_NONE;
1198 int ret = -1;
1199
1200 assert(c);
1201 assert(fn);
1202 assert(buf);
1203
1204 if (!(f = fopen(fn, "r"))) {
1205 pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
1206 if (!*fail)
1207 ret = 0;
1208 goto fail;
1209 }
1210
1211 while (fgets(line, sizeof(line), f)) {
1212 char *e = line + strcspn(line, linebreak);
1213 *e = 0;
1214
1215 if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail)
1216 goto fail;
1217 }
1218
1219 ret = 0;
1220
1221 fail:
1222 if (f)
1223 fclose(f);
1224
1225 return ret;
1226 }
1227
1228 int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) {
1229 const char *p;
1230 int ifstate = IFSTATE_NONE;
1231
1232 assert(c);
1233 assert(s);
1234 assert(buf);
1235
1236 p = s;
1237 while (*p) {
1238 size_t l = strcspn(p, linebreak);
1239 char *line = pa_xstrndup(p, l);
1240
1241 if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) {
1242 pa_xfree(line);
1243 return -1;
1244 }
1245 pa_xfree(line);
1246
1247 p += l;
1248 p += strspn(p, linebreak);
1249 }
1250
1251 return 0;
1252 }
1253