X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=gui.c;h=894fc2f87298962b7f4a8de7729f74f853b7c49c;hp=e53d5c73e41e7f665e4d14bb65d4113216a295ba;hb=405a66cac091943206ea466455638b876942fe1d;hpb=18d37ebfe2d78fc0a0c5ade216aa1b13a89bc768 diff --git a/gui.c b/gui.c index e53d5c73..894fc2f8 100644 --- a/gui.c +++ b/gui.c @@ -53,8 +53,11 @@ static int stat_pipe = -1; static struct gui_args_info conf; static int loglevel; -enum {GETCH_MODE, COMMAND_MODE, EXTERNAL_MODE}; - +enum cmd_status { + CMDS_IDLE, /* no command running */ + CMDS_DCMD, /* para or display command running */ + CMDS_XCMD, /* external command running */ +}; /** * Codes for various colors. @@ -621,19 +624,74 @@ print: 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 struct timeval next_exec; + +static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv) +{ + struct timeval atm, diff; + + if (stat_pipe >= 0) + return para_fd_set(stat_pipe, rfds, max_fileno); + gettimeofday(&atm, NULL); + if (tv_diff(&next_exec, &atm, &diff) > 0) { + *tv = diff; + return; + } + tv->tv_sec = tv->tv_usec = 0; /* min delay */ +} + +static void status_post_select(fd_set *rfds) { static char *buf; static int bufsize, loaded; - int ret, ret2; size_t sz; + pid_t pid; + int ret, ret2; + + if (stat_pipe < 0) { + struct timeval atm; + int fds[3] = {0, 1, 0}; + /* Avoid busy loop */ + gettimeofday(&atm, NULL); + if (tv_diff(&next_exec, &atm, NULL) > 0) + return; + next_exec.tv_sec = atm.tv_sec + 2; + ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds); + if (ret < 0) + return; + ret = mark_fd_nonblocking(fds[1]); + if (ret < 0) { + close(fds[1]); + return; + } + stat_pipe = fds[1]; + return; + } - if (stat_pipe < 0) - return 0; if (loaded >= bufsize) { if (bufsize > 1000 * 1000) { loaded = 0; - return 0; + return; } bufsize += bufsize + 1000; buf = para_realloc(buf, bufsize); @@ -645,33 +703,20 @@ static int read_stat_pipe(fd_set *rfds) 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(""); - } } /* @@ -802,8 +847,11 @@ reap_next_child: ret = para_reap_child(&pid); if (ret <= 0) return; - if (pid == cmd_pid) + if (pid == cmd_pid) { cmd_pid = 0; + init_curses(); + print_in_bar(COLOR_MSG, " "); + } goto reap_next_child; } @@ -893,12 +941,28 @@ out: 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; @@ -917,7 +981,7 @@ static void handle_signal(int sig) return; case SIGUSR1: PARA_NOTICE_LOG("got SIGUSR1, rereading configuration\n"); - com_reread_conf(); + reread_conf(); return; case SIGCHLD: check_sigchld(); @@ -925,149 +989,79 @@ static void handle_signal(int sig) } } -static void status_pre_select(fd_set *rfds, int *max_fileno, struct timeval *tv) +#define COMMAND_BUF_SIZE 32768 + +static enum cmd_status cmd_status(void) { - static struct timeval next_exec, atm, diff; - int ret, fds[3] = {0, 1, 0}; - pid_t pid; + if (command_fds[0] >= 0 || command_fds[1] >= 0) + return CMDS_DCMD; + if (cmd_pid > 0) + return CMDS_XCMD; + return CMDS_IDLE; +} - if (stat_pipe >= 0) - goto success; - /* Avoid busy loop */ - gettimeofday(&atm, NULL); - if (tv_diff(&next_exec, &atm, &diff) > 0) { - if (tv_diff(&diff, tv, NULL) < 0) - *tv = diff; - return; - } - next_exec.tv_sec = atm.tv_sec + 2; - ret = para_exec_cmdline_pid(&pid, conf.stat_cmd_arg, fds); - if (ret < 0) - return; - ret = mark_fd_nonblocking(fds[1]); - if (ret < 0) { - close(fds[1]); +static void command_pre_select(fd_set *rfds, int *max_fileno) +{ + enum cmd_status cmds = cmd_status(); + + if (cmds != CMDS_DCMD) return; - } - stat_pipe = fds[1]; -success: - para_fd_set(stat_pipe, rfds, max_fileno); + 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); } -#define COMMAND_BUF_SIZE 32768 - -/* - * 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 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 - * cmd_pid == 0. - */ -static int do_select(int mode) +static void command_post_select(fd_set *rfds) { - fd_set rfds; - int ret, i, max_fileno; - char command_buf[2][COMMAND_BUF_SIZE] = {"", ""}; - int cbo[2] = {0, 0}; /* command buf offsets */ - struct timeval tv; - unsigned flags[2] = {0, 0}; /* for for_each_line() */ + 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() */ + enum cmd_status cmds = cmd_status(); -repeat: - tv.tv_sec = conf.timeout_arg / 1000; - tv.tv_usec = (conf.timeout_arg % 1000) * 1000; -// ret = refresh_status(); - 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); - 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); - /* 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", + if (cmds != CMDS_DCMD) + return; + 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 || cmd_pid == 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 0; - } - if (cbo[i] == COMMAND_BUF_SIZE - 1) { - PARA_NOTICE_LOG("discarding overlong line\n"); - cbo[i] = 0; - flags[i] = FELF_DISCARD_FIRST; - } + close(command_fds[i]); + command_fds[i] = -1; + flags[i] = 0; + cbo[i] = 0; + if (command_fds[!i] < 0) /* both fds closed */ + return; } - } - 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: - ret = wgetch(top.win); - if (ret != ERR && ret != KEY_RESIZE) { - if (cmd_pid) - kill(cmd_pid, SIGTERM); - return -1; + if (cbo[i] == COMMAND_BUF_SIZE - 1) { + PARA_NOTICE_LOG("discarding overlong line"); + cbo[i] = 0; + flags[i] = FELF_DISCARD_FIRST; } - 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; } - goto repeat; +} + +static void input_pre_select(fd_set *rfds, int *max_fileno) +{ + enum cmd_status cmds = cmd_status(); + + if (cmds != CMDS_XCMD) + para_fd_set(STDIN_FILENO, rfds, max_fileno); } /* read from command pipe and print data to bot window */ @@ -1087,11 +1081,6 @@ static void exec_and_display_cmd(const char *cmd) goto fail; command_fds[0] = fds[1]; command_fds[1] = fds[2]; - if (do_select(COMMAND_MODE) >= 0) - PARA_INFO_LOG("command complete\n"); - else - PARA_NOTICE_LOG("command aborted\n"); - print_in_bar(COLOR_MSG, " "); return; fail: PARA_ERROR_LOG("%s\n", para_strerror(-ret)); @@ -1125,10 +1114,102 @@ static void external_cmd(char *cmd) if (cmd_pid) return; shutdown_curses(); - if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0) + para_exec_cmdline_pid(&cmd_pid, cmd, fds); +} + +static void handle_command(int c) +{ + int i; + + /* first check user-defined key bindings */ + for (i = 0; i < conf.key_map_given; ++i) { + char *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))) { + free(tmp); + continue; + } + if (*handler == 'd') + display_cmd(arg); + else if (*handler == 'x') + external_cmd(arg); + else if (*handler == 'p') + para_cmd(arg); + else if (*handler == 'i') { + int num = find_cmd_byname(arg); + if (num >= 0) + command_list[num].handler(); + } + free(tmp); return; - do_select(EXTERNAL_MODE); - init_curses(); + } + /* not found, check internal key bindings */ + for (i = 0; command_list[i].handler; i++) { + if (!strcmp(km_keyname(c), command_list[i].key)) { + command_list[i].handler(); + return; + } + } + print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help", + km_keyname(c)); +} + +static void input_post_select(void) +{ + int ret; + enum cmd_status cmds = cmd_status(); + + if (cmds == CMDS_XCMD) + return; + ret = wgetch(top.win); + if (ret == ERR || ret == KEY_RESIZE) + return; + if (cmds == CMDS_IDLE) + return handle_command(ret); + if (cmd_pid != 0) + kill(cmd_pid, SIGTERM); +} + +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. It checks the following fds: + * + * - signal pipe + * - stdin + * - stdout/stderr of display or internal commands + */ +__noreturn static void do_select(void) +{ + fd_set rfds; + int ret, max_fileno; + struct timeval tv; + +repeat: + tv.tv_sec = conf.timeout_arg / 1000; + tv.tv_usec = (conf.timeout_arg % 1000) * 1000; + FD_ZERO(&rfds); + max_fileno = 0; + status_pre_select(&rfds, &max_fileno, &tv); + signal_pre_select(&rfds, &max_fileno); + command_pre_select(&rfds, &max_fileno); + input_pre_select(&rfds, &max_fileno); + ret = para_select(max_fileno + 1, &rfds, NULL, &tv); + if (ret <= 0) + goto repeat; /* skip fd checks */ + signal_post_select(&rfds); + command_post_select(&rfds); + status_post_select(&rfds); + input_post_select(); + goto repeat; } static void print_scroll_msg(void) @@ -1296,19 +1377,9 @@ static void com_ll_incr(void) print_in_bar(COLOR_MSG, "loglevel set to %d\n", loglevel); } -/* - * reread configuration, terminate on errors - */ static void com_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"); + reread_conf(); } static void com_help(void) @@ -1400,48 +1471,6 @@ static void com_prev_theme(void) com_refresh(); } -static void handle_command(int c) -{ - int i; - - /* first check user-defined key bindings */ - for (i = 0; i < conf.key_map_given; ++i) { - char *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))) { - free(tmp); - continue; - } - if (*handler == 'd') - display_cmd(arg); - else if (*handler == 'x') - external_cmd(arg); - else if (*handler == 'p') - para_cmd(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++) { - if (!strcmp(km_keyname(c), command_list[i].key)) { - command_list[i].handler(); - return; - } - } - print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help", - km_keyname(c)); -} - __noreturn static void print_help_and_die(void) { struct ggo_help h = DEFINE_GGO_HELP(gui); @@ -1453,8 +1482,6 @@ __noreturn static void print_help_and_die(void) int main(int argc, char *argv[]) { - int ret; - gui_cmdline_parser(argc, argv, &conf); /* exits on errors */ loglevel = get_loglevel_by_name(conf.loglevel_arg); version_handle_flag("gui", conf.version_given); @@ -1466,12 +1493,5 @@ int main(int argc, char *argv[]) setlocale(LC_CTYPE, ""); initscr(); /* needed only once, always successful */ init_curses(); - for (;;) { - print_status_bar(); - ret = do_select(GETCH_MODE); - if (!ret) - continue; - print_in_bar(COLOR_MSG, " "); - handle_command(ret); - } + do_select(); }