Bug Summary

File:build-analysis/../src/clients/nycli/cli_context.c
Warning:line 558, column 3
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage

Annotated Source Code

1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2017 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
16
17#include <stdlib.h>
18
19#include <glib.h>
20#include <glib/gi18n.h>
21#include <glib/gprintf.h>
22
23#include <xmmsclient/xmmsclient.h>
24
25#include <xmms_configuration.h>
26
27#include "readline.h"
28
29#include "cli_context.h"
30#include "cli_cache.h"
31#include "commands.h"
32#include "cmdnames.h"
33#include "configuration.h"
34#include "command_trie.h"
35#include "alias.h"
36#include "status.h"
37
38#define MAX_CACHE_REFRESH_LOOP200 200
39
40#define COMMAND_REQ_CHECK(action, reqmask)(((reqmask) & (action)->req) == (reqmask)) (((reqmask) & (action)->req) == (reqmask))
41
42struct cli_context_St {
43 xmmsc_connection_t *conn;
44 xmmsc_connection_t *sync;
45 execution_mode_t mode;
46 action_status_t status;
47 command_trie_t *commands;
48 GList *cmdnames; /* List of command names, faster help. */
49 GList *aliasnames;
50 configuration_t *config;
51 cli_cache_t *cache;
52 status_entry_t *status_entry;
53 gint alias_count; /* For recursive aliases */
54};
55
56static gboolean
57cli_context_autostart (cli_context_t *ctx, gchar *path)
58{
59 gint ret = 0;
60
61 /* Start the server if autostart enabled! */
62 if (configuration_get_boolean (ctx->config, "SERVER_AUTOSTART")
63 && !system ("xmms2-launcher")) {
64 ret = xmmsc_connect (ctx->conn, path);
65 }
66
67 return !!ret;
68}
69
70void
71cli_context_status_mode (cli_context_t *ctx, status_entry_t *entry)
72{
73 ctx->status = CLI_ACTION_STATUS_REFRESH;
74 ctx->status_entry = entry;
75 readline_status_mode (ctx, status_get_keymap (entry));
76 status_refresh (entry, TRUE(!(0)), FALSE(0));
77}
78
79void
80cli_context_status_mode_exit (cli_context_t *ctx)
81{
82 ctx->status = CLI_ACTION_STATUS_BUSY;
83 ctx->status_entry = NULL((void*)0);
84 cli_context_loop_resume (ctx);
85}
86
87void
88cli_context_alias_begin (cli_context_t *ctx)
89{
90 cli_context_loop_suspend (ctx);
91 ctx->status = CLI_ACTION_STATUS_ALIAS;
92 ctx->alias_count++;
93}
94
95void
96cli_context_alias_end (cli_context_t *ctx)
97{
98 ctx->alias_count--;
99 if (ctx->status != CLI_ACTION_STATUS_FINISH &&
100 ctx->status != CLI_ACTION_STATUS_REFRESH &&
101 ctx->alias_count == 0) {
102 ctx->status = CLI_ACTION_STATUS_BUSY;
103 }
104 cli_context_loop_resume (ctx);
105}
106
107void
108cli_context_loop_suspend (cli_context_t *ctx)
109{
110 if (ctx->status == CLI_ACTION_STATUS_ALIAS) {
111 return;
112 }
113 if (ctx->mode == CLI_EXECUTION_MODE_SHELL) {
114 readline_suspend (ctx);
115 }
116 ctx->status = CLI_ACTION_STATUS_BUSY;
117}
118
119void
120cli_context_loop_resume (cli_context_t *ctx)
121{
122 if (ctx->status != CLI_ACTION_STATUS_BUSY) {
123 return;
124 }
125 if (ctx->mode == CLI_EXECUTION_MODE_SHELL) {
126 readline_resume (ctx);
127 }
128 ctx->status = CLI_ACTION_STATUS_READY;
129}
130
131void
132cli_context_loop_stop (cli_context_t *ctx)
133{
134 if (ctx->mode == CLI_EXECUTION_MODE_SHELL) {
135 rl_set_prompt (NULL((void*)0));
136 }
137 ctx->status = CLI_ACTION_STATUS_FINISH;
138}
139
140/* Called on server disconnection. We can keep the loop running. */
141static gint
142cli_context_disconnect_callback (xmmsv_t *val, void *userdata)
143{
144 cli_context_t *ctx = (cli_context_t *) userdata;
145
146 xmmsc_unref (ctx->conn);
147 xmmsc_unref (ctx->sync);
148
149 ctx->conn = NULL((void*)0);
150 ctx->sync = NULL((void*)0);
151
152 if (ctx->status == CLI_ACTION_STATUS_REFRESH) {
153 status_refresh (ctx->status_entry, FALSE(0), TRUE(!(0)));
154 readline_status_mode_exit ();
155 }
156 cli_context_loop_resume (ctx);
157
158 return TRUE(!(0));
159}
160
161/* Called when client was disconnected. xmms2d disappeared */
162static void
163disconnect_callback (void *userdata)
164{
165 cli_context_disconnect_callback (NULL((void*)0), userdata);
166}
167
168gboolean
169cli_context_connect (cli_context_t *ctx, gboolean autostart)
170{
171 gchar *path;
172 xmmsc_result_t *res;
173
174 /* Open Async connection first */
175 ctx->conn = xmmsc_init (CLI_CLIENTNAME"xmms2-cli");
176 if (!ctx->conn) {
177 g_printf (_("Could not init connection!\n")gettext ("Could not init connection!\n"));
178 return FALSE(0);
179 }
180
181 path = configuration_get_string (ctx->config, "ipcpath");
182
183 if (!xmmsc_connect (ctx->conn, path)) {
184 if (!autostart) {
185 /* Failed to connect, but don't autostart */
186 xmmsc_unref (ctx->conn);
187 ctx->conn = NULL((void*)0);
188 return FALSE(0);
189 } else if (!cli_context_autostart (ctx, path)) {
190 /* Autostart failed, abort now */
191 if (path) {
192 g_printf (_("Could not connect to server at '%s'!\n")gettext ("Could not connect to server at '%s'!\n"), path);
193 } else {
194 g_printf (_("Could not connect to server at default path!\n")gettext ("Could not connect to server at default path!\n"));
195 }
196 xmmsc_unref (ctx->conn);
197 ctx->conn = NULL((void*)0);
198 return FALSE(0);
199 }
200 }
201
202 /* Sync connection */
203 ctx->sync = xmmsc_init (CLI_CLIENTNAME"xmms2-cli" "-sync");
204 if (!ctx->sync) {
205 g_printf (_("Could not init sync connection!\n")gettext ("Could not init sync connection!\n"));
206 return FALSE(0);
207 }
208
209 if (!xmmsc_connect (ctx->sync, path)) {
210 if (path) {
211 g_printf (_("Could not connect to server at '%s'!\n")gettext ("Could not connect to server at '%s'!\n"), path);
212 } else {
213 g_printf (_("Could not connect to server at default path!\n")gettext ("Could not connect to server at default path!\n"));
214 }
215
216 xmmsc_unref (ctx->conn);
217 xmmsc_unref (ctx->sync);
218
219 ctx->conn = NULL((void*)0);
220 ctx->sync = NULL((void*)0);
221
222 return FALSE(0);
223 }
224
225 /* Reset the connection state on server quit */
226 res = xmmsc_broadcast_quit (ctx->conn);
227 xmmsc_disconnect_callback_set (ctx->conn, disconnect_callback, ctx);
228 xmmsc_result_notifier_setxmmsc_result_notifier_set_default (res, &cli_context_disconnect_callback, ctx);
229 xmmsc_result_unref (res);
230
231 cli_cache_start (ctx->cache, ctx->conn);
232
233 return TRUE(!(0));
234}
235
236static gboolean
237register_command (command_trie_t *commands, GList **names, command_action_t *action)
238{
239 if (command_trie_insert (commands, action)) {
240 gchar **namev;
241 namev = g_strsplit (action->name, " ", 0);
242 *names = cmdnames_prepend (*names, namev);
243 g_strfreev (namev);
244 return TRUE(!(0));
245 } else {
246 return FALSE(0);
247 }
248}
249
250cli_context_t *
251cli_context_init (void)
252{
253 cli_context_t *ctx;
254 alias_define_t *aliaslist;
255 gchar *filename;
256 gint i;
257
258 ctx = g_new0 (cli_context_t, 1)((cli_context_t *) g_malloc0_n ((1), sizeof (cli_context_t)));
259
260 /* readline_init needs PROMPT */
261 filename = configuration_get_filename ();
262 ctx->config = configuration_init (filename);
263 g_free (filename);
264
265 readline_init (ctx);
266
267 ctx->status = CLI_ACTION_STATUS_READY;
268 ctx->commands = command_trie_alloc ();
269
270 /* Register commands and command names */
271 for (i = 0; commandlist[i]; ++i) {
272 command_action_t *action = command_action_alloc ();
273 commandlist[i] (action);
274 if (!register_command (ctx->commands, &ctx->cmdnames, action)) {
275 command_action_free (action);
276 }
277 }
278
279 /* Register aliases with a default callback */
280 aliaslist = alias_list (configuration_get_aliases (ctx->config));
281 for (i = 0; aliaslist[i].name; ++i) {
282 command_action_t *action = command_action_alloc ();
283 alias_setup (action, &aliaslist[i]);
284 if (!register_command (ctx->commands, &ctx->aliasnames, action)) {
285 command_action_free (action);
286 }
287 }
288 alias_list_free (aliaslist);
289
290 ctx->alias_count = 0;
291 ctx->aliasnames = cmdnames_reverse (ctx->aliasnames);
292 ctx->cmdnames = cmdnames_reverse (ctx->cmdnames);
293 ctx->cache = cli_cache_init ();
294
295 return ctx;
296}
297
298void
299cli_context_free (cli_context_t *ctx)
300{
301 if (ctx->conn) {
302 xmmsc_unref (ctx->conn);
303 }
304 if (ctx->mode == CLI_EXECUTION_MODE_SHELL) {
305 readline_free ();
306 }
307
308 command_trie_free (ctx->commands);
309 cli_cache_free (ctx->cache);
310 configuration_free (ctx->config);
311 cmdnames_free (ctx->cmdnames);
312
313 g_free (ctx);
314}
315
316
317static void cli_context_event_loop_select (cli_context_t *ctx);
318static void cli_context_command_dispatch (cli_context_t *ctx, gint in_argc, gchar **in_argv);
319static void cli_context_flag_dispatch (cli_context_t *ctx, gint in_argc, gchar **in_argv);
320
321void
322cli_context_execute_command (cli_context_t *ctx, gchar *input)
323{
324 while (input && *input == ' ') ++input;
1
Assuming 'input' is non-null
2
Assuming the condition is false
3
Loop condition is false. Execution continues on line 326
325
326 if (input == NULL((void*)0)) {
4
Taking false branch
327 if (!cli_context_in_status (ctx, CLI_ACTION_STATUS_ALIAS)) {
328 /* End of stream, quit */
329 cli_context_loop_stop (ctx);
330 g_printf ("\n");
331 }
332 } else if (*input != 0) {
5
Assuming the condition is true
6
Taking true branch
333 gint argc;
334 gchar **argv, *listop;
335 GError *error = NULL((void*)0);
336
337 if ((listop = strchr (input, ';'))) {
7
Assuming 'listop' is null
8
Taking false branch
338 *listop++ = '\0';
339 }
340
341 if (g_shell_parse_argv (input, &argc, &argv, &error)) {
9
Assuming the condition is true
10
Taking true branch
342 if (!cli_context_in_status (ctx, CLI_ACTION_STATUS_ALIAS)) {
11
Taking true branch
343 add_history (input);
344 }
345 cli_context_command_dispatch (ctx, argc, argv);
12
Calling 'cli_context_command_dispatch'
346 g_strfreev (argv);
347 if (listop && *listop) {
348 g_printf ("\n");
349 cli_context_execute_command (ctx, listop);
350 }
351 } else {
352 g_printf (_("Error: %s\n")gettext ("Error: %s\n"), error->message);
353 g_error_free (error);
354 }
355 }
356}
357
358static gboolean
359cli_context_command_runnable (cli_context_t *ctx, command_action_t *action)
360{
361 xmmsc_connection_t *conn = cli_context_xmms_async (ctx);
362 gint n = 0;
363
364 /* Require connection, abort on failure */
365 if (COMMAND_REQ_CHECK(action, COMMAND_REQ_CONNECTION)(((COMMAND_REQ_CONNECTION) & (action)->req) == (COMMAND_REQ_CONNECTION
))
&& !conn) {
366 gboolean autostart;
367 autostart = !COMMAND_REQ_CHECK(action, COMMAND_REQ_NO_AUTOSTART)(((COMMAND_REQ_NO_AUTOSTART) & (action)->req) == (COMMAND_REQ_NO_AUTOSTART
))
;
368 if (!cli_context_connect (ctx, autostart) && autostart) {
369 return FALSE(0);
370 }
371 }
372
373 /* Get the cache ready if needed */
374 if (COMMAND_REQ_CHECK(action, COMMAND_REQ_CACHE)(((COMMAND_REQ_CACHE) & (action)->req) == (COMMAND_REQ_CACHE
))
) {
19
Taking true branch
375 /* If executing an alias have to refresh manually */
376 if (cli_context_in_status (ctx, CLI_ACTION_STATUS_ALIAS)) {
20
Taking false branch
377 cli_context_cache_refresh (ctx);
378 }
379 while (cli_context_cache_refreshing (ctx)) {
21
Loop condition is true. Entering loop body
380 /* Obviously, there is a problem with updating the cache, abort */
381 if (n == MAX_CACHE_REFRESH_LOOP200) {
22
Taking false branch
382 g_printf (_("Failed to update the cache!")gettext ("Failed to update the cache!"));
383 return FALSE(0);
384 }
385 cli_context_event_loop_select (ctx);
23
Calling 'cli_context_event_loop_select'
386 n++;
387 }
388 }
389
390 return TRUE(!(0));
391}
392
393/* Switch function which should only be called with 'raw' (i.e. inline
394 * mode, not shell mode) argv/argc. If appropriate, it enters
395 * flag_dispatch to parse program flags.
396 */
397static void
398cli_context_command_or_flag_dispatch (cli_context_t *ctx, gint in_argc, gchar **in_argv)
399{
400 /* First argument looks like a flag */
401 if (in_argc > 0 && in_argv[0][0] == '-') {
402 cli_context_flag_dispatch (ctx, in_argc, in_argv);
403 } else {
404 cli_context_command_dispatch (ctx, in_argc, in_argv);
405 }
406}
407
408/* Dispatch actions according to program flags (NOT commands or
409 * command options).
410 */
411static void
412cli_context_flag_dispatch (cli_context_t *ctx, gint in_argc, gchar **in_argv)
413{
414 command_t *cmd;
415 gboolean check;
416
417 GOptionEntry flagdefs[] = {
418 { "help", 'h', 0, G_OPTION_ARG_NONE, NULL((void*)0),
419 _("Display this help and exit.")gettext ("Display this help and exit."), NULL((void*)0) },
420 { "version", 'v', 0, G_OPTION_ARG_NONE, NULL((void*)0),
421 _("Output version information and exit.")gettext ("Output version information and exit."), NULL((void*)0) },
422 { NULL((void*)0) }
423 };
424
425 /* Include one command token as a workaround for the bug that
426 * the option parser does not parse commands starting with a
427 * flag properly (e.g. "-p foo arg1"). Will be skipped by the
428 * command utils. */
429 cmd = command_new (flagdefs, in_argc + 1, in_argv - 1);
430
431 if (!cmd) {
432 /* An error message has already been printed, so we just return. */
433 return;
434 }
435
436 if (command_flag_boolean_get (cmd, "help", &check) && check) {
437 if (command_arg_count (cmd) >= 1) {
438 help_command (ctx, cli_context_command_names (ctx),
439 command_argv_get (cmd), command_arg_count (cmd),
440 CMD_TYPE_COMMAND);
441 } else {
442 /* FIXME: explain -h and -v flags here (reuse help_command code?) */
443 g_printf (_("usage: xmms2 [<command> [args]]\n\n")gettext ("usage: xmms2 [<command> [args]]\n\n"));
444 g_printf (_("XMMS2 CLI, the awesome command-line XMMS2 client from the future, "gettext ("XMMS2 CLI, the awesome command-line XMMS2 client from the future, "
"v" "clang-analysis" ".\n\n")
445 "v" XMMS_VERSION ".\n\n")gettext ("XMMS2 CLI, the awesome command-line XMMS2 client from the future, "
"v" "clang-analysis" ".\n\n")
);
446 g_printf (_("If given a command, runs it inline and exit.\n")gettext ("If given a command, runs it inline and exit.\n"));
447 g_printf (_("If not, enters a shell-like interface to execute commands.\n\n")gettext ("If not, enters a shell-like interface to execute commands.\n\n"
)
);
448 g_printf (_("Type 'help <command>' for detailed help about a command.\n")gettext ("Type 'help <command>' for detailed help about a command.\n"
)
);
449 }
450 } else if (command_flag_boolean_get (cmd, "version", &check) && check) {
451 g_printf (_("XMMS2 CLI version " XMMS_VERSION "\n")gettext ("XMMS2 CLI version " "clang-analysis" "\n"));
452 g_printf (_("Copyright (C) 2008-2017 XMMS2 Team\n")gettext ("Copyright (C) 2008-2017 XMMS2 Team\n"));
453 g_printf (_("This is free software; see the source for copying conditions.\n")gettext ("This is free software; see the source for copying conditions.\n"
)
);
454 g_printf (_("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"gettext ("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
"PARTICULAR PURPOSE.\n")
455 "PARTICULAR PURPOSE.\n")gettext ("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
"PARTICULAR PURPOSE.\n")
);
456 /* FIXME: compiled against? use RL_READLINE_VERSION? */
457 g_printf (_(" Using readline version %s\n")gettext (" Using readline version %s\n"), rl_library_version);
458 } else {
459 /* Call help to print the "no such command" error */
460 /* FIXME: Could be a more helpful "invalid flag"?*/
461 help_command (ctx, cli_context_command_names (ctx),
462 in_argv, in_argc, CMD_TYPE_COMMAND);
463 }
464
465 command_free (cmd);
466}
467
468static void
469cli_context_command_dispatch (cli_context_t *ctx, gint in_argc, gchar **in_argv)
470{
471 command_action_t *action;
472 command_trie_match_type_t match;
473 gint argc;
474 gchar *tmp_argv[in_argc+1];
475 gchar **argv;
476
477 /* The arguments will be updated by command_trie_find and
478 * init_context_from_args, so we make a copy. */
479 memcpy (tmp_argv, in_argv, in_argc * sizeof (gchar *));
480 tmp_argv[in_argc] = NULL((void*)0);
481
482 argc = in_argc;
483 argv = tmp_argv;
484
485 /* This updates argv and argc so that they start at the first non-command
486 * token. */
487 match = cli_context_find_command (ctx, &argv, &argc, &action);
488 if (match == COMMAND_TRIE_MATCH_ACTION) {
13
Assuming 'match' is equal to COMMAND_TRIE_MATCH_ACTION
14
Taking true branch
489 gboolean help;
490 gboolean need_io;
491 command_t *cmd;
492
493 /* Include one command token as a workaround for the bug that
494 * the option parser does not parse commands starting with a
495 * flag properly (e.g. "-p foo arg1"). Will be skipped by the
496 * command utils. */
497 cmd = command_new (action->argdefs, argc + 1, argv - 1);
498
499 if (cmd) {
15
Assuming 'cmd' is non-null
16
Taking true branch
500 if (command_flag_boolean_get (cmd, "help", &help) && help) {
17
Assuming the condition is false
501 /* Help flag passed, bypass action and show help */
502 /* FIXME(g): select aliasnames list if it's an alias */
503 help_command (ctx, cli_context_command_names (ctx),
504 in_argv, in_argc, CMD_TYPE_COMMAND);
505 } else if (cli_context_command_runnable (ctx, action)) {
18
Calling 'cli_context_command_runnable'
506 /* All fine, run the command */
507 command_name_set (cmd, action->name);
508 cli_context_loop_suspend (ctx);
509 need_io = action->callback (ctx, cmd);
510 if (!need_io) {
511 cli_context_loop_resume (ctx);
512 }
513 }
514
515 command_free (cmd);
516 }
517 } else {
518 /* Call help to print the "no such command" error */
519 help_command (ctx, cli_context_command_names (ctx),
520 in_argv, in_argc, CMD_TYPE_COMMAND);
521 }
522}
523
524static void
525cli_context_event_loop_select (cli_context_t *ctx)
526{
527 xmmsc_connection_t *conn = cli_context_xmms_async (ctx);
528 fd_set rfds, wfds;
529 gint modfds;
530 gint xmms2fd;
531 gint maxfds = 0;
532
533 FD_ZERO(&rfds)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&rfds)->__fds_bits)[
0]) : "memory"); } while (0)
;
534 FD_ZERO(&wfds)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&wfds)->__fds_bits)[
0]) : "memory"); } while (0)
;
535
536 /* Listen to xmms2 if connected */
537 if (conn) {
24
Assuming 'conn' is null
25
Taking false branch
538 xmms2fd = xmmsc_io_fd_get (conn);
539 if (xmms2fd == -1) {
540 g_printf (_("Error: failed to retrieve XMMS2 file descriptor!")gettext ("Error: failed to retrieve XMMS2 file descriptor!"));
541 return;
542 }
543
544 FD_SET(xmms2fd, &rfds)((void) (((&rfds)->__fds_bits)[((xmms2fd) / (8 * (int)
sizeof (__fd_mask)))] |= ((__fd_mask) 1 << ((xmms2fd) %
(8 * (int) sizeof (__fd_mask))))))
;
545 if (xmmsc_io_want_out (conn)) {
546 FD_SET(xmms2fd, &wfds)((void) (((&wfds)->__fds_bits)[((xmms2fd) / (8 * (int)
sizeof (__fd_mask)))] |= ((__fd_mask) 1 << ((xmms2fd) %
(8 * (int) sizeof (__fd_mask))))))
;
547 }
548
549 if (maxfds < xmms2fd) {
550 maxfds = xmms2fd;
551 }
552 }
553
554 /* Listen to readline in shell mode or status mode */
555 if ((cli_context_in_mode (ctx, CLI_EXECUTION_MODE_SHELL) &&
26
Taking true branch
556 cli_context_in_status (ctx, CLI_ACTION_STATUS_READY)) ||
557 cli_context_in_status (ctx, CLI_ACTION_STATUS_REFRESH)) {
558 FD_SET(STDIN_FILENO, &rfds)((void) (((&rfds)->__fds_bits)[((0) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) 1 << ((0) % (8 * (int) sizeof
(__fd_mask))))))
;
27
Within the expansion of the macro 'FD_SET':
a
The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage
559 if (maxfds < STDIN_FILENO0) {
560 maxfds = STDIN_FILENO0;
561 }
562 }
563
564 if (cli_context_in_status (ctx, CLI_ACTION_STATUS_REFRESH)) {
565 struct timeval refresh;
566 refresh.tv_sec = cli_context_refresh_interval (ctx);
567 refresh.tv_usec = 0;
568 modfds = select (maxfds + 1, &rfds, &wfds, NULL((void*)0), &refresh);
569 } else {
570 modfds = select (maxfds + 1, &rfds, &wfds, NULL((void*)0), NULL((void*)0));
571 }
572
573 if (modfds < 0 && errno(*__errno_location ()) != EINTR4) {
574 g_printf (_("Error: invalid I/O result!")gettext ("Error: invalid I/O result!"));
575 return;
576 } else if (modfds != 0) {
577 /* Get/send data to xmms2 */
578 if (conn) {
579 if (FD_ISSET(xmms2fd, &rfds)((((&rfds)->__fds_bits)[((xmms2fd) / (8 * (int) sizeof
(__fd_mask)))] & ((__fd_mask) 1 << ((xmms2fd) % (8
* (int) sizeof (__fd_mask))))) != 0)
&&
580 !xmmsc_io_in_handle (conn)) {
581 return;
582 }
583
584 if (FD_ISSET(xmms2fd, &wfds)((((&wfds)->__fds_bits)[((xmms2fd) / (8 * (int) sizeof
(__fd_mask)))] & ((__fd_mask) 1 << ((xmms2fd) % (8
* (int) sizeof (__fd_mask))))) != 0)
&&
585 !xmmsc_io_out_handle (conn)) {
586 return;
587 }
588 }
589
590 /* User input found, read it */
591 if ((cli_context_in_mode (ctx, CLI_EXECUTION_MODE_SHELL) ||
592 cli_context_in_status (ctx, CLI_ACTION_STATUS_REFRESH)) &&
593 FD_ISSET(STDIN_FILENO, &rfds)((((&rfds)->__fds_bits)[((0) / (8 * (int) sizeof (__fd_mask
)))] & ((__fd_mask) 1 << ((0) % (8 * (int) sizeof (
__fd_mask))))) != 0)
) {
594 rl_callback_read_char ();
595 }
596 }
597
598 /* Status -refresh
599 Ask theefer: use callbacks for update and -refresh only for print?
600 Nesciens: Yes, please!
601 */
602 if (cli_context_in_status (ctx, CLI_ACTION_STATUS_REFRESH)) {
603 cli_context_refresh_status (ctx);
604 }
605}
606
607void
608cli_context_loop (cli_context_t *ctx, gint argc, gchar **argv)
609{
610 /* Execute command, if connection status is ok */
611 if (argc == 0) {
612 gchar *filename = configuration_get_string (ctx->config, "HISTORY_FILE");
613
614 ctx->mode = CLI_EXECUTION_MODE_SHELL;
615
616 /* print welcome message before initialising readline */
617 if (configuration_get_boolean (ctx->config, "SHELL_START_MESSAGE")) {
618 g_printf (_("Welcome to the XMMS2 CLI shell!\n")gettext ("Welcome to the XMMS2 CLI shell!\n"));
619 g_printf (_("Type 'help' to list the available commands "gettext ("Type 'help' to list the available commands " "and 'exit' (or CTRL-D) to leave the shell.\n"
)
620 "and 'exit' (or CTRL-D) to leave the shell.\n")gettext ("Type 'help' to list the available commands " "and 'exit' (or CTRL-D) to leave the shell.\n"
)
);
621 }
622 readline_resume (ctx);
623
624 read_history (filename);
625 using_history ();
626
627 while (!cli_context_in_status (ctx, CLI_ACTION_STATUS_FINISH)) {
628 cli_context_event_loop_select (ctx);
629 }
630
631 write_history (filename);
632 } else {
633 ctx->mode = CLI_EXECUTION_MODE_INLINE;
634 cli_context_command_or_flag_dispatch (ctx, argc , argv);
635
636 while (cli_context_in_status (ctx, CLI_ACTION_STATUS_BUSY) ||
637 cli_context_in_status (ctx, CLI_ACTION_STATUS_REFRESH)) {
638 cli_context_event_loop_select (ctx);
639 }
640 }
641}
642
643xmmsc_connection_t *
644cli_context_xmms_sync (cli_context_t *ctx)
645{
646 return ctx->sync;
647}
648
649xmmsc_connection_t *
650cli_context_xmms_async (cli_context_t *ctx)
651{
652 return ctx->conn;
653}
654
655configuration_t *
656cli_context_config (cli_context_t *ctx)
657{
658 return ctx->config;
659}
660
661GList *
662cli_context_command_names (cli_context_t *ctx)
663{
664 return ctx->cmdnames;
665}
666
667GList *
668cli_context_alias_names (cli_context_t *ctx)
669{
670 return ctx->aliasnames;
671}
672
673gboolean
674cli_context_in_mode (cli_context_t *ctx, execution_mode_t mode)
675{
676 return ctx->mode == mode;
677}
678
679gboolean
680cli_context_in_status (cli_context_t *ctx, action_status_t status)
681{
682 return ctx->status == status;
683}
684
685void
686cli_context_refresh_status (cli_context_t *ctx)
687{
688 status_refresh (ctx->status_entry, FALSE(0), FALSE(0));
689}
690
691gint
692cli_context_refresh_interval (cli_context_t *ctx)
693{
694 return status_get_refresh_interval (ctx->status_entry);
695}
696
697command_trie_match_type_t
698cli_context_find_command (cli_context_t *ctx, gchar ***argv, gint *argc,
699 command_action_t **action)
700{
701 return cli_context_complete_command (ctx, argv, argc, action, NULL((void*)0));
702}
703
704command_trie_match_type_t
705cli_context_complete_command (cli_context_t *ctx, gchar ***argv, gint *argc,
706 command_action_t **action, GList **suffixes)
707{
708 gboolean auto_complete = configuration_get_boolean (ctx->config, "AUTO_UNIQUE_COMPLETE");
709 return command_trie_find (ctx->commands, argv, argc, auto_complete, action, suffixes);
710}
711
712void
713cli_context_cache_refresh (cli_context_t *ctx)
714{
715 cli_cache_refresh (ctx->cache);
716}
717
718gboolean
719cli_context_cache_refreshing (cli_context_t *ctx)
720{
721 return !cli_cache_is_fresh (ctx->cache);
722}
723
724status_entry_t *
725cli_context_status_entry (cli_context_t *ctx)
726{
727 return ctx->status_entry;
728}
729
730gint
731cli_context_current_position (cli_context_t *ctx)
732{
733 return ctx->cache->currpos;
734}
735
736gint
737cli_context_current_id (cli_context_t *ctx)
738{
739 return ctx->cache->currid;
740}
741
742gint
743cli_context_playback_status (cli_context_t *ctx)
744{
745 return ctx->cache->playback_status;
746}
747
748xmmsv_t *
749cli_context_active_playlist (cli_context_t *ctx)
750{
751 return ctx->cache->active_playlist;
752}
753
754const gchar *
755cli_context_active_playlist_name (cli_context_t *ctx)
756{
757 return ctx->cache->active_playlist_name;
758}