X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gui.c;h=38addd9815cc5bf2775c80278679a1e9c64e872e;hp=d080946a0cab608f67269f6371ac69916d0faf16;hb=69a7e7aa11d8bf9b05d6431c57276befbc9b35a3;hpb=89b30ef7b5ee1bb73b8efa3ccbb53c229066439e diff --git a/gui.c b/gui.c index d080946a..38addd98 100644 --- a/gui.c +++ b/gui.c @@ -1,20 +1,22 @@ /* - * Copyright (C) 1998-2007 Andre Noll + * Copyright (C) 1998-2011 Andre Noll * * 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 #include #include #include +#include + #include "gui.cmdline.h" #include "para.h" #include "gui.h" -#include +#include "string.h" #include "ringbuffer.h" -#include "gui_common.h" #include "fd.h" #include "error.h" #include "list.h" @@ -29,8 +31,6 @@ static char *stat_content[NUM_STAT_ITEMS]; static int signal_pipe; -static void finish(int sig); - static struct win_data { WINDOW *win; NCURSES_SIZE_T begx; @@ -45,7 +45,7 @@ struct rb_entry { size_t len; int color; }; -void *bot_win_rb; +static struct ringbuffer *bot_win_rb; #define NUM_LINES(len) (1 + (len) / bot.cols) static unsigned scroll_position; @@ -54,21 +54,21 @@ static int cmd_died, curses_active; static pid_t cmd_pid; static int command_pipe = -1; -static int audiod_pipe = -1; +static int stat_pipe = -1; static struct gui_args_info conf; 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; @@ -91,8 +91,8 @@ struct stat_item { static struct gui_theme theme; -int _argc; -char **_argv; +static int _argc; +static char **_argv; static void com_help(void); static void com_reread_conf(void); @@ -109,8 +109,10 @@ static void com_scroll_up(void); static void com_scroll_down(void); static void com_page_up(void); static void com_page_down(void); +static void com_cancel_scrolling(void); +static void com_scroll_top(void); -struct gui_command command_list[] = { +static struct gui_command command_list[] = { { .key = "?", .name = "help", @@ -186,6 +188,16 @@ struct gui_command command_list[] = { .name = "page_down", .description = "scroll down one page", .handler = com_page_down + }, { + .key = "", + .name = "scroll_top", + .description = "scroll to top of buffer", + .handler = com_scroll_top + }, { + .key = "", + .name = "cancel_scroll", + .description = "deactivate scroll mode", + .handler = com_cancel_scrolling }, { .handler = NULL } @@ -230,6 +242,14 @@ static char *km_keyname(int c) sprintf(buf, ""); return buf; } + if (c == KEY_HOME) { + sprintf(buf, ""); + return buf; + } + if (c == KEY_END) { + sprintf(buf, ""); + return buf; + } if (c < 256 && c > -128 && iscntrl((unsigned char) c)) { if (c < 0) c += 256; @@ -282,20 +302,23 @@ 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, const char *string, unsigned int len, +static int align_str(WINDOW* win, char *str, unsigned int len, unsigned int align) { - int num; /* of spaces */ - char *str; + int i, num; /* of spaces */ - if (!win || !string) + if (!win || !str) return -1; - num = len - strlen(string); - str = para_strdup(string); + num = len - strlen(str); if (num < 0) { str[len] = '\0'; num = 0; } + /* replace control characters by spaces */ + for (i = 0; i < len && str[i]; i++) { + if (str[i] == '\n' || str[i] == '\r' || str[i] == '\f') + str[i] = ' '; + } if (align == LEFT) { waddstr(win, str); add_spaces(win, num); @@ -307,7 +330,6 @@ static int align_str(WINDOW* win, const char *string, unsigned int len, waddstr(win, str[0]? str: ""); add_spaces(win, num - num / 2); } - free(str); return 1; } @@ -330,10 +352,14 @@ __printf_2_3 static void print_in_bar(int color, const char *fmt,...) */ static void print_status_bar(void) { + char *tmp; + if (!curses_active) return; + tmp = para_strdup(STANDARD_STATUS_BAR); 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); } @@ -374,11 +400,13 @@ static int draw_top_rbe(unsigned *lines) rbe = ringbuffer_get(bot_win_rb, fvr); if (!rbe) return -1; - /* first rbe might be only partially visible */ - offset = (*lines - bot.lines) * bot.cols; len = strlen(rbe->msg); - if (offset < 0 || len < offset) - return -1; + if (*lines > bot.lines) { + /* first rbe is only partially visible */ + offset = (*lines - bot.lines) * bot.cols; + assert(offset <= len); + } else + offset = 0; wattron(bot.win, COLOR_PAIR(rbe->color)); waddstr(bot.win, rbe->msg + offset); *lines = NUM_LINES(len - offset); @@ -459,17 +487,19 @@ static int add_output_line(char *line, __a_unused void *data) 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; - if (ll < conf.loglevel_arg || !curses_active) + if (ll < loglevel || !curses_active) return; switch (ll) { - case DEBUG: - case INFO: - case NOTICE: + case LL_DEBUG: + case LL_INFO: + case LL_NOTICE: color = COLOR_MSG; break; default: @@ -489,13 +519,12 @@ static void setup_signal_handling(void) 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); } @@ -509,7 +538,7 @@ static void shutdown_curses(void) endwin(); } -static void finish(int ret) +__noreturn static void finish(int ret) { shutdown_curses(); do_exit(ret); @@ -518,7 +547,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, 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; @@ -532,8 +561,7 @@ __printf_2_3 static void msg_n_exit(int ret, const char* fmt, ...) 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); @@ -629,14 +657,6 @@ static void init_wins(int top_lines) doupdate(); } -static void check_geometry(void) -{ - if (LINES < theme.lines_min || COLS < theme.cols_min) - msg_n_exit(EXIT_FAILURE, "Error: Terminal (%dx%d) too small" - " (need at least %dx%d)\n", COLS, LINES, - theme.cols_min, theme.lines_min); -} - /* * Print stat item #i to curses window */ @@ -649,7 +669,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); -// 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)); @@ -658,6 +677,70 @@ static void print_stat_item(int i) wrefresh(top.win); } +static int update_item(int item_num, char *buf) +{ + char **c = stat_content + item_num; + + free(*c); + if (buf && buf[0]) + goto dup; + switch (item_num) { + case SI_ARTIST: + *c = para_strdup("(artist tag not set)"); + goto print; + case SI_TITLE: + *c = para_strdup("(title tag not set)"); + goto print; + case SI_YEAR: + *c = para_strdup("????"); + goto print; + case SI_ALBUM: + *c = para_strdup("(album tag not set)"); + goto print; + case SI_COMMENT: + *c = para_strdup("(comment tag not set)"); + goto print; + } +dup: + *c = para_strdup(buf); +print: + print_stat_item(item_num); + return 1; +} + +static int read_stat_pipe(fd_set *rfds) +{ + static char *buf; + static int bufsize, loaded; + int ret, ret2; + size_t sz; + + if (stat_pipe < 0) + return 0; + if (loaded >= bufsize) { + if (bufsize > 1000 * 1000) { + loaded = 0; + return 0; + } + bufsize += bufsize + 1000; + buf = para_realloc(buf, bufsize); + } + assert(loaded < bufsize); + ret = read_nonblock(stat_pipe, buf + loaded, bufsize - loaded, + rfds, &sz); + loaded += sz; + ret2 = for_each_stat_item(buf, loaded, update_item); + if (ret < 0 || ret2 < 0) { + loaded = 0; + return ret2 < 0? ret2 : ret; + } + sz = ret2; /* what is left */ + if (sz > 0 && sz < loaded) + memmove(buf, buf + loaded - sz, sz); + loaded = sz; + return 1; +} + static void print_all_items(void) { int i; @@ -678,52 +761,60 @@ static void clear_all_items(void) } } -static void init_colors(void) +static void init_pair_or_die(short pair, short f, short b) +{ + if (init_pair(pair, f, b) == ERR) + msg_n_exit(EXIT_FAILURE, "fatal: init_pair() failed\n"); +} + +static void init_colors_or_die(void) { int i; + if (!has_colors()) - msg_n_exit(EXIT_FAILURE, "Error: No color term\n"); - start_color(); + msg_n_exit(EXIT_FAILURE, "fatal: No color term\n"); + if (start_color() == ERR) + msg_n_exit(EXIT_FAILURE, "fatal: failed to start colors\n"); 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); - init_pair(COLOR_COMMAND, theme.cmd_fg, theme.cmd_bg); - init_pair(COLOR_OUTPUT, theme.output_fg, theme.output_bg); - init_pair(COLOR_MSG, theme.msg_fg, theme.msg_bg); - init_pair(COLOR_ERRMSG, theme.err_msg_fg, theme.err_msg_bg); - init_pair(COLOR_WELCOME, theme.welcome_fg, theme.welcome_bg); - init_pair(COLOR_SEPARATOR, theme.sep_fg, theme.sep_bg); - init_pair(COLOR_TOP, theme.default_fg, theme.default_bg); - init_pair(COLOR_BOT, theme.default_fg, theme.default_bg); + init_pair_or_die(i + 1, theme.data[i].fg, + theme.data[i].bg); + init_pair_or_die(COLOR_STATUSBAR, theme.sb_fg, theme.sb_bg); + init_pair_or_die(COLOR_COMMAND, theme.cmd_fg, theme.cmd_bg); + init_pair_or_die(COLOR_OUTPUT, theme.output_fg, theme.output_bg); + init_pair_or_die(COLOR_MSG, theme.msg_fg, theme.msg_bg); + init_pair_or_die(COLOR_ERRMSG, theme.err_msg_fg, theme.err_msg_bg); + init_pair_or_die(COLOR_WELCOME, theme.welcome_fg, theme.welcome_bg); + init_pair_or_die(COLOR_SEPARATOR, theme.sep_fg, theme.sep_bg); + init_pair_or_die(COLOR_TOP, theme.default_fg, theme.default_bg); + init_pair_or_die(COLOR_BOT, theme.default_fg, theme.default_bg); } -/* - * (re-)initialize the curses library FIXME: Error checking - */ +/* (Re-)initialize the curses library. */ static void init_curses(void) { curses_active = 1; - if (top.win && refresh() == ERR) { /* refesh is really needed */ + if (top.win && refresh() == ERR) /* refesh is really needed */ msg_n_exit(EXIT_FAILURE, "refresh() failed\n"); - } - check_geometry(); + if (LINES < theme.lines_min || COLS < theme.cols_min) + msg_n_exit(EXIT_FAILURE, "Error: Terminal (%dx%d) too small" + " (need at least %dx%d)\n", COLS, LINES, + theme.cols_min, theme.lines_min); curs_set(0); /* make cursor invisible, ignore errors */ -// if (noraw() == ERR); -// msg_n_exit(EXIT_FAILURE, "can not place terminal out of " -// "raw mode\n"); - nonl(); /* tell curses not to do NL->CR/NL on output */ - noecho(); /* don't echo input */ - cbreak(); /* take input chars one at a time, no wait for \n */ - //reset_prog_mode(); - init_colors(); - clear(); + nonl(); /* do not NL->CR/NL on output, always returns OK */ + /* don't echo input */ + if (noecho() == ERR) + msg_n_exit(EXIT_FAILURE, "fatal: noecho() failed\n"); + /* take input chars one at a time, no wait for \n */ + if (cbreak() == ERR) + msg_n_exit(EXIT_FAILURE, "fatal: cbreak() failed\n"); + init_colors_or_die(); + clear(); /* ignore non-fatal errors */ init_wins(theme.top_lines_default); print_all_items(); - noecho(); /* don't echo input */ + // noecho(); /* don't echo input */ } - static void check_sigchld(void) { int ret; @@ -739,24 +830,6 @@ reap_next_child: goto reap_next_child; } -/* - * print status line if line starts with known command. - */ -static int check_stat_line(char *line, __a_unused void *data) -{ - 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]) + 2; - free(stat_content[i]); - stat_content[i] = para_strdup(line); - print_stat_item(i); - } - return 1; -} - /* * This sucker modifies its first argument. *handler and *arg are * pointers to 0-terminated strings (inside line). Crap. @@ -826,13 +899,13 @@ static void handle_signal(int sig) } 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: - PARA_NOTICE_LOG("%s", "got SIGUSR1, rereading configuration"); + PARA_NOTICE_LOG("got SIGUSR1, rereading configuration"); com_reread_conf(); return; case SIGCHLD: @@ -841,15 +914,30 @@ static void handle_signal(int sig) } } -static int open_audiod_pipe(void) +static int open_stat_pipe(void) { static int init = 1; + int ret, fds[3] = {0, 1, 0}; + pid_t pid; if (init) init = 0; else - sleep(1); - return para_open_audiod_pipe(conf.stat_cmd_arg); + /* + * Sleep a bit to avoid a busy loop. As the call to sleep() may + * be interrupted by SIGCHLD, we simply wait until the call + * succeeds. + */ + while (sleep(2)) + ; /* nothing */ + ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds); + if (ret < 0) + return ret; + ret = mark_fd_nonblocking(fds[1]); + if (ret >= 0) + return fds[1]; + close(fds[1]); + return ret; } /* @@ -863,14 +951,14 @@ static int open_audiod_pipe(void) * 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) { fd_set rfds; int ret; - int max_fileno, cp_numread = 1; + int max_fileno; char command_buf[4096] = ""; int cbo = 0; /* command buf offset */ struct timeval tv; @@ -880,11 +968,10 @@ repeat: // ret = refresh_status(); FD_ZERO(&rfds); max_fileno = 0; - /* audiod pipe */ - if (audiod_pipe < 0) - audiod_pipe = open_audiod_pipe(); - if (audiod_pipe >= 0) - para_fd_set(audiod_pipe, &rfds, &max_fileno); + if (stat_pipe < 0) + stat_pipe = open_stat_pipe(); + if (stat_pipe >= 0) + para_fd_set(stat_pipe, &rfds, &max_fileno); /* signal pipe */ para_fd_set(signal_pipe, &rfds, &max_fileno); /* command pipe only for COMMAND_MODE */ @@ -894,46 +981,41 @@ repeat: 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); - } + ret = para_next_signal(&rfds); + if (ret > 0) + handle_signal(ret); /* 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, - sizeof(command_buf) - 1 - cbo); - if (cp_numread >= 0) - cbo += cp_numread; - else { - if (cp_numread < 0) - PARA_ERROR_LOG("read error (%d)", cp_numread); + 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 (audiod_pipe >= 0 && FD_ISSET(audiod_pipe, &rfds)) - if (read_audiod_pipe(audiod_pipe, check_stat_line) <= 0) { - close(audiod_pipe); - audiod_pipe = -1; - clear_all_items(); - free(stat_content[SI_BASENAME]); - stat_content[SI_BASENAME] = - para_strdup("audiod not running!?"); - print_all_items(); - } + ret = read_stat_pipe(&rfds); + if (ret < 0) { + PARA_NOTICE_LOG("closing stat pipe: %s\n", para_strerror(-ret)); + close(stat_pipe); + stat_pipe = -1; + clear_all_items(); + free(stat_content[SI_BASENAME]); + stat_content[SI_BASENAME] = + para_strdup("stat command terminated!?"); + print_all_items(); + } check_return: switch (mode) { case COMMAND_MODE: - if (cp_numread <= 0 && !cbo) /* command complete */ - return 0; - if (cbo) - cbo = for_each_line(command_buf, cbo, - &add_output_line, NULL); - if (cp_numread <= 0) - cbo = 0; - wrefresh(bot.win); ret = wgetch(top.win); if (ret != ERR && ret != KEY_RESIZE) { if (command_pipe) { @@ -964,12 +1046,19 @@ check_return: */ static int 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; + } if (do_select(COMMAND_MODE) >= 0) - PARA_INFO_LOG("%s", "command complete"); + PARA_INFO_LOG("command complete"); else - PARA_NOTICE_LOG("%s", "command aborted"); + PARA_NOTICE_LOG("command aborted"); print_in_bar(COLOR_MSG, " "); return 1; } @@ -977,7 +1066,7 @@ static int send_output(void) 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"); @@ -986,7 +1075,6 @@ static int client_cmd_cmdline(char *cmd) if (ret < 0) return -1; command_pipe = fds[1]; - mark_fd_nonblocking(command_pipe); return send_output(); } @@ -1002,7 +1090,6 @@ static int display_cmd(char *cmd) if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0) return -1; command_pipe = fds[1]; - mark_fd_nonblocking(command_pipe); return send_output(); } @@ -1031,6 +1118,41 @@ static void print_scroll_msg(void) filled - scroll_position, ringbuffer_filled(bot_win_rb)); } +static void com_scroll_top(void) +{ + int i = RINGBUFFER_SIZE - 1; + unsigned lines = 0; + + while (i > 0 && !ringbuffer_get(bot_win_rb, i)) + i--; + /* i is oldest entry */ + for (; lines < bot.lines && i >= 0; i--) { + struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i); + if (!rbe) + break; + lines += NUM_LINES(strlen(rbe->msg)); + } + i++; + if (lines > 0 && scroll_position != i) { + scroll_position = i; + redraw_bot_win(); + print_scroll_msg(); + return; + } + print_in_bar(COLOR_ERRMSG, "top of buffer is shown\n"); +} + +static void com_cancel_scrolling(void) +{ + + if (scroll_position == 0) { + print_in_bar(COLOR_ERRMSG, "bottom of buffer is shown\n"); + return; + } + scroll_position = 0; + redraw_bot_win(); +} + static void com_page_down(void) { unsigned lines = 0; @@ -1054,13 +1176,14 @@ static void com_page_up(void) { 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--) { - fvr = first_visible_rbe(&lines); + first_visible_rbe(&lines); if (lines == bot.lines) break; } @@ -1131,24 +1254,24 @@ err_out: 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; } - 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) { - if (conf.loglevel_arg >= EMERG) { + if (loglevel >= LL_EMERG) { print_in_bar(COLOR_ERRMSG, - "loglevel already at miminal verbosity\n"); + "loglevel already at minimal 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); } /* @@ -1161,17 +1284,21 @@ static void com_reread_conf(void) .override = 1, .initialize = 1, .check_required = 0, - .check_ambiguity = 0 + .check_ambiguity = 0, + .print_errors = 0, }; if (!cf) { - PARA_WARNING_LOG("%s", "there is no configuration to read"); + PARA_WARNING_LOG("there is no configuration to read"); return; } - PARA_INFO_LOG("%s", "rereading command line options and config file"); - gui_cmdline_parser(_argc, _argv, &conf); - gui_cmdline_parser_config_file(cf, &conf, ¶ms); - PARA_NOTICE_LOG("%s", "config file reloaded"); + PARA_INFO_LOG("rereading command line options and config file"); + gui_cmdline_parser_ext(_argc, _argv, &conf, ¶ms); + if (gui_cmdline_parser_config_file(cf, &conf, ¶ms) != 0) { + PARA_EMERG_LOG("errors in config file"); + finish(EXIT_FAILURE); + } + PARA_NOTICE_LOG("config file reloaded"); if (check_key_map_args() < 0) finish(EXIT_FAILURE); } @@ -1216,7 +1343,7 @@ static void com_help(void) 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); @@ -1228,7 +1355,7 @@ static void com_shrink_top_win(void) 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); @@ -1243,7 +1370,7 @@ static void com_version(void) CODENAME "\""); } -static void com_quit(void) +__noreturn static void com_quit(void) { finish(0); } @@ -1283,31 +1410,30 @@ static void handle_command(int c) /* first check user's key bindings */ for (i = 0; i < conf.key_map_given; ++i) { - char tmp[MAXLINE], *handler, *arg; + char *tmp, *handler, *arg; - strcpy(tmp, conf.key_map_arg[i]); - if (!split_key_map(tmp, &handler, &arg)) + tmp = para_strdup(conf.key_map_arg[i]); + if (!split_key_map(tmp, &handler, &arg)) { + free(tmp); return; - if (!strcmp(tmp, km_keyname(c))) { - if (*handler == 'd') { - display_cmd(arg); - return; - } - if (*handler == 'x') { - external_cmd(arg); - return; - } - if (*handler == 'p') { - client_cmd_cmdline(arg); - return; - } - if (*handler == 'i') { - int num = find_cmd_byname(arg); - if (num >= 0) - command_list[num].handler(); - return; - } } + if (strcmp(tmp, km_keyname(c))) { + free(tmp); + continue; + } + if (*handler == 'd') + display_cmd(arg); + else if (*handler == 'x') + external_cmd(arg); + else if (*handler == 'p') + client_cmd_cmdline(arg); + else if (*handler == 'i') { + int num = find_cmd_byname(arg); + if (num >= 0) + command_list[num].handler(); + } + free(tmp); + return; } /* not found, check internal key bindings */ for (i = 0; command_list[i].handler; i++) { @@ -1328,17 +1454,9 @@ int main(int argc, char *argv[]) _argc = argc; _argv = argv; - if (gui_cmdline_parser(argc, argv, &conf)) { - fprintf(stderr, "parse error while reading command line\n"); + if (gui_cmdline_parser(argc, argv, &conf) != 0) exit(EXIT_FAILURE); - } HANDLE_VERSION_FLAG("gui", conf); - init_theme(0, &theme); - top.lines = theme.top_lines_default; - if (check_key_map_args() < 0) { - fprintf(stderr, "invalid key map\n"); - exit(EXIT_FAILURE); - } cf = configfile_exists(); if (!cf && conf.config_file_given) { fprintf(stderr, "can not read config file %s\n", @@ -1350,14 +1468,19 @@ int main(int argc, char *argv[]) .override = 0, .initialize = 0, .check_required = 0, - .check_ambiguity = 0 + .check_ambiguity = 0, + .print_errors = 1, }; - gui_cmdline_parser_config_file(cf, &conf, ¶ms); + if (gui_cmdline_parser_config_file(cf, &conf, ¶ms) != 0) + exit(EXIT_FAILURE); } + loglevel = get_loglevel_by_name(conf.loglevel_arg); if (check_key_map_args() < 0) { - fprintf(stderr, "invalid key map in config file\n"); + fprintf(stderr, "invalid key map\n"); exit(EXIT_FAILURE); } + init_theme_or_die(conf.theme_arg, &theme); + top.lines = theme.top_lines_default; setup_signal_handling(); bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE); initscr(); /* needed only once, always successful */