Merge remote branch 'fml/next' into next
[paraslash.git] / gui.c
diff --git a/gui.c b/gui.c
index 9a02bdcabc3c252fb875b893cea5610f23243b2e..5b44819c05afc074fadca3a5a7d5c1ece9fe8b8f 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -1,19 +1,21 @@
 /*
- * Copyright (C) 1998-2008 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1998-2009 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
 
 /** \file gui.c Curses-based interface for paraslash. */
 
+#include <regex.h>
 #include <signal.h>
 #include <sys/types.h>
 #include <dirent.h>
+#include <curses.h>
+
 #include "gui.cmdline.h"
 #include "para.h"
 #include "gui.h"
 #include "string.h"
-#include <curses.h>
 #include "ringbuffer.h"
 #include "fd.h"
 #include "error.h"
@@ -43,7 +45,7 @@ struct rb_entry {
        size_t len;
        int color;
 };
-struct ringbuffer *bot_win_rb;
+static struct ringbuffer *bot_win_rb;
 #define NUM_LINES(len) (1 + (len) / bot.cols)
 
 static unsigned scroll_position;
@@ -89,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);
@@ -108,7 +110,7 @@ static void com_scroll_down(void);
 static void com_page_up(void);
 static void com_page_down(void);
 
-struct gui_command command_list[] = {
+static struct gui_command command_list[] = {
        {
                .key = "?",
                .name = "help",
@@ -203,24 +205,6 @@ static int para_open_audiod_pipe(char *cmd)
        return ret;
 }
 
-static int read_audiod_pipe(int fd, line_handler_t *line_handler)
-{
-       static char buf[4096];
-       const ssize_t bufsize = sizeof(buf) - 1;
-       static ssize_t loaded;
-       ssize_t ret;
-
-       if (loaded >= bufsize)
-               loaded = 0;
-       ret = read(fd, buf + loaded, bufsize - loaded);
-       if (ret > 0) {
-               loaded += ret;
-               buf[loaded] = '\0';
-               loaded = for_each_line(buf, loaded, line_handler, NULL);
-       }
-       return ret;
-}
-
 static int find_cmd_byname(char *name)
 {
        int i;
@@ -312,20 +296,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 newlines by spaces */
+       for (i = 0; i < len && str[i]; i++) {
+               if (str[i] == '\n')
+                       str[i] = ' ';
+       }
        if (align == LEFT) {
                waddstr(win, str);
                add_spaces(win, num);
@@ -337,7 +324,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;
 }
 
@@ -360,10 +346,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);
 }
 
@@ -489,17 +479,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:
@@ -519,13 +511,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);
 }
@@ -539,7 +530,7 @@ static void shutdown_curses(void)
        endwin();
 }
 
-static void finish(int ret)
+__noreturn static void finish(int ret)
 {
        shutdown_curses();
        do_exit(ret);
@@ -548,7 +539,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;
@@ -562,8 +553,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);
@@ -687,6 +677,63 @@ 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_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;
@@ -769,26 +816,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]) + 1;
-               if (*line == ' ')
-                       line++;
-               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.
@@ -859,8 +886,8 @@ static void handle_signal(int sig)
                return;
        case SIGINT:
                PARA_WARNING_LOG("caught SIGINT, reset");
-               /* Nothing to do. SIGINT killed our child, para_client stat.
-                * This get noticed by do_select which resets everything
+               /* Nothing to do. SIGINT killed our child which gets noticed
+                * by do_select and resets everything.
                 */
                return;
        case SIGUSR1:
@@ -895,7 +922,7 @@ 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)
@@ -946,7 +973,7 @@ repeat:
                }
        }
        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();
@@ -1091,13 +1118,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;
        }
@@ -1168,24 +1196,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);
 }
 
 /*
@@ -1280,7 +1308,7 @@ static void com_version(void)
                CODENAME "\"");
 }
 
-static void com_quit(void)
+__noreturn static void com_quit(void)
 {
        finish(0);
 }
@@ -1391,6 +1419,7 @@ int main(int argc, char *argv[])
                };
                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);