Merge branch 't/gui_improvements'
authorAndre Noll <maan@systemlinux.org>
Thu, 29 Mar 2012 17:58:04 +0000 (19:58 +0200)
committerAndre Noll <maan@systemlinux.org>
Thu, 29 Mar 2012 18:05:55 +0000 (20:05 +0200)
      gui: Make some functions return void.
      gui: Rename client_cmd_cmdline() to para_cmd().
      gui: Check return value of para_exec_cmdline_pid().
      gui: Also display command's stderr output.

NEWS
gui.c

diff --git a/NEWS b/NEWS
index 7c3ac3c..dc83e16 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,9 +2,14 @@
 0.4.10 (to be announced) "heterogeneous vacuum"
 -----------------------------------------------
 
+Nothing earth-shaking in this release, but quite a few usability
+improvements and the usual mix of cleanups and fixes.
+
        - The --no_default_filters option of para_filter has been
-         depricated. It still works but has no effect and will be
+         deprecated. It still works but has no effect and will be
          removed in the next version.
+       - para_gui now prints also the stderr output of the executing
+          command in the bottom window.
        - Cleanup and consolidation of the various wrappers for
          write(), writev(), send() and friends.
        - The obscure error messages on mmap() failures have been
@@ -15,7 +20,6 @@
          being built.
        - New configure options: --with-id3tag-{headers,libs}.
 
-
 -------------------------------------
 0.4.9 (2011-12-06) "hybrid causality"
 -------------------------------------
diff --git a/gui.c b/gui.c
index 0316e36..65b2ac0 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -53,7 +53,7 @@ static unsigned scroll_position;
 static int cmd_died, curses_active;
 static pid_t cmd_pid;
 
-static int command_pipe = -1;
+static int command_fds[2];
 static int stat_pipe = -1;
 static struct gui_args_info conf;
 
@@ -485,11 +485,12 @@ __printf_2_3 static void outputf(int color, const char* fmt,...)
        wrefresh(bot.win);
 }
 
-static int add_output_line(char *line, __a_unused void *data)
+static int add_output_line(char *line, void *data)
 {
+       int color = *(int *)data? COLOR_ERRMSG : COLOR_OUTPUT;
        if (!curses_active)
                return 1;
-       rb_add_entry(COLOR_OUTPUT, para_strdup(line));
+       rb_add_entry(color, para_strdup(line));
        return 1;
 }
 
@@ -950,15 +951,16 @@ static int open_stat_pipe(void)
        return ret;
 }
 
+#define COMMAND_BUF_SIZE 4096
+
 /*
  * This is the core select loop. Besides the (internal) signal
  * pipe, the following other fds are checked according to the mode:
  *
  * GETCH_MODE: check stdin, return when key is pressed
  *
- * COMMAND_MODE: check command_pipe and stdin. Return when a screen full
- * of output has been read or when other end has closed command pipe or
- * when any key is pressed.
+ * COMMAND_MODE: check command fds and stdin. Return when peer has closed both
+ * stdout and stderr or when any key is pressed.
  *
  * EXTERNAL_MODE: Check only signal pipe. Used when an external command
  * is running. During that time curses is disabled.  Returns when
@@ -967,11 +969,11 @@ static int open_stat_pipe(void)
 static int do_select(int mode)
 {
        fd_set rfds;
-       int ret;
-       int max_fileno;
-       char command_buf[4096] = "";
-       int cbo = 0; /* command buf offset */
+       int ret, i, max_fileno;
+       char command_buf[2][COMMAND_BUF_SIZE] = {"", ""};
+       int cbo[2] = {0, 0}; /* command buf offsets */
        struct timeval tv;
+
 repeat:
        tv.tv_sec = conf.timeout_arg  / 1000;
        tv.tv_usec = (conf.timeout_arg % 1000) * 1000;
@@ -985,8 +987,12 @@ repeat:
        /* signal pipe */
        para_fd_set(signal_pipe, &rfds, &max_fileno);
        /* command pipe only for COMMAND_MODE */
-       if (command_pipe >= 0 && mode == COMMAND_MODE)
-               para_fd_set(command_pipe, &rfds, &max_fileno);
+       if (mode == COMMAND_MODE) {
+               if (command_fds[0] >= 0)
+                       para_fd_set(command_fds[0], &rfds, &max_fileno);
+               if (command_fds[1] >= 0)
+                       para_fd_set(command_fds[1], &rfds, &max_fileno);
+       }
        ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
        if (ret <= 0)
                goto check_return; /* skip fd checks */
@@ -995,21 +1001,28 @@ repeat:
        if (ret > 0)
                handle_signal(ret);
        /* read command pipe if ready */
-       if (command_pipe >= 0 && mode == COMMAND_MODE) {
-               size_t sz;
-               ret = read_nonblock(command_pipe, command_buf + cbo,
-                       sizeof(command_buf) - 1 - cbo, &rfds, &sz);
-               cbo += sz;
-               sz = cbo;
-               cbo = for_each_line(command_buf, cbo, &add_output_line, NULL);
-               if (sz != cbo)
-                       wrefresh(bot.win);
-               if (ret < 0) {
-                       PARA_NOTICE_LOG("closing command pipe: %s",
-                               para_strerror(-ret));
-                       close(command_pipe);
-                       command_pipe = -1;
-                       return 0;
+       if (mode == COMMAND_MODE) {
+               for (i = 0; i < 2; i++) {
+                       size_t sz;
+                       if (command_fds[i] < 0)
+                               continue;
+                       ret = read_nonblock(command_fds[i],
+                               command_buf[i] + cbo[i],
+                               COMMAND_BUF_SIZE - 1 - cbo[i], &rfds, &sz);
+                       cbo[i] += sz;
+                       sz = cbo[i];
+                       cbo[i] = for_each_line(command_buf[i], cbo[i],
+                               add_output_line, &i);
+                       if (sz != cbo[i])
+                               wrefresh(bot.win);
+                       if (ret < 0) {
+                               PARA_NOTICE_LOG("closing command fd %d: %s",
+                                       i, para_strerror(-ret));
+                               close(command_fds[i]);
+                               command_fds[i] = -1;
+                               if (command_fds[!i] < 0) /* both fds closed */
+                                       return 0;
+                       }
                }
        }
        ret = read_stat_pipe(&rfds);
@@ -1028,9 +1041,13 @@ check_return:
        case COMMAND_MODE:
                ret = wgetch(top.win);
                if (ret != ERR && ret != KEY_RESIZE) {
-                       if (command_pipe) {
-                               close(command_pipe);
-                               command_pipe = -1;
+                       if (command_fds[0] >= 0) {
+                               close(command_fds[0]);
+                               command_fds[0] = -1;
+                       }
+                       if (command_fds[1] >= 0) {
+                               close(command_fds[1]);
+                               command_fds[1] = -1;
                        }
                        if (cmd_pid)
                                kill(cmd_pid, SIGTERM);
@@ -1054,28 +1071,31 @@ check_return:
 /*
  * read from command pipe and print data to bot window
  */
-static int send_output(void)
+static void send_output(void)
 {
        int ret;
 
-       if (command_pipe < 0)
-               return 0;
-       ret = mark_fd_nonblocking(command_pipe);
-       if (ret < 0) {
-               close(command_pipe);
-               return ret;
-       }
+       ret = mark_fd_nonblocking(command_fds[0]);
+       if (ret < 0)
+               goto fail;
+       ret = mark_fd_nonblocking(command_fds[1]);
+       if (ret < 0)
+               goto fail;
        if (do_select(COMMAND_MODE) >= 0)
                PARA_INFO_LOG("command complete");
        else
                PARA_NOTICE_LOG("command aborted");
        print_in_bar(COLOR_MSG, " ");
-       return 1;
+       return;
+fail:
+       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       close(command_fds[0]);
+       close(command_fds[1]);
 }
 
-static int client_cmd_cmdline(char *cmd)
+static void para_cmd(char *cmd)
 {
-       int ret, fds[3] = {0, 1, 0};
+       int ret, fds[3] = {0, 1, 1};
        char *c = make_message(BINDIR "/para_client -- %s", cmd);
 
        outputf(COLOR_COMMAND, "%s", c);
@@ -1083,41 +1103,43 @@ static int client_cmd_cmdline(char *cmd)
        ret = para_exec_cmdline_pid(&cmd_pid, c, fds);
        free(c);
        if (ret < 0)
-               return -1;
-       command_pipe = fds[1];
-       return send_output();
+               return;
+       command_fds[0] = fds[1];
+       command_fds[1] = fds[2];
+       send_output();
 }
 
 /*
  * exec command and print output to bot win
  */
-static int display_cmd(char *cmd)
+static void display_cmd(char *cmd)
 {
-       int fds[3] = {0, 1, 0};
+       int fds[3] = {0, 1, 1};
 
        print_in_bar(COLOR_MSG, "executing display command, hit any key to abort");
        outputf(COLOR_COMMAND, "%s", cmd);
        if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
-               return -1;
-       command_pipe = fds[1];
-       return send_output();
+               return;
+       command_fds[0] = fds[1];
+       command_fds[1] = fds[2];
+       send_output();
 }
 
 /*
  * shutdown curses and stat pipe before executing external commands
  */
-static int external_cmd(char *cmd)
+static void external_cmd(char *cmd)
 {
        int fds[3] = {-1, -1, -1};
 
        if (cmd_pid)
-               return -1;
+               return;
        shutdown_curses();
-       para_exec_cmdline_pid(&cmd_pid, cmd, fds);
+       if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
+               return;
        cmd_died = 0;
        do_select(EXTERNAL_MODE);
        init_curses();
-       return 0;
 }
 
 static void print_scroll_msg(void)
@@ -1436,7 +1458,7 @@ static void handle_command(int c)
                else if (*handler == 'x')
                        external_cmd(arg);
                else if (*handler == 'p')
-                       client_cmd_cmdline(arg);
+                       para_cmd(arg);
                else if (*handler == 'i') {
                        int num = find_cmd_byname(arg);
                        if (num >= 0)