]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - play.c
Merge topic branch t/sf_float into pu
[paraslash.git] / play.c
diff --git a/play.c b/play.c
index 4024c8ea4fa5468ff81059f89e732df29dd5fbbf..5b20315af2bbb11bcf1b79a67550788992fcbda9 100644 (file)
--- a/play.c
+++ b/play.c
@@ -24,6 +24,7 @@
 #include "recv.h"
 #include "write.h"
 #include "fd.h"
+#include "interactive.h"
 
 /** Array of error strings. */
 DEFINE_PARA_ERRLIST;
@@ -222,7 +223,7 @@ static int get_playback_error(void)
        int err;
 
        if (!pt->wn.task)
-               return 0;
+               return 1;
        err = task_status(pt->wn.task);
        if (err >= 0)
                return 0;
@@ -253,7 +254,7 @@ static int eof_cleanup(void)
 
        decoder = filter_get(pt->fn.filter_num);
        task_reap(&pt->fn.task);
-       if (decoder->close)
+       if (decoder && decoder->close)
                decoder->close(&pt->fn);
        btr_remove_node(&pt->fn.btrn);
        lls_free_parse_result(pt->fn.lpr, FILTER_CMD(pt->fn.filter_num));
@@ -470,8 +471,6 @@ static void kill_stream(void)
                task_notify(pt->wn.task, E_EOF);
 }
 
-#ifdef HAVE_READLINE
-
 /* only called from com_prev(), nec. only if we have readline */
 static int previous_valid_file(void)
 {
@@ -488,8 +487,6 @@ static int previous_valid_file(void)
        return -E_NO_VALID_FILES;
 }
 
-#include "interactive.h"
-
 /*
  * Define the default (internal) key mappings and helper functions to get the
  * key sequence or the command from a key id, which is what we obtain from
@@ -573,15 +570,17 @@ static inline char *get_internal_key_map_seq(int key)
        return para_strdup(default_keyseqs[get_internal_key_map_idx(key)]);
 }
 
-static char *get_user_key_map_seq(int key)
+static char *get_key_map_seq(int key)
 {
-       const char *kma = get_user_key_map_arg(key);
-       const char *p = strchr(kma + 1, ':');
+       const char *kma, *p;
        char *result;
        int len;
 
-       if (!p)
-               return NULL;
+       if (is_internal_key(key))
+               return get_internal_key_map_seq(key);
+       kma = get_user_key_map_arg(key);
+       p = strchr(kma + 1, ':');
+       assert(p); /* We checked earlier that kma contains a colon */
        len = p - kma;
        result = alloc(len + 1);
        memcpy(result, kma, len);
@@ -589,12 +588,6 @@ static char *get_user_key_map_seq(int key)
        return result;
 }
 
-static char *get_key_map_seq(int key)
-{
-       return is_internal_key(key)?
-               get_internal_key_map_seq(key) : get_user_key_map_seq(key);
-}
-
 static char *get_key_map_seq_safe(int key)
 {
        const char hex[] = "0123456789abcdef";
@@ -918,7 +911,7 @@ static int com_jmp(struct lls_parse_result *lpr)
                return com_next(NULL);
        if (pt->playing && !pt->fn.btrn)
                return 0;
-       pt->start_chunk = percent * pt->num_chunks / 100;
+       pt->start_chunk = (uint64_t)percent * pt->num_chunks / 100;
        if (!pt->playing)
                return 0;
        pt->rq = CRT_REPOS;
@@ -948,7 +941,7 @@ static int com_ff(struct lls_parse_result *lpr)
        seconds += (get_play_time() + 500) / 1000;
        seconds = PARA_MIN(seconds, (typeof(seconds))pt->seconds - 4);
        seconds = PARA_MAX(seconds, 0);
-       pt->start_chunk = pt->num_chunks * seconds / pt->seconds;
+       pt->start_chunk = (uint64_t)pt->num_chunks * seconds / pt->seconds;
        pt->start_chunk = PARA_MIN(pt->start_chunk, pt->num_chunks - 1);
        pt->start_chunk = PARA_MAX(pt->start_chunk, 0UL);
        if (!pt->playing)
@@ -1044,17 +1037,14 @@ static void session_open(void)
        if (OPT_GIVEN(HISTORY_FILE))
                history_file = para_strdup(OPT_STRING_VAL(HISTORY_FILE));
        else {
-               char *home = para_homedir();
-               char *dot_para = make_message("%s/.paraslash", home);
+               const char *confdir = get_confdir();
 
-               free(home);
-               ret = para_mkdir(dot_para, 0777);
+               ret = para_mkdir(confdir);
                /* warn, but otherwise ignore mkdir error */
-               if (ret < 0 && ret != -ERRNO_TO_PARA_ERROR(EEXIST))
-                       PARA_WARNING_LOG("Can not create %s: %s\n", dot_para,
+               if (ret < 0)
+                       PARA_WARNING_LOG("Can not create %s: %s\n", confdir,
                                para_strerror(-ret));
-               history_file = make_message("%s/play.history", dot_para);
-               free(dot_para);
+               history_file = make_message("%s/play.history", confdir);
        }
        ici.history_file = history_file;
        ici.loglevel = loglevel;
@@ -1098,64 +1088,6 @@ static void session_update_time_string(char *str, unsigned len)
        i9e_print_status_bar(str, len);
 }
 
-/*
- * If we are about to die we must call i9e_close() to reset the terminal.
- * However, i9e_close() must be called in *this* context, i.e. from
- * play_task.post_monitor() rather than from i9e_post_monitor(), because
- * otherwise i9e would access freed memory upon return. So the play task must
- * stay alive until the i9e task terminates.
- *
- * We achieve this by sending a fake SIGTERM signal via i9e_signal_dispatch()
- * and reschedule. In the next iteration, i9e->post_monitor returns an error and
- * terminates. Subsequent calls to i9e_get_error() then return negative and we
- * are allowed to call i9e_close() and terminate as well.
- */
-static int session_post_monitor(__a_unused struct sched *s)
-{
-       int ret;
-
-       if (pt->background)
-               detach_stdout();
-       else
-               attach_stdout(__FUNCTION__);
-       ret = i9e_get_error();
-       if (ret < 0) {
-               kill_stream();
-               i9e_close();
-               para_log = stderr_log;
-               free(ici.history_file);
-               return ret;
-       }
-       if (get_playback_state() == 'X')
-               i9e_signal_dispatch(SIGTERM);
-       return 0;
-}
-
-#else /* HAVE_READLINE */
-
-static int session_post_monitor(struct sched *s)
-{
-       char c;
-
-       if (!sched_read_ok(STDIN_FILENO, s))
-               return 0;
-       if (read(STDIN_FILENO, &c, 1))
-               do_nothing;
-       kill_stream();
-       return 1;
-}
-
-static void session_open(void)
-{
-}
-
-static void session_update_time_string(char *str, __a_unused unsigned len)
-{
-       printf("\r%s     ", str);
-       fflush(stdout);
-}
-#endif /* HAVE_READLINE */
-
 static void play_pre_monitor(struct sched *s, __a_unused void *context)
 {
        char state;
@@ -1194,18 +1126,24 @@ static unsigned get_time_string(char **result)
        );
 }
 
-static int play_post_monitor(struct sched *s, __a_unused void *context)
+static int play_post_monitor(__a_unused struct sched *s, __a_unused void *context)
 {
-       int ret;
+       int ret, i9e_error;
 
+       if (pt->background)
+               detach_stdout();
+       else
+               attach_stdout(__FUNCTION__);
+       i9e_error = i9e_get_error();
        ret = eof_cleanup();
-       if (ret < 0) {
-               pt->rq = CRT_TERM_RQ;
-               return 0;
-       }
-       ret = session_post_monitor(s);
-       if (ret < 0)
-               goto out;
+       if (pt->rq == CRT_TERM_RQ || i9e_error < 0) /* com_quit() or CTRL+D */
+               kill_stream(); /* terminate receiver/filter/writer */
+       if ((ret < 0 || pt->rq == CRT_TERM_RQ) && i9e_error >= 0)
+               i9e_signal_dispatch(SIGTERM); /* terminate the i9e task */
+       if (ret < 0) /* unexpected error from the writer node */
+               return ret;
+       if (ret != 0 && i9e_error < 0) /* eof, and i9e has died */
+               return i9e_error;
        if (!pt->wn.btrn && !pt->fn.btrn) {
                char state = get_playback_state();
                if (state == 'P' || state == 'R' || state == 'F') {
@@ -1214,8 +1152,7 @@ static int play_post_monitor(struct sched *s, __a_unused void *context)
                        if (ret < 0) {
                                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                                pt->rq = CRT_TERM_RQ;
-                               ret = 1;
-                               goto out;
+                               return 1;
                        }
                        pt->next_update = *now;
                }
@@ -1229,9 +1166,7 @@ static int play_post_monitor(struct sched *s, __a_unused void *context)
                free(str);
                tv_add(now, &delay, &pt->next_update);
        }
-       ret = 1;
-out:
-       return ret;
+       return 1;
 }
 
 /**
@@ -1278,7 +1213,12 @@ int main(int argc, char *argv[])
        }, &sched);
        ret = schedule(&sched);
        sched_shutdown(&sched);
+       i9e_close();
+       wipe_receiver_node();
+       para_log = stderr_log;
+       free(ici.history_file);
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+       free(get_confdir());
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
 }