static int command_fds[2] = {-1, -1};
static int stat_pipe = -1;
static struct gui_args_info conf;
+static int loglevel;
enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE};
return buf;
}
-static char *configfile_exists(void)
-{
- static char *config_file;
- char *tmp;
-
- if (!conf.config_file_given) {
- if (!config_file) {
- char *home = para_homedir();
- config_file = make_message("%s/.paraslash/gui.conf",
- home);
- free(home);
- }
- tmp = config_file;
- } else
- tmp = conf.config_file_arg;
- return file_exists(tmp)? tmp: NULL;
-}
-
/* Print given number of spaces to curses window. */
static void add_spaces(WINDOW* win, unsigned int num)
{
return 1;
}
-static int loglevel;
-
static __printf_2_3 void curses_log(int ll, const char *fmt,...)
{
va_list ap;
return 1;
}
-static int read_stat_pipe(fd_set *rfds)
+static void print_all_items(void)
+{
+ int i;
+
+ if (!curses_active())
+ return;
+ FOR_EACH_STATUS_ITEM(i)
+ print_stat_item(i);
+}
+
+static void clear_all_items(void)
+{
+ int i;
+
+ FOR_EACH_STATUS_ITEM(i) {
+ free(stat_content[i]);
+ stat_content[i] = para_strdup("");
+ }
+}
+
+static void status_post_select(fd_set *rfds)
{
static char *buf;
static int bufsize, loaded;
size_t sz;
if (stat_pipe < 0)
- return 0;
+ return;
if (loaded >= bufsize) {
if (bufsize > 1000 * 1000) {
loaded = 0;
- return 0;
+ return;
}
bufsize += bufsize + 1000;
buf = para_realloc(buf, bufsize);
ret2 = for_each_stat_item(buf, loaded, update_item);
if (ret < 0 || ret2 < 0) {
loaded = 0;
- return ret2 < 0? ret2 : ret;
+ 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();
+ return;
}
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;
-
- if (!curses_active())
- return;
- FOR_EACH_STATUS_ITEM(i)
- print_stat_item(i);
-}
-
-static void clear_all_items(void)
-{
- int i;
-
- FOR_EACH_STATUS_ITEM(i) {
- free(stat_content[i]);
- stat_content[i] = para_strdup("");
- }
}
/*
free(tmp);
}
+static void parse_config_file_or_die(bool override)
+{
+ bool err;
+ char *config_file;
+ struct gui_cmdline_parser_params params = {
+ .override = override,
+ .initialize = 0,
+ .check_required = !override,
+ .check_ambiguity = 0,
+ .print_errors = 1,
+ };
+
+ if (conf.config_file_given)
+ config_file = para_strdup(conf.config_file_arg);
+ else {
+ char *home = para_homedir();
+ config_file = make_message("%s/.paraslash/gui.conf", home);
+ free(home);
+ }
+ if (!file_exists(config_file)) {
+ if (!conf.config_file_given)
+ err = false;
+ else {
+ PARA_EMERG_LOG("config file %s does not exist\n",
+ config_file);
+ err = true;
+ }
+ goto out;
+ }
+ gui_cmdline_parser_config_file(config_file, &conf, ¶ms);
+ loglevel = get_loglevel_by_name(conf.loglevel_arg);
+ check_key_map_args_or_die();
+ theme_init(conf.theme_arg, &theme);
+ err = false;
+out:
+ free(config_file);
+ if (err)
+ exit(EXIT_FAILURE);
+}
+
+/* reread configuration, terminate on errors */
+static void reread_conf(void)
+{
+ /*
+ * gengetopt might print to stderr and exit on errors. So we have to
+ * shutdown curses first.
+ */
+ shutdown_curses();
+ parse_config_file_or_die(true /* override */);
+ init_curses();
+ print_in_bar(COLOR_MSG, "config file reloaded\n");
+}
+
/*
* React to various signal-related events
*/
-static void handle_signal(int sig)
+static void signal_post_select(fd_set *rfds)
{
- switch (sig) {
+ int ret = para_next_signal(rfds);
+ if (ret <= 0)
+ return;
+ switch (ret) {
case SIGTERM:
die(EXIT_FAILURE, "only the good die young (caught SIGTERM)\n");
return;
return;
case SIGUSR1:
PARA_NOTICE_LOG("got SIGUSR1, rereading configuration\n");
- com_reread_conf();
+ reread_conf();
return;
case SIGCHLD:
check_sigchld();
#define COMMAND_BUF_SIZE 32768
+static void command_pre_select(int mode, fd_set *rfds, int *max_fileno)
+{
+ /* check command pipe only in COMMAND_MODE */
+ if (mode != COMMAND_MODE)
+ return;
+ 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);
+}
+
+static int command_post_select(int mode, fd_set *rfds)
+{
+ int i, ret;
+ static char command_buf[2][COMMAND_BUF_SIZE];
+ static int cbo[2]; /* command buf offsets */
+ static unsigned flags[2]; /* for for_each_line() */
+
+ if (mode != COMMAND_MODE)
+ return 0;
+ 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(flags[i], command_buf[i], cbo[i],
+ add_output_line, &i);
+ if (sz != cbo[i]) { /* at least one line found */
+ wrefresh(bot.win);
+ flags[i] = 0;
+ }
+ if (ret < 0) {
+ PARA_NOTICE_LOG("closing command fd %d: %s",
+ i, para_strerror(-ret));
+ close(command_fds[i]);
+ command_fds[i] = -1;
+ flags[i] = 0;
+ cbo[i] = 0;
+ if (command_fds[!i] < 0) /* both fds closed */
+ return -1;
+ }
+ if (cbo[i] == COMMAND_BUF_SIZE - 1) {
+ PARA_NOTICE_LOG("discarding overlong line");
+ cbo[i] = 0;
+ flags[i] = FELF_DISCARD_FIRST;
+ }
+ }
+ return 1;
+}
+
+static void input_pre_select(int mode, fd_set *rfds, int *max_fileno)
+{
+ if (mode == GETCH_MODE || mode == COMMAND_MODE)
+ para_fd_set(STDIN_FILENO, rfds, max_fileno);
+}
+
+static int input_post_select(int mode)
+{
+ int ret;
+
+ switch (mode) {
+ case COMMAND_MODE:
+ ret = wgetch(top.win);
+ if (ret != ERR && ret != KEY_RESIZE) {
+ if (cmd_pid)
+ kill(cmd_pid, SIGTERM);
+ return -1;
+ }
+ return 0;
+ case GETCH_MODE:
+ ret = wgetch(top.win);
+ if (ret != ERR && ret != KEY_RESIZE)
+ return ret;
+ return 0;
+ case EXTERNAL_MODE:
+ if (cmd_pid == 0)
+ return -1;
+ return 0;
+ default:
+ assert(false); /* bug */
+ }
+}
+
+static void signal_pre_select(fd_set *rfds, int *max_fileno)
+{
+ para_fd_set(signal_pipe, rfds, max_fileno);
+}
+
/*
* This is the core select loop. Besides the (internal) signal
* pipe, the following other fds are checked according to the mode:
static int do_select(int mode)
{
fd_set rfds;
- int ret, i, max_fileno;
- char command_buf[2][COMMAND_BUF_SIZE] = {"", ""};
- int cbo[2] = {0, 0}; /* command buf offsets */
+ int ret, max_fileno;
struct timeval tv;
- unsigned flags[2] = {0, 0}; /* for for_each_line() */
repeat:
tv.tv_sec = conf.timeout_arg / 1000;
FD_ZERO(&rfds);
max_fileno = 0;
status_pre_select(&rfds, &max_fileno, &tv);
- /* signal pipe */
- para_fd_set(signal_pipe, &rfds, &max_fileno);
- /* command pipe only for COMMAND_MODE */
- 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);
- }
- if (mode == GETCH_MODE || mode == COMMAND_MODE)
- para_fd_set(STDIN_FILENO, &rfds, &max_fileno);
+ signal_pre_select(&rfds, &max_fileno);
+ command_pre_select(mode, &rfds, &max_fileno);
+ input_pre_select(mode, &rfds, &max_fileno);
ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
if (ret <= 0)
goto check_return; /* skip fd checks */
- /* signals */
- ret = para_next_signal(&rfds);
- if (ret > 0)
- handle_signal(ret);
+ signal_post_select(&rfds);
/* read command pipe if ready */
- 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(flags[i], command_buf[i], cbo[i],
- add_output_line, &i);
- if (sz != cbo[i]) { /* at least one line found */
- wrefresh(bot.win);
- flags[i] = 0;
- }
- if (ret < 0) {
- PARA_NOTICE_LOG("closing command fd %d: %s\n",
- i, para_strerror(-ret));
- close(command_fds[i]);
- command_fds[i] = -1;
- flags[i] = 0;
- cbo[i] = 0;
- if (command_fds[!i] < 0) /* both fds closed */
- return 0;
- }
- if (cbo[i] == COMMAND_BUF_SIZE - 1) {
- PARA_NOTICE_LOG("discarding overlong line\n");
- cbo[i] = 0;
- flags[i] = FELF_DISCARD_FIRST;
- }
- }
- }
- 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();
- }
+ ret = command_post_select(mode, &rfds);
+ if (ret < 0)
+ return 0;
+ status_post_select(&rfds);
check_return:
- switch (mode) {
- case COMMAND_MODE:
- ret = wgetch(top.win);
- if (ret != ERR && ret != KEY_RESIZE) {
- if (cmd_pid)
- kill(cmd_pid, SIGTERM);
- return -1;
- }
- break;
- case GETCH_MODE:
- ret = wgetch(top.win);
- if (ret != ERR && ret != KEY_RESIZE)
- return ret;
- break;
- case EXTERNAL_MODE:
- if (cmd_pid == 0)
- return 0;
- }
+ ret = input_post_select(mode);
+ if (ret != 0)
+ return ret;
goto repeat;
}
print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel);
}
-/*
- * reread configuration, terminate on errors
- */
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,
- .print_errors = 0,
- };
-
- if (!cf) {
- PARA_WARNING_LOG("there is no configuration to read\n");
- return;
- }
- PARA_INFO_LOG("rereading command line options and config file\n");
- /*
- * Despite .print_errors is set to 0, gengetopt will print to stderr
- * anyway, and exit on errors. So we have to shutdown curses first.
- */
- shutdown_curses();
- gui_cmdline_parser_config_file(cf, &conf, ¶ms);
- init_curses();
- PARA_NOTICE_LOG("config file reloaded\n");
- check_key_map_args_or_die();
+ reread_conf();
}
static void com_help(void)
int main(int argc, char *argv[])
{
int ret;
- char *cf;
gui_cmdline_parser(argc, argv, &conf); /* exits on errors */
loglevel = get_loglevel_by_name(conf.loglevel_arg);
version_handle_flag("gui", conf.version_given);
if (conf.help_given || conf.detailed_help_given)
print_help_and_die();
- cf = configfile_exists();
- if (!cf && conf.config_file_given)
- die(EXIT_FAILURE, "can not read config file %s\n",
- conf.config_file_arg);
- if (cf) {
- struct gui_cmdline_parser_params params = {
- .override = 0,
- .initialize = 0,
- .check_required = 0,
- .check_ambiguity = 0,
- .print_errors = 1,
- };
- gui_cmdline_parser_config_file(cf, &conf, ¶ms);
- loglevel = get_loglevel_by_name(conf.loglevel_arg);
- }
- check_key_map_args_or_die();
- theme_init(conf.theme_arg, &theme);
+ parse_config_file_or_die(false /* override */);
setup_signal_handling();
bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE);
setlocale(LC_CTYPE, "");