Pass full argument list to mood parsers.
[paraslash.git] / gui.c
diff --git a/gui.c b/gui.c
index 2513db6d4ad17746af1ece48e2b9b4a21a1efbac..e734b10c8e9e57438075a14a2cc1941f0c28a7b1 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -1,42 +1,34 @@
 /*
 /*
- * Copyright (C) 1998-2006 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1998-2009 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 */
+/** \file gui.c Curses-based interface for paraslash. */
 
 
+#include <signal.h>
+#include <sys/types.h>
+#include <dirent.h>
 #include "gui.cmdline.h"
 #include "para.h"
 #include "gui.cmdline.h"
 #include "para.h"
+#include "gui.h"
+#include "string.h"
 #include <curses.h>
 #include "ringbuffer.h"
 #include <curses.h>
 #include "ringbuffer.h"
-#include "string.h"
 #include "fd.h"
 #include "error.h"
 #include "fd.h"
 #include "error.h"
+#include "list.h"
+#include "sched.h"
+#include "signal.h"
 
 /** define the array of error lists needed by para_gui */
 INIT_GUI_ERRLISTS;
 
 /** 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 " PACKAGE_VERSION " (hit ? for help)"
 
 static int signal_pipe;
 
 static char *stat_content[NUM_STAT_ITEMS];
 
 #define STANDARD_STATUS_BAR "para_gui " PACKAGE_VERSION " (hit ? for help)"
 
 static int signal_pipe;
 
-static void finish(int sig);
-
 static struct win_data {
        WINDOW *win;
        NCURSES_SIZE_T begx;
 static struct win_data {
        WINDOW *win;
        NCURSES_SIZE_T begx;
@@ -51,7 +43,7 @@ struct rb_entry {
        size_t len;
        int color;
 };
        size_t len;
        int color;
 };
-void *bot_win_rb;
+struct ringbuffer *bot_win_rb;
 #define NUM_LINES(len) (1 + (len) / bot.cols)
 
 static unsigned scroll_position;
 #define NUM_LINES(len) (1 + (len) / bot.cols)
 
 static unsigned scroll_position;
@@ -66,15 +58,15 @@ static struct gui_args_info conf;
 enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
 
 
 enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
 
 
-#define COLOR_STATUSBAR 32
-#define COLOR_COMMAND 33
-#define COLOR_OUTPUT 34
-#define COLOR_MSG 35
-#define COLOR_ERRMSG 36
-#define COLOR_WELCOME 37
-#define COLOR_SEPARATOR 38
-#define COLOR_TOP 39
-#define COLOR_BOT 40
+#define COLOR_STATUSBAR 52
+#define COLOR_COMMAND 53
+#define COLOR_OUTPUT 54
+#define COLOR_MSG 55
+#define COLOR_ERRMSG 56
+#define COLOR_WELCOME 57
+#define COLOR_SEPARATOR 58
+#define COLOR_TOP 59
+#define COLOR_BOT 60
 
 struct gui_command {
        const char *key;
 
 struct gui_command {
        const char *key;
@@ -197,6 +189,20 @@ struct gui_command command_list[] = {
        }
 };
 
        }
 };
 
+static int para_open_audiod_pipe(char *cmd)
+{
+       int fds[3] = {0, 1, 0};
+       pid_t pid;
+       int ret = para_exec_cmdline_pid(&pid, cmd, fds);
+       if (ret < 0)
+               return ret;
+       ret = mark_fd_nonblocking(fds[1]);
+       if (ret > 0)
+               return fds[1];
+       close(fds[1]);
+       return ret;
+}
+
 static int find_cmd_byname(char *name)
 {
        int i;
 static int find_cmd_byname(char *name)
 {
        int i;
@@ -288,20 +294,23 @@ static void add_spaces(WINDOW* win, unsigned int num)
  * print aligned string to curses window. This function always prints
  * exactly len chars.
  */
  * print aligned string to curses window. This function always prints
  * exactly len chars.
  */
-static int align_str(WINDOW* win, const char *string, unsigned int len,
+static int align_str(WINDOW* win, char *str, unsigned int len,
                unsigned int align)
 {
                unsigned int align)
 {
-       int num; /* of spaces */
-       char *str;
+       int i, num; /* of spaces */
 
 
-       if (!win || !string)
+       if (!win || !str)
                return -1;
                return -1;
-       num = len - strlen(string);
-       str = para_strdup(string);
+       num = len - strlen(str);
        if (num < 0) {
                str[len] = '\0';
                num = 0;
        }
        if (num < 0) {
                str[len] = '\0';
                num = 0;
        }
+       /* replace newlines by spaces */
+       for (i = 0; i < len; i++) {
+               if (str[i] == '\n')
+                       str[i] = ' ';
+       }
        if (align == LEFT) {
                waddstr(win, str);
                add_spaces(win, num);
        if (align == LEFT) {
                waddstr(win, str);
                add_spaces(win, num);
@@ -313,7 +322,6 @@ static int align_str(WINDOW* win, const char *string, unsigned int len,
                waddstr(win, str[0]? str: "");
                add_spaces(win, num - num / 2);
        }
                waddstr(win, str[0]? str: "");
                add_spaces(win, num - num / 2);
        }
-       free(str);
        return 1;
 }
 
        return 1;
 }
 
@@ -336,10 +344,14 @@ __printf_2_3 static void print_in_bar(int color, const char *fmt,...)
  */
 static void print_status_bar(void)
 {
  */
 static void print_status_bar(void)
 {
+       char *tmp;
+
        if (!curses_active)
                return;
        if (!curses_active)
                return;
+       tmp = para_strdup(STANDARD_STATUS_BAR);
        wmove(sb.win, 0, 0);
        wmove(sb.win, 0, 0);
-       align_str(sb.win, STANDARD_STATUS_BAR, sb.cols, CENTER);
+       align_str(sb.win, tmp, sb.cols, CENTER);
+       free(tmp);
        wrefresh(sb.win);
 }
 
        wrefresh(sb.win);
 }
 
@@ -457,24 +469,27 @@ __printf_2_3 static void outputf(int color, const char* fmt,...)
        wrefresh(bot.win);
 }
 
        wrefresh(bot.win);
 }
 
-static void add_output_line(char *line)
+static int add_output_line(char *line, __a_unused void *data)
 {
        if (!curses_active)
 {
        if (!curses_active)
-               return;
+               return 1;
        rb_add_entry(COLOR_OUTPUT, para_strdup(line));
        rb_add_entry(COLOR_OUTPUT, para_strdup(line));
+       return 1;
 }
 
 }
 
-void para_log(int ll, const char *fmt,...)
+static int loglevel;
+
+__printf_2_3 void para_log(int ll, const char *fmt,...)
 {
        int color;
        char *msg;
 
 {
        int color;
        char *msg;
 
-       if (ll < conf.loglevel_arg || !curses_active)
+       if (ll < loglevel || !curses_active)
                return;
        switch (ll) {
                return;
        switch (ll) {
-               case DEBUG:
-               case INFO:
-               case NOTICE:
+               case LL_DEBUG:
+               case LL_INFO:
+               case LL_NOTICE:
                        color = COLOR_MSG;
                        break;
                default:
                        color = COLOR_MSG;
                        break;
                default:
@@ -494,13 +509,12 @@ static void setup_signal_handling(void)
        para_install_sighandler(SIGCHLD);
        para_install_sighandler(SIGWINCH);
        para_install_sighandler(SIGUSR1);
        para_install_sighandler(SIGCHLD);
        para_install_sighandler(SIGWINCH);
        para_install_sighandler(SIGUSR1);
-       signal(SIGPIPE, SIG_IGN);
-       signal(SIGHUP, SIG_IGN);
+       para_sigaction(SIGHUP, SIG_IGN);
 }
 
 }
 
-static void do_exit(int ret)
+__noreturn static void do_exit(int ret)
 {
 {
-       signal(SIGTERM, SIG_IGN);
+       para_sigaction(SIGTERM, SIG_IGN);
        kill(0, SIGTERM);
        exit(ret);
 }
        kill(0, SIGTERM);
        exit(ret);
 }
@@ -514,7 +528,7 @@ static void shutdown_curses(void)
        endwin();
 }
 
        endwin();
 }
 
-static void finish(int ret)
+__noreturn static void finish(int ret)
 {
        shutdown_curses();
        do_exit(ret);
 {
        shutdown_curses();
        do_exit(ret);
@@ -523,7 +537,7 @@ static void finish(int ret)
 /*
  * exit curses and print given message to stdout/stderr
  */
 /*
  * exit curses and print given message to stdout/stderr
  */
-__printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...)
+__noreturn __printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...)
 {
        va_list argp;
        FILE *outfd = ret? stderr: stdout;
 {
        va_list argp;
        FILE *outfd = ret? stderr: stdout;
@@ -537,8 +551,7 @@ __printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...)
 
 static void print_welcome(void)
 {
 
 static void print_welcome(void)
 {
-       int ll = conf.loglevel_arg;
-       if (ll > NOTICE)
+       if (loglevel > LL_NOTICE)
                return;
        outputf(COLOR_WELCOME, "Welcome to para_gui " PACKAGE_VERSION
                " \"" CODENAME "\". Theme: %s", theme.name);
                return;
        outputf(COLOR_WELCOME, "Welcome to para_gui " PACKAGE_VERSION
                " \"" CODENAME "\". Theme: %s", theme.name);
@@ -654,7 +667,6 @@ static void print_stat_item(int i)
        if (!curses_active || !d.len || !c)
                return;
        tmp = make_message("%s%s%s", d.prefix, c, d.postfix);
        if (!curses_active || !d.len || !c)
                return;
        tmp = make_message("%s%s%s", d.prefix, c, d.postfix);
-//     PARA_DEBUG_LOG("%s: read: %s\n", __func__, tmp);
        wmove(top.win, d.y * top.lines / 100, d.x * COLS / 100);
        wrefresh(top.win);
        wattron(top.win, COLOR_PAIR(i + 1));
        wmove(top.win, d.y * top.lines / 100, d.x * COLS / 100);
        wrefresh(top.win);
        wattron(top.win, COLOR_PAIR(i + 1));
@@ -663,20 +675,55 @@ static void print_stat_item(int i)
        wrefresh(top.win);
 }
 
        wrefresh(top.win);
 }
 
+static int update_item(int item_num, char *buf)
+{
+       free(stat_content[item_num]);
+       stat_content[item_num] = para_strdup(buf);
+       print_stat_item(item_num);
+       return 1;
+}
+
+static int read_audiod_pipe(int fd)
+{
+       static char *buf;
+       static int bufsize, loaded;
+       int ret;
+
+       if (loaded >= bufsize) {
+               if (bufsize > 1000 * 1000) {
+                       loaded = 0;
+                       return 0;
+               }
+               bufsize += bufsize + 1000;
+               buf = para_realloc(buf, bufsize);
+       }
+       assert(loaded < bufsize);
+       ret = read(fd, buf + loaded, bufsize - loaded);
+       if (ret <= 0)
+               return ret;
+       loaded += ret;
+       ret = for_each_stat_item(buf, loaded, update_item);
+       if (ret < 0)
+               return ret;
+       loaded = ret;
+       return 1;
+}
+
 static void print_all_items(void)
 {
        int i;
 
        if (!curses_active)
                return;
 static void print_all_items(void)
 {
        int i;
 
        if (!curses_active)
                return;
-       for (i = 0; i < NUM_STAT_ITEMS; i++)
+       FOR_EACH_STATUS_ITEM(i)
                print_stat_item(i);
 }
                print_stat_item(i);
 }
+
 static void clear_all_items(void)
 {
        int i;
 
 static void clear_all_items(void)
 {
        int i;
 
-       for (i = 0; i < NUM_STAT_ITEMS; i++) {
+       FOR_EACH_STATUS_ITEM(i) {
                free(stat_content[i]);
                stat_content[i] = para_strdup("");
        }
                free(stat_content[i]);
                stat_content[i] = para_strdup("");
        }
@@ -685,10 +732,11 @@ static void clear_all_items(void)
 static void init_colors(void)
 {
        int i;
 static void init_colors(void)
 {
        int i;
+
        if (!has_colors())
                msg_n_exit(EXIT_FAILURE, "Error: No color term\n");
        start_color();
        if (!has_colors())
                msg_n_exit(EXIT_FAILURE, "Error: No color term\n");
        start_color();
-       for (i = 0; i < NUM_STAT_ITEMS; i++)
+       FOR_EACH_STATUS_ITEM(i)
                if (theme.data[i].len)
                        init_pair(i + 1, theme.data[i].fg, theme.data[i].bg);
        init_pair(COLOR_STATUSBAR, theme.sb_fg, theme.sb_bg);
                if (theme.data[i].len)
                        init_pair(i + 1, theme.data[i].fg, theme.data[i].bg);
        init_pair(COLOR_STATUSBAR, theme.sb_fg, theme.sb_bg);
@@ -730,10 +778,11 @@ static void init_curses(void)
 
 static void check_sigchld(void)
 {
 
 static void check_sigchld(void)
 {
+       int ret;
        pid_t pid;
 reap_next_child:
        pid_t pid;
 reap_next_child:
-       pid = para_reap_child();
-       if (pid <= 0)
+       ret = para_reap_child(&pid);
+       if (ret <= 0)
                return;
        if (pid == cmd_pid) {
                cmd_pid = 0;
                return;
        if (pid == cmd_pid) {
                cmd_pid = 0;
@@ -742,24 +791,6 @@ reap_next_child:
        goto reap_next_child;
 }
 
        goto reap_next_child;
 }
 
-/*
- * print status line if line starts with known command.
- */
-static void check_stat_line(char *line)
-{
-       int i;
-
-//     PARA_INFO_LOG("%s: checking: %s\n", __func__, line);
-       i = stat_line_valid(line);
-       if (i >= 0) {
-               line += strlen(status_item_list[i]) + 1;
-               free(stat_content[i]);
-               stat_content[i] = para_strdup(line);
-               print_stat_item(i);
-       }
-       return;
-}
-
 /*
  * This sucker modifies its first argument. *handler and *arg are
  * pointers to 0-terminated strings (inside line). Crap.
 /*
  * This sucker modifies its first argument. *handler and *arg are
  * pointers to 0-terminated strings (inside line). Crap.
@@ -829,13 +860,13 @@ static void handle_signal(int sig)
                }
                return;
        case SIGINT:
                }
                return;
        case SIGINT:
-               PARA_WARNING_LOG("%s", "caught SIGINT, reset");
-               /* Nothing to do. SIGINT killed our child, para_client stat.
-                * This get noticed by do_select which resets everything
+               PARA_WARNING_LOG("caught SIGINT, reset");
+               /* Nothing to do. SIGINT killed our child which gets noticed
+                * by do_select and resets everything.
                 */
                return;
        case SIGUSR1:
                 */
                return;
        case SIGUSR1:
-               PARA_NOTICE_LOG("%s", "got SIGUSR1, rereading configuration");
+               PARA_NOTICE_LOG("got SIGUSR1, rereading configuration");
                com_reread_conf();
                return;
        case SIGCHLD:
                com_reread_conf();
                return;
        case SIGCHLD:
@@ -866,7 +897,7 @@ static int open_audiod_pipe(void)
  * when any key is pressed.
  *
  * EXTERNAL_MODE: Check only signal pipe. Used when an external command
  * when any key is pressed.
  *
  * EXTERNAL_MODE: Check only signal pipe. Used when an external command
- * is running. During that thime curses is disabled.  Returns when
+ * is running. During that time curses is disabled.  Returns when
  * cmd_pid == 0.
  */
 static int do_select(int mode)
  * cmd_pid == 0.
  */
 static int do_select(int mode)
@@ -874,7 +905,7 @@ static int do_select(int mode)
        fd_set rfds;
        int ret;
        int max_fileno, cp_numread = 1;
        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:
        int cbo = 0; /* command buf offset */
        struct timeval tv;
 repeat:
@@ -906,7 +937,7 @@ repeat:
        if (command_pipe >= 0 && mode == COMMAND_MODE &&
                        FD_ISSET(command_pipe, &rfds)) {
                cp_numread = read(command_pipe, command_buf + cbo,
        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 {
                if (cp_numread >= 0)
                        cbo += cp_numread;
                else {
@@ -917,12 +948,12 @@ repeat:
                }
        }
        if (audiod_pipe >= 0 && FD_ISSET(audiod_pipe, &rfds))
                }
        }
        if (audiod_pipe >= 0 && FD_ISSET(audiod_pipe, &rfds))
-               if (read_audiod_pipe(audiod_pipe, check_stat_line) <= 0) {
+               if (read_audiod_pipe(audiod_pipe) <= 0) {
                        close(audiod_pipe);
                        audiod_pipe = -1;
                        clear_all_items();
                        close(audiod_pipe);
                        audiod_pipe = -1;
                        clear_all_items();
-                       free(stat_content[SI_STATUS_BAR]);
-                       stat_content[SI_STATUS_BAR] =
+                       free(stat_content[SI_BASENAME]);
+                       stat_content[SI_BASENAME] =
                                para_strdup("audiod not running!?");
                        print_all_items();
                }
                                para_strdup("audiod not running!?");
                        print_all_items();
                }
@@ -932,7 +963,8 @@ check_return:
                if (cp_numread <= 0 && !cbo) /* command complete */
                        return 0;
                if (cbo)
                if (cp_numread <= 0 && !cbo) /* command complete */
                        return 0;
                if (cbo)
-                       cbo = for_each_line(command_buf, cbo, &add_output_line);
+                       cbo = for_each_line(command_buf, cbo,
+                               &add_output_line, NULL);
                if (cp_numread <= 0)
                        cbo = 0;
                wrefresh(bot.win);
                if (cp_numread <= 0)
                        cbo = 0;
                wrefresh(bot.win);
@@ -966,12 +998,19 @@ check_return:
  */
 static int send_output(void)
 {
  */
 static int send_output(void)
 {
+       int ret;
+
        if (command_pipe < 0)
                return 0;
        if (command_pipe < 0)
                return 0;
+       ret = mark_fd_nonblocking(command_pipe);
+       if (ret < 0) {
+               close(command_pipe);
+               return ret;
+       }
        if (do_select(COMMAND_MODE) >= 0)
        if (do_select(COMMAND_MODE) >= 0)
-               PARA_INFO_LOG("%s", "command complete");
+               PARA_INFO_LOG("command complete");
        else
        else
-               PARA_NOTICE_LOG("%s", "command aborted");
+               PARA_NOTICE_LOG("command aborted");
        print_in_bar(COLOR_MSG, " ");
        return 1;
 }
        print_in_bar(COLOR_MSG, " ");
        return 1;
 }
@@ -979,7 +1018,7 @@ static int send_output(void)
 static int client_cmd_cmdline(char *cmd)
 {
        int ret, fds[3] = {0, 1, 0};
 static int client_cmd_cmdline(char *cmd)
 {
        int ret, fds[3] = {0, 1, 0};
-       char *c = make_message(BINDIR "/para_client %s", cmd);
+       char *c = make_message(BINDIR "/para_client -- %s", cmd);
 
        outputf(COLOR_COMMAND, "%s", c);
        print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n");
 
        outputf(COLOR_COMMAND, "%s", c);
        print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n");
@@ -1054,13 +1093,14 @@ static void com_page_up(void)
 {
        unsigned lines;
        int fvr = first_visible_rbe(&lines);
 {
        unsigned lines;
        int fvr = first_visible_rbe(&lines);
+
        if (fvr < 0 || fvr + 1 >= ringbuffer_filled(bot_win_rb)) {
                print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n");
                return;
        }
        scroll_position = fvr + 1;
        for (; scroll_position > 0; scroll_position--) {
        if (fvr < 0 || fvr + 1 >= ringbuffer_filled(bot_win_rb)) {
                print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n");
                return;
        }
        scroll_position = fvr + 1;
        for (; scroll_position > 0; scroll_position--) {
-               fvr = first_visible_rbe(&lines);
+               first_visible_rbe(&lines);
                if (lines == bot.lines)
                        break;
        }
                if (lines == bot.lines)
                        break;
        }
@@ -1131,24 +1171,24 @@ err_out:
 
 static void com_ll_decr(void)
 {
 
 static void com_ll_decr(void)
 {
-       if (conf.loglevel_arg <= DEBUG) {
+       if (loglevel <= LL_DEBUG) {
                print_in_bar(COLOR_ERRMSG,
                        "loglevel already at maximal verbosity\n");
                return;
        }
                print_in_bar(COLOR_ERRMSG,
                        "loglevel already at maximal verbosity\n");
                return;
        }
-       conf.loglevel_arg--;
-       print_in_bar(COLOR_MSG, "loglevel set to %d\n", conf.loglevel_arg);
+       loglevel--;
+       print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel);
 }
 
 static void com_ll_incr(void)
 {
 }
 
 static void com_ll_incr(void)
 {
-       if (conf.loglevel_arg >= EMERG) {
+       if (loglevel >= LL_EMERG) {
                print_in_bar(COLOR_ERRMSG,
                print_in_bar(COLOR_ERRMSG,
-                       "loglevel already at miminal verbosity\n");
+                       "loglevel already at minimal verbosity\n");
                return;
        }
                return;
        }
-       conf.loglevel_arg++;
-       print_in_bar(COLOR_MSG, "loglevel set to %d\n", conf.loglevel_arg);
+       loglevel++;
+       print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel);
 }
 
 /*
 }
 
 /*
@@ -1157,15 +1197,21 @@ static void com_ll_incr(void)
 static void com_reread_conf(void)
 {
        char *cf =configfile_exists();
 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) {
 
        if (!cf) {
-               PARA_WARNING_LOG("%s", "there is no configuration to read");
+               PARA_WARNING_LOG("there is no configuration to read");
                return;
        }
                return;
        }
-       PARA_INFO_LOG("%s", "rereading command line options and config file");
+       PARA_INFO_LOG("rereading command line options and config file");
        gui_cmdline_parser(_argc, _argv, &conf);
        gui_cmdline_parser(_argc, _argv, &conf);
-       gui_cmdline_parser_configfile(cf, &conf, 1, 1, 0);
-       PARA_NOTICE_LOG("%s", "configuration read");
+       gui_cmdline_parser_config_file(cf, &conf, &params);
+       PARA_NOTICE_LOG("config file reloaded");
        if (check_key_map_args() < 0)
                finish(EXIT_FAILURE);
 }
        if (check_key_map_args() < 0)
                finish(EXIT_FAILURE);
 }
@@ -1210,7 +1256,7 @@ static void com_help(void)
 static void com_shrink_top_win(void)
 {
        if (top.lines <= theme.top_lines_min) {
 static void com_shrink_top_win(void)
 {
        if (top.lines <= theme.top_lines_min) {
-               PARA_WARNING_LOG("%s", "can not decrease top window");
+               PARA_WARNING_LOG("can not decrease top window");
                return;
        }
        init_wins(top.lines - 1);
                return;
        }
        init_wins(top.lines - 1);
@@ -1222,7 +1268,7 @@ static void com_shrink_top_win(void)
 static void com_enlarge_top_win(void)
 {
        if (bot.lines < 3) {
 static void com_enlarge_top_win(void)
 {
        if (bot.lines < 3) {
-               PARA_WARNING_LOG("%s", "can not increase top window");
+               PARA_WARNING_LOG("can not increase top window");
                return;
        }
        init_wins(top.lines + 1);
                return;
        }
        init_wins(top.lines + 1);
@@ -1237,7 +1283,7 @@ static void com_version(void)
                CODENAME "\"");
 }
 
                CODENAME "\"");
 }
 
-static void com_quit(void)
+__noreturn static void com_quit(void)
 {
        finish(0);
 }
 {
        finish(0);
 }
@@ -1326,6 +1372,7 @@ int main(int argc, char *argv[])
                fprintf(stderr, "parse error while reading command line\n");
                exit(EXIT_FAILURE);
        }
                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) {
        init_theme(0, &theme);
        top.lines = theme.top_lines_default;
        if (check_key_map_args() < 0) {
@@ -1338,8 +1385,16 @@ int main(int argc, char *argv[])
                        conf.config_file_arg);
                exit(EXIT_FAILURE);
        }
                        conf.config_file_arg);
                exit(EXIT_FAILURE);
        }
-       if (cf)
-               gui_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);
+       }
+       loglevel = get_loglevel_by_name(conf.loglevel_arg);
        if (check_key_map_args() < 0) {
                fprintf(stderr, "invalid key map in config file\n");
                exit(EXIT_FAILURE);
        if (check_key_map_args() < 0) {
                fprintf(stderr, "invalid key map in config file\n");
                exit(EXIT_FAILURE);