Move chunk_queue stuff to own files chunk_queue.[ch].
[paraslash.git] / gui.c
diff --git a/gui.c b/gui.c
index 9b1c739f2110d6e05c0d27e0a832472d72b5b149..a2d3e6cd5b63c5d867d793939dbae219196b6bab 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -1,33 +1,27 @@
 /*
- * Copyright (C) 1998-2006 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1998-2007 Andre Noll <maan@systemlinux.org>
  *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
 /** \file gui.c ncurses-based interface for paraslash */
 
 #include "gui.cmdline.h"
 #include "para.h"
+#include "gui.h"
 #include <curses.h>
 #include "ringbuffer.h"
 #include "string.h"
+#include "fd.h"
+#include "error.h"
+#include "signal.h"
 
+/** define the array of error lists needed by para_gui */
+INIT_GUI_ERRLISTS;
 extern const char *status_item_list[NUM_STAT_ITEMS];
 static char *stat_content[NUM_STAT_ITEMS];
 
-#define STANDARD_STATUS_BAR "para_gui " VERSION " (hit ? for help)"
+#define STANDARD_STATUS_BAR "para_gui " PACKAGE_VERSION " (hit ? for help)"
 
 static int signal_pipe;
 
@@ -52,12 +46,12 @@ void *bot_win_rb;
 
 static unsigned scroll_position;
 
-static int external_cmd_died, curses_active;
-static pid_t external_cmd_pid;
+static int cmd_died, curses_active;
+static pid_t cmd_pid;
 
 static int command_pipe = -1;
 static int audiod_pipe = -1;
-static struct gengetopt_args_info conf;
+static struct gui_args_info conf;
 
 enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
 
@@ -73,9 +67,9 @@ enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
 #define COLOR_BOT 40
 
 struct gui_command {
-       char *key;
-       char *name;
-       char *description;
+       const char *key;
+       const char *name;
+       const char *description;
        void (*handler)(void);
 };
 
@@ -284,7 +278,7 @@ static void add_spaces(WINDOW* win, unsigned int num)
  * print aligned string to curses window. This function always prints
  * exactly len chars.
  */
-static int align_str(WINDOW* win, char *string, unsigned int len,
+static int align_str(WINDOW* win, const char *string, unsigned int len,
                unsigned int align)
 {
        int num; /* of spaces */
@@ -313,7 +307,7 @@ static int align_str(WINDOW* win, char *string, unsigned int len,
        return 1;
 }
 
-__printf_2_3 static void print_in_bar(int color, char *fmt,...)
+__printf_2_3 static void print_in_bar(int color, const char *fmt,...)
 {
        char *msg;
 
@@ -335,7 +329,7 @@ static void print_status_bar(void)
        if (!curses_active)
                return;
        wmove(sb.win, 0, 0);
-       align_str(sb.win,STANDARD_STATUS_BAR, sb.cols, CENTER);
+       align_str(sb.win, STANDARD_STATUS_BAR, sb.cols, CENTER);
        wrefresh(sb.win);
 }
 
@@ -442,7 +436,7 @@ static void rb_add_entry(int color, char *msg)
 /*
  * print formated output to bot win and refresh
  */
-__printf_2_3 static void outputf(int color, char* fmt,...)
+__printf_2_3 static void outputf(int color, const char* fmt,...)
 {
        char *msg;
 
@@ -460,7 +454,7 @@ static void add_output_line(char *line)
        rb_add_entry(COLOR_OUTPUT, para_strdup(line));
 }
 
-void para_log(int ll, char *fmt,...)
+void para_log(int ll, const char *fmt,...)
 {
        int color;
        char *msg;
@@ -519,7 +513,7 @@ static void finish(int ret)
 /*
  * exit curses and print given message to stdout/stderr
  */
-__printf_2_3 static void msg_n_exit(int ret, char* fmt, ...)
+__printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...)
 {
        va_list argp;
        FILE *outfd = ret? stderr: stdout;
@@ -536,7 +530,7 @@ static void print_welcome(void)
        int ll = conf.loglevel_arg;
        if (ll > NOTICE)
                return;
-       outputf(COLOR_WELCOME, "Welcome to para_gui " VERSION
+       outputf(COLOR_WELCOME, "Welcome to para_gui " PACKAGE_VERSION
                " \"" CODENAME "\". Theme: %s", theme.name);
        wclrtoeol(bot.win);
 }
@@ -731,9 +725,9 @@ reap_next_child:
        pid = para_reap_child();
        if (pid <= 0)
                return;
-       if (pid == external_cmd_pid) {
-               external_cmd_pid = 0;
-               external_cmd_died = 1;
+       if (pid == cmd_pid) {
+               cmd_pid = 0;
+               cmd_died = 1;
        }
        goto reap_next_child;
 }
@@ -863,14 +857,14 @@ static int open_audiod_pipe(void)
  *
  * EXTERNAL_MODE: Check only signal pipe. Used when an external command
  * is running. During that thime curses is disabled.  Returns when
- * external_cmd_pid == 0.
+ * cmd_pid == 0.
  */
 static int do_select(int mode)
 {
        fd_set rfds;
        int ret;
        int max_fileno, cp_numread = 1;
-       char command_buf[STRINGSIZE] = "";
+       char command_buf[4096] = "";
        int cbo = 0; /* command buf offset */
        struct timeval tv;
 repeat:
@@ -882,36 +876,27 @@ repeat:
        /* audiod pipe */
        if (audiod_pipe < 0)
                audiod_pipe = open_audiod_pipe();
-       if (audiod_pipe >= 0) {
-               FD_SET(audiod_pipe, &rfds);
-               max_fileno = MAX(max_fileno, audiod_pipe);
-       }
-
+       if (audiod_pipe >= 0)
+               para_fd_set(audiod_pipe, &rfds, &max_fileno);
        /* signal pipe */
-       FD_SET(signal_pipe, &rfds);
-       max_fileno = MAX(max_fileno, signal_pipe);
+       para_fd_set(signal_pipe, &rfds, &max_fileno);
        /* command pipe only for COMMAND_MODE */
-       if (command_pipe >= 0 && mode == COMMAND_MODE) {
-               FD_SET(command_pipe, &rfds);
-               max_fileno = MAX(max_fileno, command_pipe);
-       }
-       FD_SET(STDIN_FILENO, &rfds);
-       ret = select(max_fileno + 1, &rfds, NULL, NULL, &tv);
-//     PARA_DEBUG_LOG("select returned %d\n", ret);
-
+       if (command_pipe >= 0 && mode == COMMAND_MODE)
+               para_fd_set(command_pipe, &rfds, &max_fileno);
+       ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
+       if (ret <= 0)
+               goto check_return; /* skip fd checks */
        /* signals */
        if (FD_ISSET(signal_pipe, &rfds)) {
                int sig_nr = para_next_signal();
                if (sig_nr > 0)
                        handle_signal(sig_nr);
        }
-       if (ret <= 0)
-               goto check_return; /* skip fd checks */
        /* read command pipe if ready */
        if (command_pipe >= 0 && mode == COMMAND_MODE &&
                        FD_ISSET(command_pipe, &rfds)) {
                cp_numread = read(command_pipe, command_buf + cbo,
-                       STRINGSIZE - 1 - cbo);
+                       sizeof(command_buf) - 1 - cbo);
                if (cp_numread >= 0)
                        cbo += cp_numread;
                else {
@@ -941,6 +926,16 @@ check_return:
                if (cp_numread <= 0)
                        cbo = 0;
                wrefresh(bot.win);
+               ret = wgetch(top.win);
+               if (ret != ERR && ret != KEY_RESIZE) {
+                       if (command_pipe) {
+                               close(command_pipe);
+                               command_pipe = -1;
+                       }
+                       if (cmd_pid)
+                               kill(cmd_pid, SIGTERM);
+                       return -1;
+               }
                break;
        case GETCH_MODE:
                ret = wgetch(top.win);
@@ -948,8 +943,8 @@ check_return:
                        return ret;
                break;
        case EXTERNAL_MODE:
-               if (external_cmd_died) {
-                       external_cmd_died = 0;
+               if (cmd_died) {
+                       cmd_died = 0;
                        return 0;
                }
        }
@@ -973,17 +968,17 @@ static int send_output(void)
 
 static int client_cmd_cmdline(char *cmd)
 {
-       pid_t pid;
        int ret, fds[3] = {0, 1, 0};
        char *c = make_message(BINDIR "/para_client %s", cmd);
 
        outputf(COLOR_COMMAND, "%s", c);
-       print_in_bar(COLOR_MSG, "executing client command, hit q to abort\n");
-       ret = para_exec_cmdline_pid(&pid, c, fds);
+       print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n");
+       ret = para_exec_cmdline_pid(&cmd_pid, c, fds);
        free(c);
        if (ret < 0)
                return -1;
        command_pipe = fds[1];
+       mark_fd_nonblock(command_pipe);
        return send_output();
 }
 
@@ -992,14 +987,14 @@ static int client_cmd_cmdline(char *cmd)
  */
 static int display_cmd(char *cmd)
 {
-       pid_t pid;
        int fds[3] = {0, 1, 0};
 
-       print_in_bar(COLOR_MSG, "executing display command, hit q to abort");
+       print_in_bar(COLOR_MSG, "executing display command, hit any key to abort");
        outputf(COLOR_COMMAND, "%s", cmd);
-       if (para_exec_cmdline_pid(&pid, cmd, fds) < 0)
+       if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
                return -1;
        command_pipe = fds[1];
+       mark_fd_nonblock(command_pipe);
        return send_output();
 }
 
@@ -1010,10 +1005,11 @@ static int external_cmd(char *cmd)
 {
        int fds[3] = {-1, -1, -1};
 
-       if (external_cmd_pid)
+       if (cmd_pid)
                return -1;
        shutdown_curses();
-       para_exec_cmdline_pid(&external_cmd_pid, cmd, fds);
+       para_exec_cmdline_pid(&cmd_pid, cmd, fds);
+       cmd_died = 0;
        do_select(EXTERNAL_MODE);
        init_curses();
        return 0;
@@ -1088,22 +1084,22 @@ static void com_scroll_up(void)
 {
        struct rb_entry *rbe = NULL;
        unsigned lines;
-       int i, first_rbe, scroll;
+       int i, first_rbe, num_scroll;
 
        /* the entry that is going to vanish */
        rbe = ringbuffer_get(bot_win_rb, scroll_position);
        if (!rbe)
                goto err_out;
-       scroll = NUM_LINES(rbe->len);
+       num_scroll = NUM_LINES(rbe->len);
        first_rbe = first_visible_rbe(&lines);
        if (first_rbe < 0 || (first_rbe == ringbuffer_filled(bot_win_rb) - 1))
                goto err_out;
        scroll_position++;
-       wscrl(bot.win, -scroll);
+       wscrl(bot.win, -num_scroll);
        i = draw_top_rbe(&lines);
        if (i < 0)
                goto err_out;
-       while (i > 0 && lines < scroll) {
+       while (i > 0 && lines < num_scroll) {
                int rbe_lines;
                rbe = ringbuffer_get(bot_win_rb, --i);
                if (!rbe)
@@ -1153,15 +1149,21 @@ static void com_ll_incr(void)
 static void com_reread_conf(void)
 {
        char *cf =configfile_exists();
+       struct gui_cmdline_parser_params params = {
+               .override = 1,
+               .initialize = 1,
+               .check_required = 0,
+               .check_ambiguity = 0
+       };
 
        if (!cf) {
                PARA_WARNING_LOG("%s", "there is no configuration to read");
                return;
        }
        PARA_INFO_LOG("%s", "rereading command line options and config file");
-       cmdline_parser(_argc, _argv, &conf);
-       cmdline_parser_configfile(cf, &conf, 1, 1, 0);
-       PARA_NOTICE_LOG("%s", "configuration read");
+       gui_cmdline_parser(_argc, _argv, &conf);
+       gui_cmdline_parser_config_file(cf, &conf, &params);
+       PARA_NOTICE_LOG("%s", "config file reloaded");
        if (check_key_map_args() < 0)
                finish(EXIT_FAILURE);
 }
@@ -1171,24 +1173,26 @@ static void com_help(void)
        int i;
 
        for (i = 0; i < conf.key_map_given; ++i) {
-               char *s = conf.key_map_arg[i], *handler, *arg,
-                       *desc = "", tmp[MAXLINE];
+               char *handler, *arg, *tmp = para_strdup(conf.key_map_arg[i]);
+               const char *handler_text = "???", *desc = NULL;
 
-               strcpy(tmp, s);
-               if (!split_key_map(tmp, &handler, &arg))
+               if (!split_key_map(tmp, &handler, &arg)) {
+                       free(tmp);
                        return;
-               switch(*handler) {
+               }
+               switch (*handler) {
                        case 'i':
-                               handler = "internal";
+                               handler_text = "internal";
                                desc = command_list[find_cmd_byname(arg)].description;
                                break;
-                       case 'x': handler = "external"; break;
-                       case 'd': handler = "display "; break;
-                       case 'p': handler = "para    "; break;
+                       case 'x': handler_text = "external"; break;
+                       case 'd': handler_text = "display "; break;
+                       case 'p': handler_text = "para    "; break;
                }
-               outputf(COLOR_MSG, "%s\t%s\t%s%s\t%s", tmp, handler, arg,
+               outputf(COLOR_MSG, "%s\t%s\t%s%s\t%s", tmp, handler_text, arg,
                        strlen(arg) < 8? "\t" : "",
-                       desc);
+                       desc? desc : "");
+               free(tmp);
        }
        for (i = 0; command_list[i].handler; i++) {
                struct gui_command gc = command_list[i];
@@ -1199,7 +1203,6 @@ static void com_help(void)
        }
        print_in_bar(COLOR_MSG, "try \"para_gui -h\" or \"para_client help\" "
                "for more info");
-       return;
 }
 
 static void com_shrink_top_win(void)
@@ -1228,7 +1231,8 @@ static void com_enlarge_top_win(void)
 
 static void com_version(void)
 {
-       print_in_bar(COLOR_MSG, "para_gui " VERSION " \"" CODENAME "\"");
+       print_in_bar(COLOR_MSG, "para_gui " PACKAGE_VERSION " \""
+               CODENAME "\"");
 }
 
 static void com_quit(void)
@@ -1316,10 +1320,11 @@ int main(int argc, char *argv[])
        _argc = argc;
        _argv = argv;
 
-       if (cmdline_parser(argc, argv, &conf)) {
+       if (gui_cmdline_parser(argc, argv, &conf)) {
                fprintf(stderr, "parse error while reading command line\n");
                exit(EXIT_FAILURE);
        }
+       HANDLE_VERSION_FLAG("gui", conf);
        init_theme(0, &theme);
        top.lines = theme.top_lines_default;
        if (check_key_map_args() < 0) {
@@ -1332,8 +1337,15 @@ int main(int argc, char *argv[])
                        conf.config_file_arg);
                exit(EXIT_FAILURE);
        }
-       if (cf)
-               cmdline_parser_configfile(cf, &conf, 0, 0, 0);
+       if (cf) {
+               struct gui_cmdline_parser_params params = {
+                       .override = 0,
+                       .initialize = 0,
+                       .check_required = 0,
+                       .check_ambiguity = 0
+               };
+               gui_cmdline_parser_config_file(cf, &conf, &params);
+       }
        if (check_key_map_args() < 0) {
                fprintf(stderr, "invalid key map in config file\n");
                exit(EXIT_FAILURE);