Merge branch 't/gui_improvements'
authorAndre Noll <maan@systemlinux.org>
Fri, 7 Jun 2013 19:34:51 +0000 (21:34 +0200)
committerAndre Noll <maan@systemlinux.org>
Fri, 7 Jun 2013 19:38:17 +0000 (21:38 +0200)
Was cooking for more than one month.

bf1831 string: Speed up xvasprintf().
bcc083 string: Add discard feature for for_each_line().
e3868d string: Simplify return value of for_each_line().
d1f0f0 string: Simplify for_each_line().
23b121 string: Clean up for_each_line() and related functions.
6256ed string: Replace the for_each_line_modes enum by a bitmap.
14e689 gui: Don't sleep before executing the status command.
e90c6c gui: Speed up add_spaces().
20e2c6 gui: Rename do_exit().
ef0508 gui: Remove superfluous cmd_died.
d7562b gui: Check stdin for readability.
a44fa6 gui: Discard overlong input lines.

Conflicts:
gui.c

63 files changed:
CREDITS
Makefile.in
NEWS
aacdec_filter.c
afh.c
afh_common.c
afh_recv.c
afs.c
alsa_write.c
amp_filter.c
ao_write.c
audioc.c
audiod.c
check_wav.c
check_wav.h
client.c
client_common.c
command.c
compress_filter.c
configure.ac
daemon.c
dccp_recv.c
fecdec_filter.c
file_write.c
filter.h
filter_common.c
flacdec_filter.c
grab_client.c
gui.c
http_recv.c
interactive.c
mix.h
mp3_afh.c
mp3dec_filter.c
oggdec_filter.c
oss_write.c
osx_write.c
para.h
play.c
prebuffer_filter.c
recv.h
resample_filter.c
sched.c
sched.h
server.c
spxdec_filter.c
stdin.c
stdout.c
string.c
string.h
time.c
udp_recv.c
udp_send.c
vss.c
wav_filter.c
web/header.html
web/header2.html
web/manual.m4
wma.h
wmadec_filter.c
write.c
write.h
write_common.c

diff --git a/CREDITS b/CREDITS
index 1d8ad0c..ec4e536 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -40,7 +40,7 @@ Loren Merritt (FFmpeg)
 
 Simon Morlat <simon.morlat@linphone.org> (ortp)
 
-Christof Müller (bug reports)
+Christof Müller (bug reports)
 
 M. Hari Nezumi <magenta@trikuare.cx> (AudioCompress)
 
@@ -50,7 +50,7 @@ Manuel Odendahl <manuel-poc@bl0rg.net> (poc)
 
 Guillaume Outters <guillaume.outters@free.fr> (mosx-mpg123)
 
-Christian Reißmann (design)
+Christian Reißmann (design)
 
 Gerrit Renker <gerrit@erg.abdn.ac.uk> (dccp improvements, IPv6 support)
 
index d577ce2..f3dfea0 100644 (file)
@@ -79,6 +79,8 @@ CPPFLAGS += -I/usr/local/include
 CPPFLAGS += -I$(cmdline_dir)
 CPPFLAGS += @osl_cppflags@
 
+LDFLAGS += @clock_gettime_ldflags@
+
 man_pages := $(patsubst %, $(man_dir)/%.1, @executables@)
 
 autocrap := config.h.in configure
@@ -244,47 +246,47 @@ endif
 
 para_recv: $(recv_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) $(recv_objs) -o $@ @recv_ldflags@
+       $(Q) $(CC) $(recv_objs) -o $@ @recv_ldflags@ $(LDFLAGS)
 
 para_filter: $(filter_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) $(filter_objs) -o $@ @filter_ldflags@
+       $(Q) $(CC) $(filter_objs) -o $@ @filter_ldflags@ $(LDFLAGS)
 
 para_client: $(client_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(client_objs) @client_ldflags@
+       $(Q) $(CC) -o $@ $(client_objs) @client_ldflags@ $(LDFLAGS)
 
 para_gui: $(gui_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(gui_objs) -lcurses
+       $(Q) $(CC) -o $@ $(gui_objs) @gui_ldflags@ $(LDFLAGS)
 
 para_audiod: $(audiod_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(audiod_objs) @audiod_ldflags@
+       $(Q) $(CC) -o $@ $(audiod_objs) @audiod_ldflags@ $(LDFLAGS)
 
 para_audioc: $(audioc_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(audioc_objs) @audioc_ldflags@
+       $(Q) $(CC) -o $@ $(audioc_objs) @audioc_ldflags@ $(LDFLAGS)
 
 para_fade: $(fade_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(fade_objs) @fade_ldflags@
+       $(Q) $(CC) -o $@ $(fade_objs) @fade_ldflags@ $(LDFLAGS)
 
 para_server: $(server_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(server_objs)  @server_ldflags@
+       $(Q) $(CC) -o $@ $(server_objs) @server_ldflags@ $(LDFLAGS)
 
 para_write: $(write_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(write_objs) @write_ldflags@
+       $(Q) $(CC) -o $@ $(write_objs) @write_ldflags@ $(LDFLAGS)
 
 para_afh: $(afh_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(afh_objs) @afh_ldflags@
+       $(Q) $(CC) -o $@ $(afh_objs) @afh_ldflags@ $(LDFLAGS)
 
 para_play: $(play_objs)
        @[ -z "$(Q)" ] || echo 'LD $@'
-       $(Q) $(CC) $(LDFLAGS) -o $@ $(play_objs) @play_ldflags@
+       $(Q) $(CC) -o $@ $(play_objs) @play_ldflags@ $(LDFLAGS)
 
 clean:
        @[ -z "$(Q)" ] || echo 'CLEAN'
diff --git a/NEWS b/NEWS
index f323df1..a93fb2e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@
 0.?.? (to be announced) "spectral gravity"
 ------------------------------------------
 
+       - UTF8 support for para_gui and the mp3 audio format handler.
+       - Scheduler improvements and fixes.
+       - The obsolete gettimeofday() function has been replaced
+         by clock_gettime() on systems which support it.
+       - Speed and usability improvements for para_gui.
+
 -----------------------------------------
 0.4.12 (2012-12-20) "volatile relativity"
 -----------------------------------------
index 55f7ea2..3ff9083 100644 (file)
@@ -80,7 +80,7 @@ static void aacdec_close(struct filter_node *fn)
        fn->private_data = NULL;
 }
 
-static void aacdec_post_select(__a_unused struct sched *s, struct task *t)
+static int aacdec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct btr_node *btrn = fn->btrn;
@@ -91,12 +91,11 @@ static void aacdec_post_select(__a_unused struct sched *s, struct task *t)
        size_t len, skip, consumed, loaded;
 
 next_buffer:
-       t->error = 0;
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0)
                goto err;
        if (ret == 0)
-               return;
+               return 0;
        btr_merge(btrn, fn->min_iqs);
        len = btr_next_buffer(btrn, (char **)&inbuf);
        len = PARA_MIN(len, (size_t)8192);
@@ -123,7 +122,7 @@ next_buffer:
                        ret = -E_AACDEC_INIT;
                        if (NeAACDecInit2(padd->handle, p,
                                        padd->decoder_length, &rate,
-                                       &channels) < 0)
+                                       &channels) != 0)
                                goto out;
                }
                padd->sample_rate = rate;
@@ -203,8 +202,8 @@ out:
        }
 err:
        assert(ret < 0);
-       t->error = ret;
        btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 /**
diff --git a/afh.c b/afh.c
index aab664c..4c65d7c 100644 (file)
--- a/afh.c
+++ b/afh.c
@@ -7,7 +7,6 @@
 /** \file afh.c Paraslash's standalone audio format handler tool. */
 
 #include <regex.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "string.h"
index 5c866c1..6c161a7 100644 (file)
@@ -7,7 +7,6 @@
 /** \file afh_common.c Common audio format handler functions. */
 
 #include <sys/mman.h> /* mmap */
-#include <sys/time.h> /* gettimeofday */
 #include <sys/types.h>
 #include <regex.h>
 
index febda8a..774ae88 100644 (file)
@@ -173,7 +173,7 @@ static void afh_recv_pre_select(struct sched *s, struct task *t)
        sched_request_barrier_or_min_delay(&chunk_time, s);
 }
 
-static void afh_recv_post_select(__a_unused struct sched *s, struct task *t)
+static int afh_recv_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct receiver_node *rn = container_of(t, struct receiver_node, task);
        struct afh_recv_args_info *conf = rn->conf;
@@ -233,7 +233,7 @@ out:
                btr_remove_node(&rn->btrn);
                pard->current_chunk = pard->first_chunk;
        }
-       t->error = ret;
+       return ret;
 }
 
 /**
diff --git a/afs.c b/afs.c
index eb18708..2f52129 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -723,9 +723,9 @@ static void signal_pre_select(struct sched *s, struct task *t)
        para_fd_set(st->fd, &s->rfds, &s->max_fileno);
 }
 
-static void afs_signal_post_select(struct sched *s, struct task *t)
+static int afs_signal_post_select(struct sched *s, __a_unused struct task *t)
 {
-       int signum;
+       int signum, ret;
 
        if (getppid() == 1) {
                PARA_EMERG_LOG("para_server died\n");
@@ -733,20 +733,20 @@ static void afs_signal_post_select(struct sched *s, struct task *t)
        }
        signum = para_next_signal(&s->rfds);
        if (signum == 0)
-               return;
+               return 0;
        if (signum == SIGHUP) {
                close_afs_tables();
                parse_config_or_die(1);
-               t->error = open_afs_tables();
-               if (t->error < 0)
-                       return;
+               ret = open_afs_tables();
+               if (ret < 0)
+                       return ret;
                init_admissible_files(current_mop);
-               return;
+               return 0;
        }
        PARA_EMERG_LOG("terminating on signal %d\n", signum);
 shutdown:
        task_notify_all(s, E_AFS_SIGNAL);
-       t->error = -E_AFS_SIGNAL;
+       return -E_AFS_SIGNAL;
 }
 
 static void register_signal_task(struct sched *s)
@@ -915,7 +915,7 @@ err:
 /** Shutdown connection if query has not arrived until this many seconds. */
 #define AFS_CLIENT_TIMEOUT 3
 
-static void command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, struct task *t)
 {
        struct command_task *ct = container_of(t, struct command_task, task);
        struct sockaddr_un unix_addr;
@@ -923,16 +923,13 @@ static void command_post_select(struct sched *s, struct task *t)
        int fd, ret;
 
        ret = task_get_notification(t);
-       if (ret < 0) {
-               t->error = ret;
-               return;
-       }
+       if (ret < 0)
+               return ret;
        ret = execute_server_command(&s->rfds);
        if (ret < 0) {
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));
                task_notify_all(s, -ret);
-               t->error = ret;
-               return;
+               return ret;
        }
        /* Check the list of connected clients. */
        list_for_each_entry_safe(client, tmp, &afs_client_list, node) {
@@ -953,17 +950,18 @@ static void command_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
        if (ret <= 0)
-               return;
+               return 0;
        ret = mark_fd_nonblocking(fd);
        if (ret < 0) {
                PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
                close(fd);
-               return;
+               return 0;
        }
        client = para_malloc(sizeof(*client));
        client->fd = fd;
        client->connect_time = *now;
        para_list_add(&client->node, &afs_client_list);
+       return 0;
 }
 
 static void register_command_task(uint32_t cookie, struct sched *s)
index ba844db..88e48b4 100644 (file)
@@ -15,7 +15,6 @@
 #include <regex.h>
 #include <sys/types.h>
 #include <alsa/asoundlib.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "fd.h"
@@ -165,17 +164,18 @@ static int alsa_init(struct private_alsa_write_data *pad,
                goto fail;
        ret = snd_output_buffer_open(&output_log);
        if (ret == 0) {
-               char *buf;
+               char *buf, *p;
+               size_t sz;
                PARA_INFO_LOG("dumping alsa configuration\n");
                snd_pcm_dump(pad->handle, output_log);
-               snd_output_buffer_string(output_log, &buf);
-               for (;;) {
-                       char *p = strchr(buf, '\n');
-                       if (!p) /* omit last output line, it's empty */
+               sz = snd_output_buffer_string(output_log, &buf);
+               for (p = buf; p < buf + sz;) {
+                       char *q = memchr(p, '\n', buf + sz - p);
+                       if (!q)
                                break;
-                       *p = '\0';
-                       PARA_INFO_LOG("%s\n", buf);
-                       buf = p + 1;
+                       *q = '\0';
+                       PARA_INFO_LOG("%s\n", p);
+                       p = q + 1;
                }
                snd_output_close(output_log);
        }
@@ -236,7 +236,7 @@ static void alsa_close(struct writer_node *wn)
        free(pad);
 }
 
-static void alsa_write_post_select(__a_unused struct sched *s,
+static int alsa_write_post_select(__a_unused struct sched *s,
                struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
@@ -253,7 +253,7 @@ static void alsa_write_post_select(__a_unused struct sched *s,
 again:
        ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
        if (ret == 0)
-               return;
+               return 0;
        btr_merge(btrn, wn->min_iqs);
        bytes = btr_next_buffer(btrn, &data);
        if (ret < 0 || bytes < wn->min_iqs) { /* eof */
@@ -266,17 +266,17 @@ again:
                        PARA_DEBUG_LOG("waiting for device to drain\n");
                        tv_add(now, &(struct timeval)EMBRACE(0, 200 * 1000),
                                &pad->drain_barrier);
-                       return;
+                       return 0;
                }
                if (tv_diff(now, &pad->drain_barrier, NULL) > 0)
                        goto err;
-               return;
+               return 0;
        }
        if (!pad) {
                int32_t val;
 
                if (bytes == 0) /* no data available */
-                       return;
+                       return 0;
                pad = para_calloc(sizeof(*pad));
                get_btr_sample_rate(btrn, &val);
                pad->sample_rate = val;
@@ -297,7 +297,7 @@ again:
                goto again;
        }
        if (pad->poll_fd < 0 || !FD_ISSET(pad->poll_fd, &s->rfds))
-               return;
+               return 0;
        frames = bytes / pad->bytes_per_frame;
        frames = snd_pcm_writei(pad->handle, data, frames);
        if (frames == 0 || frames == -EAGAIN) {
@@ -311,7 +311,7 @@ again:
                char buf[100];
                if (read(pad->poll_fd, buf, 100))
                        do_nothing;
-               return;
+               return 0;
        }
        if (frames > 0) {
                btr_consume(btrn, frames * pad->bytes_per_frame);
@@ -320,14 +320,14 @@ again:
        if (frames == -EPIPE) {
                PARA_WARNING_LOG("underrun (tried to write %zu bytes)\n", bytes);
                snd_pcm_prepare(pad->handle);
-               return;
+               return 0;
        }
        PARA_ERROR_LOG("alsa write error: %s\n", snd_strerror(-frames));
        ret = -E_ALSA;
 err:
        assert(ret < 0);
        btr_remove_node(&wn->btrn);
-       t->error = ret;
+       return ret;
 }
 
 __malloc static void *alsa_parse_config_or_die(int argc, char **argv)
index 90b5660..a6bfca2 100644 (file)
@@ -62,7 +62,7 @@ static void amp_open(struct filter_node *fn)
                pad->amp, pad->amp / 64.0 + 1.0);
 }
 
-static void amp_post_select(__a_unused struct sched *s, struct task *t)
+static int amp_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct private_amp_data *pad = fn->private_data;
@@ -73,16 +73,15 @@ static void amp_post_select(__a_unused struct sched *s, struct task *t)
        bool inplace = btr_inplace_ok(btrn);
 
        if (pad->amp == 0) { /* no amplification */
-               t->error = -E_AMP_ZERO_AMP;
                btr_splice_out_node(btrn);
-               return;
+               return -E_AMP_ZERO_AMP;
        }
 next_buffer:
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0)
                goto err;
        if (ret == 0)
-               return;
+               return 0;
        btr_merge(btrn, fn->min_iqs);
        in_bytes = btr_next_buffer(btrn, (char **)&in);
        len = in_bytes / 2;
@@ -110,12 +109,11 @@ next_buffer:
                btr_consume(btrn, len * 2);
                btr_add_output((char *)out, len * 2, btrn);
        }
-       t->error = 0;
        goto next_buffer;
 err:
        assert(ret < 0);
-       t->error = ret;
        btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 static void amp_free_config(void *conf)
index ffe8669..9d204ff 100644 (file)
@@ -276,7 +276,7 @@ fail:
        return -E_AO_PTHREAD;
 }
 
-static void aow_post_select(__a_unused struct sched *s,
+static int aow_post_select(__a_unused struct sched *s,
                struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
@@ -291,7 +291,7 @@ static void aow_post_select(__a_unused struct sched *s,
                if (ret < 0)
                        goto remove_btrn;
                if (ret == 0)
-                       return;
+                       return 0;
                get_btr_sample_rate(wn->btrn, &rate);
                get_btr_channels(wn->btrn, &ch);
                get_btr_sample_format(wn->btrn, &format);
@@ -312,7 +312,7 @@ static void aow_post_select(__a_unused struct sched *s,
                ret = aow_create_thread(wn);
                if (ret < 0)
                        goto remove_thread_btrn;
-               return;
+               return 0;
        }
        pthread_mutex_lock(&pawd->mutex);
        ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
@@ -334,7 +334,7 @@ remove_thread_btrn:
 remove_btrn:
        btr_remove_node(&wn->btrn);
 out:
-       t->error = ret;
+       return ret;
 }
 
 __malloc static void *aow_parse_config_or_die(int argc, char **argv)
index abd7635..74fb11c 100644 (file)
--- a/audioc.c
+++ b/audioc.c
@@ -106,7 +106,7 @@ static void audioc_pre_select(struct sched *s, struct task *t)
        para_fd_set(at->fd, &s->rfds, &s->max_fileno);
 }
 
-static void audioc_post_select(struct sched *s, struct task *t)
+static int audioc_post_select(struct sched *s, struct task *t)
 {
        char *buf = NULL;
        struct audioc_task *at = container_of(t, struct audioc_task, task);
@@ -115,7 +115,7 @@ static void audioc_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                goto out;
        if (!FD_ISSET(at->fd, &s->rfds))
-               return;
+               return 0;
        buf = para_malloc(conf.bufsize_arg);
        ret = recv_bin_buffer(at->fd, buf, conf.bufsize_arg);
        PARA_DEBUG_LOG("recv: %d\n", ret);
@@ -124,14 +124,14 @@ static void audioc_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                goto out;
        btr_add_output(buf, ret, at->btrn);
-       return;
+       return 0;
 out:
        if (ret < 0) {
                free(buf);
                btr_remove_node(&at->btrn);
                close(at->fd);
        }
-       t->error = ret;
+       return ret;
 }
 
 static struct audioc_task audioc_task = {
index 4f2d415..d2c66f2 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -496,7 +496,6 @@ static void open_filters(struct slot_info *s)
                fn->conf = a->filter_conf[i];
                fn->task.pre_select = f->pre_select;
                fn->task.post_select = f->post_select;
-
                fn->btrn = btr_new_node(&(struct btr_node_description)
                        EMBRACE(.name = f->name, .parent = parent,
                                .handler = f->execute, .context = fn));
@@ -992,7 +991,7 @@ static void signal_pre_select(struct sched *s, struct task *t)
        para_fd_set(st->fd, &s->rfds, &s->max_fileno);
 }
 
-static void signal_post_select(struct sched *s, __a_unused struct task *t)
+static int signal_post_select(struct sched *s, __a_unused struct task *t)
 {
        int signum;
 
@@ -1004,6 +1003,7 @@ static void signal_post_select(struct sched *s, __a_unused struct task *t)
                PARA_EMERG_LOG("terminating on signal %d\n", signum);
                clean_exit(EXIT_FAILURE, "caught deadly signal");
        }
+       return 0;
 }
 
 static void signal_setup_default(struct signal_task *st)
@@ -1019,7 +1019,7 @@ static void command_pre_select(struct sched *s, struct task *t)
        para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
 }
 
-static void command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, struct task *t)
 {
        int ret;
        struct command_task *ct = container_of(t, struct command_task, task);
@@ -1036,6 +1036,7 @@ static void command_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        audiod_status_dump();
+       return 0;
 }
 
 static void init_command_task(struct command_task *ct)
@@ -1089,32 +1090,44 @@ static void set_stat_task_restart_barrier(unsigned seconds)
        tv_add(now, &delay, &stat_task->restart_barrier);
 }
 
-static void try_to_close_slot(int slot_num)
+static bool must_close_slot(int slot_num)
 {
        struct slot_info *s = &slot[slot_num];
        struct audio_format_info *a = afi + s->format;
        int i;
 
        if (s->format < 0)
-               return;
+               return false;
        if (s->receiver_node && s->receiver_node->task.error >= 0)
-               return;
+               return false;
        for (i = 0; i < a->num_filters; i++)
                if (s->fns && s->fns[i].task.error >= 0)
-                       return;
+                       return false;
        if (a->num_writers > 0) {
                for (i = 0; i < a->num_writers; i++)
                        if (s->wns && s->wns[i].task.error >= 0)
-                               return;
+                               return false;
        } else {
                if (s->wns && s->wns[0].task.error >= 0)
-                       return;
+                       return false;
+       }
+       return true;
+}
+
+static void close_unused_slots(void)
+{
+       int i;
+
+       FOR_EACH_SLOT(i) {
+               struct slot_info *s = slot + i;
+               if (!must_close_slot(i))
+                       continue;
+               PARA_INFO_LOG("closing slot %d\n", i);
+               close_writers(s);
+               close_filters(s);
+               close_receiver(i);
+               clear_slot(i);
        }
-       PARA_INFO_LOG("closing slot %d\n", slot_num);
-       close_writers(s);
-       close_filters(s);
-       close_receiver(slot_num);
-       clear_slot(slot_num);
 }
 
 /*
@@ -1123,12 +1136,11 @@ static void try_to_close_slot(int slot_num)
  */
 static void start_stop_decoders(void)
 {
-       int i, ret;
+       int ret;
        struct slot_info *sl;
        struct audio_format_info *a;
 
-       FOR_EACH_SLOT(i)
-               try_to_close_slot(i);
+       close_unused_slots();
        if (audiod_status != AUDIOD_ON ||
                        !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
                return notify_receivers(E_NOT_PLAYING);
@@ -1151,10 +1163,13 @@ static void start_stop_decoders(void)
 static void status_pre_select(struct sched *s, struct task *t)
 {
        struct status_task *st = container_of(t, struct status_task, task);
-       int ret, cafn = stat_task->current_audio_format_num;
+       int i, ret, cafn = stat_task->current_audio_format_num;
 
        if (must_start_decoder())
                goto min_delay;
+       FOR_EACH_SLOT(i)
+               if (must_close_slot(i))
+                       goto min_delay;
        ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
        if (ret > 0)
                goto min_delay;
@@ -1177,7 +1192,7 @@ min_delay:
 }
 
 /* restart the client task if necessary */
-static void status_post_select(struct sched *s, struct task *t)
+static int status_post_select(struct sched *s, struct task *t)
 {
        struct status_task *st = container_of(t, struct status_task, task);
 
@@ -1250,6 +1265,7 @@ static void status_post_select(struct sched *s, struct task *t)
        st->last_status_read = *now;
 out:
        start_stop_decoders();
+       return 0;
 }
 
 static void init_status_task(struct status_task *st)
index 8026547..11459e0 100644 (file)
 /** Length of a standard wav header. */
 #define WAV_HEADER_LEN 44
 
+/** The possible states of a check_wav instance. */
 enum check_wav_state {
+       /** Initial state, less than \p WAV_HEADER_LEN bytes available. */
        CWS_NEED_HEADER,
+       /** Wav hader was detected. */
        CWS_HAVE_HEADER,
+       /** First part of the stream did not look like a wav header. */
        CWS_NO_HEADER,
 };
 
@@ -37,6 +41,15 @@ struct check_wav_context {
        unsigned sample_rate;
 };
 
+/**
+ * Set select timeout according to the given context.
+ *
+ * \param s Contains the timeval that should be set.
+ * \param cwc Contains a pointer to the buffer tree node.
+ *
+ * This requests a minimal timeout from the scheduler if btrn of \a cwc is not
+ * idle.
+ */
 void check_wav_pre_select(struct sched *s, struct check_wav_context *cwc)
 {
        int ret = btr_node_status(cwc->btrn, cwc->min_iqs, BTR_NT_INTERNAL);
@@ -95,6 +108,22 @@ out:
        return 1;
 }
 
+/**
+ * Filter out the wav header, pushdown everything else.
+ *
+ * \param cwc The context of this instance.
+ *
+ * This function looks at the first \p WAV_HEADER_SIZE bytes of the input queue
+ * of the btrn of \a cwc. If they look like a wav header, the function extracts
+ * the information of interest and swallows this part of the stream. Otherwise
+ * it is pushed down to all children. In either case the rest of the input is
+ * pushed down as well.
+ *
+ * Once the first part has been processed this way, the state of the instance
+ * changes from \p CWS_NEED_HEADER to \p CWS_HAVE_HEADER or \p CWS_NO_HEADER.
+ *
+ * \return Standard.
+ */
 int check_wav_post_select(struct check_wav_context *cwc)
 {
        struct btr_node *btrn = cwc->btrn;
@@ -160,6 +189,23 @@ out:
        return ret;
 }
 
+/**
+ * Allocate and set up a new check_wav instance.
+ *
+ * \param parent This buffer tree node will be the parent of the new node.
+ * \param child The child of the new node.
+ * \param params Default values and options.
+ * \param cw_btrn A pointer to the check wav node is returned here.
+ *
+ * This function also sets up the ->execute handler of the btrn so that all
+ * children of this node can figure out channel count, sample rate, etc.
+ *
+ * \return The (opaque) handle of the newly created check_wav instance. It is
+ * supposed to be passed to \ref check_wav_pre_select() and \ref
+ * check_wav_post_select().
+ *
+ * \sa \ref btr_new_node.
+ */
 struct check_wav_context *check_wav_init(struct btr_node *parent,
                struct btr_node *child, struct wav_params *params,
                struct btr_node **cw_btrn)
@@ -177,6 +223,14 @@ struct check_wav_context *check_wav_init(struct btr_node *parent,
        return cwc;
 }
 
+/**
+ * Dellocate all ressources of a check_wav instance.
+ *
+ * \param cwc Determines the instance to shut down.
+ *
+ * This function may only be called after check_wav_post_select() has returned
+ * negative.
+ */
 void check_wav_shutdown(struct check_wav_context *cwc)
 {
        free(cwc);
index 6a95776..ba1a8ec 100644 (file)
@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 2012-2013 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file check_wav.h Detect, process and cut a wav header. */
+
 struct check_wav_context;
 
 /**
index 715df9c..90dc432 100644 (file)
--- a/client.c
+++ b/client.c
@@ -54,7 +54,7 @@ static void exec_pre_select(struct sched *s, struct task *t)
                sched_min_delay(s);
 }
 
-static void exec_post_select(__a_unused struct sched *s, struct task *t)
+static int exec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct exec_task *et = container_of(t, struct exec_task, task);
        struct btr_node *btrn = et->btrn;
@@ -63,10 +63,8 @@ static void exec_post_select(__a_unused struct sched *s, struct task *t)
        int ret;
 
        ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
-       if (ret <= 0) {
-               t->error = ret;
-               return;
-       }
+       if (ret <= 0)
+               return ret;
        sz = btr_next_buffer(btrn, &buf);
        if (sz <= 1)
                goto out;
@@ -76,6 +74,7 @@ static void exec_post_select(__a_unused struct sched *s, struct task *t)
        et->result_buf[et->result_size - 1] = '\0';
 out:
        btr_consume(btrn, sz);
+       return 0;
 }
 
 static int make_client_argv(const char *line)
@@ -531,23 +530,21 @@ __noreturn static void print_completions(void)
 
 #endif /* HAVE_READLINE */
 
-static void supervisor_post_select(struct sched *s, struct task *t)
+static int supervisor_post_select(struct sched *s, __a_unused struct task *t)
 {
-       if (ct->task.error < 0) {
-               t->error = ct->task.error;
-               return;
-       }
+       if (ct->task.error < 0)
+               return ct->task.error;
        if (ct->status == CL_SENDING) {
                stdin_set_defaults(&sit);
                register_task(s, &sit.task);
-               t->error = -E_TASK_STARTED;
-               return;
+               return -E_TASK_STARTED;
        }
        if (ct->status == CL_RECEIVING) {
                stdout_set_defaults(&sot);
                register_task(s, &sot.task);
-               t->error = -E_TASK_STARTED; return;
+               return -E_TASK_STARTED;
        }
+       return 0;
 }
 
 static struct task svt = {
index 7bdb473..8ea4192 100644 (file)
@@ -326,7 +326,7 @@ static int send_sb_command(struct client_task *ct)
  *
  * \sa struct sched, struct task.
  */
-static void client_post_select(struct sched *s, struct task *t)
+static int client_post_select(struct sched *s, struct task *t)
 {
        struct client_task *ct = container_of(t, struct client_task, task);
        struct btr_node *btrn = ct->btrn;
@@ -338,7 +338,7 @@ static void client_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                goto out;
        if (ct->scc.fd < 0)
-               return;
+               return 0;
        switch (ct->status) {
        case CL_CONNECTED: /* receive welcome message */
                ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n);
@@ -346,10 +346,10 @@ static void client_post_select(struct sched *s, struct task *t)
                        goto out;
                ct->features = parse_features(buf);
                ct->status = CL_RECEIVED_WELCOME;
-               return;
+               return 0;
        case CL_RECEIVED_WELCOME: /* send auth command */
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return;
+                       return 0;
                if (has_feature("sideband", ct)) {
                        ct->use_sideband = true;
                        sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user);
@@ -360,7 +360,7 @@ static void client_post_select(struct sched *s, struct task *t)
                if (ret < 0)
                        goto out;
                ct->status = CL_SENT_AUTH;
-               return;
+               return 0;
        case CL_SENT_AUTH:
                /*
                 * Receive challenge and session keys, decrypt the challenge and
@@ -406,7 +406,7 @@ static void client_post_select(struct sched *s, struct task *t)
                hash_to_asc(ct->challenge_hash, buf);
                PARA_INFO_LOG("--> %s\n", buf);
                ct->status = CL_RECEIVED_CHALLENGE;
-               return;
+               return 0;
                }
        case CL_RECEIVED_CHALLENGE:
                if (ct->use_sideband) {
@@ -447,20 +447,20 @@ static void client_post_select(struct sched *s, struct task *t)
                if (!strstr(buf, PROCEED_MSG))
                        goto out;
                ct->status = CL_RECEIVED_PROCEED;
-               return;
+               return 0;
                }
        case CL_RECEIVED_PROCEED: /* concat args and send command */
                {
                int i;
                char *command = NULL;
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return;
+                       return 0;
                if (ct->use_sideband) {
                        ret = send_sb_command(ct);
                        if (ret <= 0)
                                goto out;
                        ct->status = CL_SENT_COMMAND;
-                       return;
+                       return 0;
                }
                for (i = 0; i < ct->conf.inputs_num; i++) {
                        char *tmp = command;
@@ -475,7 +475,7 @@ static void client_post_select(struct sched *s, struct task *t)
                if (ret < 0)
                        goto out;
                ct->status = CL_SENT_COMMAND;
-               return;
+               return 0;
                }
        case CL_SENT_COMMAND:
                {
@@ -501,7 +501,7 @@ static void client_post_select(struct sched *s, struct task *t)
                        if (strstr(buf2, AWAITING_DATA_MSG)) {
                                free(buf2);
                                ct->status = CL_SENDING;
-                               return;
+                               return 0;
                        }
                        ct->status = CL_RECEIVING;
                        btr_add_output(buf2, n, btrn);
@@ -517,15 +517,15 @@ static void client_post_select(struct sched *s, struct task *t)
                if (ret < 0)
                        goto out;
                if (ret == 0)
-                       return;
+                       return 0;
                if (!FD_ISSET(ct->scc.fd, &s->wfds))
-                       return;
+                       return 0;
                sz = btr_next_buffer(btrn, &buf2);
                ret = sc_send_bin_buffer(&ct->scc, buf2, sz);
                if (ret < 0)
                        goto out;
                btr_consume(btrn, sz);
-               return;
+               return 0;
                }
        case CL_RECEIVING:
                {
@@ -534,13 +534,13 @@ static void client_post_select(struct sched *s, struct task *t)
                if (ret < 0)
                        goto out;
                if (ret == 0)
-                       return;
+                       return 0;
                /*
                 * The FD_ISSET() is not strictly necessary, but is allows us
                 * to skip the malloc below if there is nothing to read anyway.
                 */
                if (!FD_ISSET(ct->scc.fd, &s->rfds))
-                       return;
+                       return 0;
                if (ct->use_sideband) {
                        struct sb_buffer sbb;
                        ret = recv_sb(ct, &s->rfds, &sbb);
@@ -559,13 +559,13 @@ static void client_post_select(struct sched *s, struct task *t)
                }
        }
 out:
-       t->error = ret;
        if (ret < 0) {
                if (!ct->use_sideband && ret != -E_SERVER_EOF &&
                                ret != -E_BTR_EOF && ret != -E_EOF)
-                       PARA_ERROR_LOG("%s\n", para_strerror(-t->error));
+                       PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                btr_remove_node(&ct->btrn);
        }
+       return ret;
 }
 
 /**
index aaaaaec..ec822c8 100644 (file)
--- a/command.c
+++ b/command.c
@@ -8,7 +8,6 @@
 
 #include <regex.h>
 #include <signal.h>
-#include <sys/time.h>
 #include <sys/types.h>
 #include <osl.h>
 
@@ -124,7 +123,7 @@ static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly,
                localtime_r(&nmmd->mtime, &mtime_tm);
                strftime(mtime, 29, "%b %d %Y", &mtime_tm);
        }
-       gettimeofday(&current_time, NULL);
+       clock_get_realtime(&current_time);
        /*
         * The calls to WRITE_STATUS_ITEM() below never fail because
         * b->max_size is zero (unlimited), see para_printf(). However, clang
index 04377b7..d716279 100644 (file)
@@ -41,7 +41,7 @@ static void compress_close(struct filter_node *fn)
        free(fn->private_data);
 }
 
-static void compress_post_select(__a_unused struct sched *s, struct task *t)
+static int compress_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct private_compress_data *pcd = fn->private_data;
@@ -56,12 +56,11 @@ static void compress_post_select(__a_unused struct sched *s, struct task *t)
 
        //inplace = false;
 next_buffer:
-       t->error = 0;
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0)
                goto err;
        if (ret == 0)
-               return;
+               return 0;
        btr_merge(btrn, fn->min_iqs);
        length = btr_next_buffer(btrn, &inbuf) & ~(size_t)1;
        if (length == 0) { /* eof and 1 byte available */
@@ -108,8 +107,8 @@ next_buffer:
        goto next_buffer;
 err:
        assert(ret < 0);
-       t->error = ret;
        btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 /** TODO: Add sanity checks */
index 35c9fd5..12959c8 100644 (file)
@@ -247,6 +247,18 @@ if test x$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf != "xyesyes";
 AC_MSG_ERROR([fatal: buggy snprintf() detected])
 fi])
 AX_FUNC_SNPRINTF()
+################################################################## clock_gettime
+clock_gettime_lib=
+AC_CHECK_LIB([c], [clock_gettime], [clock_gettime_lib=c], [
+       AC_CHECK_LIB([rt], [clock_gettime], [clock_gettime_lib=rt], [], [])
+])
+if test -n "$clock_gettime_lib"; then
+       AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [
+               define to 1 if clock_gettime() is supported])
+fi
+if test "$clock_gettime_lib" = "rt"; then
+       AC_SUBST(clock_gettime_ldflags, -lrt)
+fi
 ########################################################################### osl
 have_osl=yes
 OLD_CPPFLAGS="$CPPFLAGS"
@@ -471,12 +483,17 @@ fi
 AC_CHECK_HEADER(curses.h, [], [
        have_curses="no"
 ])
-AC_CHECK_LIB([curses], [initscr], [], [
-       have_curses="no"
-])
+gui_ldflags="$curses_libs"
+AC_CHECK_LIB([ncursesw], [initscr],
+       [gui_ldflags="$curses_libs -lncursesw"], [
+               AC_CHECK_LIB([curses], [initscr],
+                       [gui_ldflags="$curses_libs -lcurses"],
+                       [have_curses="no"]
+               )
+       ]
+)
 if test "$have_curses" = "yes"; then
        AC_SUBST(curses_cppflags)
-       AC_DEFINE(HAVE_NCURSES, 1, [define to 1 to turn on curses support])
        extras="$extras gui"
        executables="$executables gui"
 else
@@ -1243,6 +1260,7 @@ AC_DEFINE_UNQUOTED(INIT_AUDIOC_ERRLISTS,
        objlist_to_errlist($audioc_errlist_objs), errors used by para_audioc)
 
 AC_SUBST(gui_objs, add_dot_o($gui_objs))
+AC_SUBST(gui_ldflags, $gui_ldflags)
 AC_DEFINE_UNQUOTED(INIT_GUI_ERRLISTS,
        objlist_to_errlist($gui_errlist_objs), errors used by para_gui)
 
@@ -1251,8 +1269,6 @@ AC_SUBST(play_ldflags, $play_ldflags)
 AC_DEFINE_UNQUOTED(INIT_PLAY_ERRLISTS,
        objlist_to_errlist($play_errlist_objs), errors used by para_play)
 
-AC_MSG_NOTICE(play objs: $play_objs)
-
 enum="$(for i in $filters; do printf "${i}_FILTER, " | tr '[a-z]' '[A-Z]'; done)"
 AC_DEFINE_UNQUOTED(FILTER_ENUM, $enum NUM_SUPPORTED_FILTERS,
        enum of supported filters)
index 29b00ed..18ad156 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -10,7 +10,6 @@
 #include <pwd.h>
 #include <sys/types.h> /* getgrnam() */
 #include <grp.h>
-#include <sys/time.h>
 #include <signal.h>
 
 #include "para.h"
@@ -374,7 +373,7 @@ __printf_2_3 void daemon_log(int ll, const char* fmt,...)
                fprintf(fp, "%s", color);
        if (log_time || log_timing) {
                struct timeval tv;
-               gettimeofday(&tv, NULL);
+               clock_get_realtime(&tv);
                if (daemon_test_flag(DF_LOG_TIME)) { /* print date and time */
                        time_t t1 = tv.tv_sec;
                        char str[100];
index eb442f3..1f9df18 100644 (file)
@@ -124,7 +124,7 @@ static void dccp_recv_pre_select(struct sched *s, struct task *t)
        para_fd_set(rn->fd, &s->rfds, &s->max_fileno);
 }
 
-static void dccp_recv_post_select(struct sched *s, struct task *t)
+static int dccp_recv_post_select(struct sched *s, struct task *t)
 {
        struct receiver_node *rn = container_of(t, struct receiver_node, task);
        struct btr_node *btrn = rn->btrn;
@@ -152,10 +152,9 @@ static void dccp_recv_post_select(struct sched *s, struct task *t)
                btr_add_output_pool(rn->btrp, num_bytes - iov[0].iov_len, btrn);
        }
 out:
-       if (ret >= 0)
-               return;
-       btr_remove_node(&rn->btrn);
-       t->error = ret;
+       if (ret < 0)
+               btr_remove_node(&rn->btrn);
+       return ret;
 }
 
 static void dccp_recv_free_config(void *conf)
index d5a708c..2f0a674 100644 (file)
@@ -436,7 +436,7 @@ static void fecdec_close(struct filter_node *fn)
        fn->private_data = NULL;
 }
 
-static void fecdec_post_select(__a_unused struct sched *s, struct task *t)
+static int fecdec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct btr_node *btrn = fn->btrn;
@@ -468,9 +468,9 @@ next_buffer:
        btr_consume(btrn, FEC_HEADER_SIZE + h.slice_bytes);
        goto next_buffer;
 out:
-       t->error = ret;
        if (ret < 0)
                btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 static void fecdec_open(struct filter_node *fn)
index a12867d..cea21cb 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <regex.h>
 #include <sys/types.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "list.h"
@@ -38,10 +37,8 @@ struct private_file_write_data {
 __must_check __malloc static char *random_filename(void)
 {
        char *result, *home = para_homedir();
-       struct timeval tv;
 
-       gettimeofday(&tv, NULL);
-       srandom(tv.tv_usec);
+       srandom(clock_get_realtime(NULL)->tv_usec);
        result = make_message("%s/.paraslash/%08lu", home,
                para_random(99999999));
        free(home);
@@ -100,7 +97,7 @@ static void file_write_close(struct writer_node *wn)
        free(pfwd);
 }
 
-static void file_write_post_select(__a_unused struct sched *s,
+static int file_write_post_select(__a_unused struct sched *s,
                struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
@@ -121,18 +118,18 @@ static void file_write_post_select(__a_unused struct sched *s,
                goto out;
        }
        if (!FD_ISSET(pfwd->fd, &s->wfds))
-               return;
+               return 0;
        bytes = btr_next_buffer(btrn, &buf);
        assert(bytes > 0);
        //PARA_INFO_LOG("writing %zu\n", bytes);
-       ret = write(pfwd->fd, buf, bytes);
+       ret = xwrite(pfwd->fd, buf, bytes);
        if (ret < 0)
                goto out;
        btr_consume(btrn, ret);
 out:
        if (ret < 0)
                btr_remove_node(&wn->btrn);
-       t->error = ret;
+       return ret;
 }
 
 __malloc static void *file_write_parse_config_or_die(int argc, char **argv)
index eefa6f6..9c57904 100644 (file)
--- a/filter.h
+++ b/filter.h
@@ -109,7 +109,7 @@ struct filter {
         * post_select function is supposed to set t->error to a (negative)
         * error code.
         */
-       void (*post_select)(struct sched *s, struct task *t);
+       int (*post_select)(struct sched *s, struct task *t);
        /**
         * Answer a buffer tree query.
         *
index 415824a..907912f 100644 (file)
@@ -123,13 +123,13 @@ void print_filter_helps(int detailed)
 }
 
 /**
- * Set select timeout of the the scheduler.
+ * Set select timeout of the scheduler.
  *
  * \param s The scheduler.
  * \param t The task struct of this filter.
  *
  * This looks at the status of the btr node of the filter. If data is available
- * in the input queue of the filter, or if an error occured, a minimal timeout
+ * in the input queue of the filter, or if an error occurred, a minimal timeout
  * for the next select call is requested from the scheduler. Otherwise the
  * scheduler timeout is left unchanged.
  */
index b0f499c..09b319a 100644 (file)
@@ -216,7 +216,7 @@ static void flacdec_pre_select(struct sched *s, struct task *t)
                return sched_min_delay(s);
 }
 
-static void flacdec_post_select(__a_unused struct sched *s, struct task *t)
+static int flacdec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct private_flacdec_data *pfd = fn->private_data;
@@ -224,7 +224,7 @@ static void flacdec_post_select(__a_unused struct sched *s, struct task *t)
        int ret;
 
        if (output_queue_full(btrn))
-               return;
+               return 0;
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0 && ret != -E_BTR_EOF) /* fatal error */
                goto out;
@@ -255,9 +255,9 @@ static void flacdec_post_select(__a_unused struct sched *s, struct task *t)
        fn->min_iqs = 0;
        ret = 1;
 out:
-       t->error = ret;
        if (ret < 0)
                btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 static void flacdec_close(struct filter_node *fn)
index a800b70..ecc16fc 100644 (file)
@@ -108,7 +108,7 @@ static void gc_pre_select(struct sched *s, struct task *t)
  * We need this forward declaration as post_select() needs
  * activate_grab_client and vice versa.
  */
-static void gc_post_select(struct sched *s, struct task *t);
+static int gc_post_select(struct sched *s, struct task *t);
 
 /**
  * Move a grab client to the active list and start it.
@@ -184,7 +184,7 @@ static int gc_close(struct grab_client *gc, int err)
        return 0;
 }
 
-static void gc_post_select(__a_unused struct sched *s, struct task *t)
+static int gc_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct grab_client *gc = container_of(t, struct grab_client, task);
        struct btr_node *btrn = gc->btrn;
@@ -192,10 +192,9 @@ static void gc_post_select(__a_unused struct sched *s, struct task *t)
        size_t sz;
        char *buf;
 
-       t->error = 0;
        ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
        if (ret == 0)
-               return;
+               return 0;
        if (ret < 0)
                goto err;
        sz = btr_next_buffer(btrn, &buf);
@@ -205,10 +204,10 @@ static void gc_post_select(__a_unused struct sched *s, struct task *t)
                goto err;
        if (ret > 0)
                btr_consume(btrn, ret);
-       return;
+       return 0;
 err:
        gc_close(gc, ret);
-       t->error = ret;
+       return ret;
 }
 
 static int gc_check_args(int argc, char **argv, struct grab_client *gc)
diff --git a/gui.c b/gui.c
index 85d77c9..096beb9 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -10,6 +10,7 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <curses.h>
+#include <locale.h>
 #include <sys/time.h>
 
 #include "gui.cmdline.h"
@@ -312,11 +313,18 @@ static void add_spaces(WINDOW* win, unsigned int num)
 static int align_str(WINDOW* win, char *str, unsigned int len,
                unsigned int align)
 {
-       int i, num; /* of spaces */
+       int ret, i, num; /* of spaces */
+       size_t width;
 
        if (!win || !str)
-               return -1;
-       num = len - strlen(str);
+               return 0;
+       ret = strwidth(str, &width);
+       if (ret < 0) {
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+               width = 0;
+               str[0] = '\0';
+       }
+       num = len - width;
        if (num < 0) {
                str[len] = '\0';
                num = 0;
@@ -398,11 +406,14 @@ static int first_visible_rbe(unsigned *lines)
        return RINGBUFFER_SIZE - 1;
 }
 
+/*
+returns number of first visible rbe, *lines is the number of lines drawn.
+ */
 static int draw_top_rbe(unsigned *lines)
 {
-       unsigned len;
-       int offset, fvr = first_visible_rbe(lines);
+       int ret, fvr = first_visible_rbe(lines);
        struct rb_entry *rbe;
+       size_t bytes_to_skip, cells_to_skip, width;
 
        if (fvr < 0)
                return -1;
@@ -410,16 +421,22 @@ static int draw_top_rbe(unsigned *lines)
        rbe = ringbuffer_get(bot_win_rb, fvr);
        if (!rbe)
                return -1;
-       len = strlen(rbe->msg);
        if (*lines > bot.lines) {
-               /* first rbe is only partially visible */
-               offset = (*lines - bot.lines) * bot.cols;
-               assert(offset <= len);
-       } else
-               offset = 0;
+               /* rbe is partially visible multi-line */
+               cells_to_skip = (*lines - bot.lines) * bot.cols;
+               ret = skip_cells(rbe->msg, cells_to_skip, &bytes_to_skip);
+               if (ret < 0)
+                       return ret;
+               ret = strwidth(rbe->msg + bytes_to_skip, &width);
+               if (ret < 0)
+                       return ret;
+       } else {
+               bytes_to_skip = 0;
+               width = rbe->len;
+       }
        wattron(bot.win, COLOR_PAIR(rbe->color));
-       waddstr(bot.win, rbe->msg + offset);
-       *lines = NUM_LINES(len - offset);
+       waddstr(bot.win, rbe->msg + bytes_to_skip);
+       *lines = NUM_LINES(width);
        return fvr;
 }
 
@@ -451,10 +468,15 @@ out:
 
 static void rb_add_entry(int color, char *msg)
 {
-       struct rb_entry *old, *new = para_malloc(sizeof(struct rb_entry));
+       struct rb_entry *old, *new;
        int x, y;
+       size_t len;
+
+       if (strwidth(msg, &len) < 0)
+               return;
+       new = para_malloc(sizeof(struct rb_entry));
        new->color = color;
-       new->len = strlen(msg);
+       new->len = len;
        new->msg = msg;
        old = ringbuffer_add(bot_win_rb, new);
 //     fprintf(stderr, "added: %s\n", new->msg);
@@ -1176,7 +1198,7 @@ static void com_scroll_top(void)
                struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i);
                if (!rbe)
                        break;
-               lines += NUM_LINES(strlen(rbe->msg));
+               lines += NUM_LINES(rbe->len);
        }
        i++;
        if (lines > 0 && scroll_position != i) {
@@ -1207,7 +1229,7 @@ static void com_page_down(void)
                struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i);
                if (!rbe)
                        break;
-               lines += NUM_LINES(strlen(rbe->msg));
+               lines += NUM_LINES(rbe->len);
        }
        if (lines) {
                scroll_position = i;
@@ -1528,6 +1550,7 @@ int main(int argc, char *argv[])
        top.lines = theme.top_lines_default;
        setup_signal_handling();
        bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE);
+       setlocale(LC_CTYPE, "");
        initscr(); /* needed only once, always successful */
        init_curses();
        print_welcome();
index a913d3a..f1d8593 100644 (file)
@@ -60,7 +60,6 @@ static void http_recv_pre_select(struct sched *s, struct task *t)
        struct receiver_node *rn = container_of(t, struct receiver_node, task);
        struct private_http_recv_data *phd = rn->private_data;
 
-       t->error = 0;
        if (generic_recv_pre_select(s, t) <= 0)
                return;
        if  (phd->status == HTTP_CONNECTED)
@@ -74,7 +73,7 @@ static void http_recv_pre_select(struct sched *s, struct task *t)
  * area with data read from the socket. In any case, update the state of the
  * connection if necessary.
  */
-static void http_recv_post_select(struct sched *s, struct task *t)
+static int http_recv_post_select(struct sched *s, struct task *t)
 {
        struct receiver_node *rn = container_of(t, struct receiver_node, task);
        struct private_http_recv_data *phd = rn->private_data;
@@ -90,11 +89,11 @@ static void http_recv_post_select(struct sched *s, struct task *t)
        if (ret < 0)
                goto out;
        if (ret == 0)
-               return;
+               return 0;
        if (phd->status == HTTP_CONNECTED) {
                char *rq;
                if (!FD_ISSET(rn->fd, &s->wfds))
-                       return;
+                       return 0;
                rq = make_request_msg();
                PARA_INFO_LOG("sending http request\n");
                ret = write_va_buffer(rn->fd, "%s", rq);
@@ -102,17 +101,17 @@ static void http_recv_post_select(struct sched *s, struct task *t)
                if (ret < 0)
                        goto out;
                phd->status = HTTP_SENT_GET_REQUEST;
-               return;
+               return 0;
        }
        if (phd->status == HTTP_SENT_GET_REQUEST) {
                ret = read_pattern(rn->fd, HTTP_OK_MSG, strlen(HTTP_OK_MSG), &s->rfds);
                if (ret < 0)
                        goto out;
                if (ret == 0)
-                       return;
+                       return 0;
                PARA_INFO_LOG("received ok msg, streaming\n");
                phd->status = HTTP_STREAMING;
-               return;
+               return 0;
        }
        ret = -E_HTTP_RECV_OVERRUN;
        iovcnt = btr_pool_get_buffers(rn->btrp, iov);
@@ -128,10 +127,9 @@ static void http_recv_post_select(struct sched *s, struct task *t)
                btr_add_output_pool(rn->btrp, num_bytes - iov[0].iov_len, btrn);
        }
 out:
-       if (ret >= 0)
-               return;
-       btr_remove_node(&rn->btrn);
-       t->error = ret;
+       if (ret < 0)
+               btr_remove_node(&rn->btrn);
+       return ret;
 }
 
 static void http_recv_close(struct receiver_node *rn)
index bc3a7c1..f281901 100644 (file)
@@ -307,7 +307,7 @@ static void i9e_line_handler(char *line)
        }
 }
 
-static void i9e_post_select(__a_unused struct sched *s, struct task *t)
+static int i9e_post_select(__a_unused struct sched *s, __a_unused struct task *t)
 {
        int ret;
        struct i9e_client_info *ici = i9ep->ici;
@@ -361,7 +361,7 @@ rm_btrn:
                wipe_bottom_line();
 out:
        i9ep->caught_sigint = false;
-       t->error = ret;
+       return ret;
 }
 
 static void i9e_pre_select(struct sched *s, __a_unused struct task *t)
diff --git a/mix.h b/mix.h
index a410554..427a84f 100644 (file)
--- a/mix.h
+++ b/mix.h
@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 2012-2013 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file mix.h Mixer API (used by para_fade). */
+
 /**
  * Opaque structure which corresponds to an instance of a mixer.
  *
index 6470982..ece13e1 100644 (file)
--- a/mp3_afh.c
+++ b/mp3_afh.c
@@ -72,11 +72,11 @@ static const char *mode_text[] = {"stereo", "joint stereo", "dual channel", "mon
 
 #include <id3tag.h>
 
-static char *get_latin1(id3_ucs4_t const *string)
+static char *get_utf8(id3_ucs4_t const *string)
 {
        if (!string)
                return NULL;
-       return (char *)id3_ucs4_latin1duplicate(string);
+       return (char *)id3_ucs4_utf8duplicate(string);
 }
 
 static char *get_stringlist(union id3_field *field)
@@ -85,7 +85,7 @@ static char *get_stringlist(union id3_field *field)
        char *result = NULL;
 
        for (k = 0; k < nstrings; k++) {
-               char *tmp = (char *)get_latin1(id3_field_getstrings(field, k));
+               char *tmp = (char *)get_utf8(id3_field_getstrings(field, k));
                if (result) {
                        char *tmp2 = result;
                        result = make_message("%s %s", tmp2, tmp);
@@ -101,7 +101,7 @@ static char *get_string(union id3_field *field)
 {
        id3_ucs4_t const *string = id3_field_getfullstring(field);
 
-       return get_latin1(string);
+       return get_utf8(string);
 }
 
 #define FOR_EACH_FIELD(f, j, fr) for (j = 0; j < (fr)->nfields && \
index bd1f0d3..9862750 100644 (file)
@@ -77,7 +77,7 @@ static void mp3dec_close(struct filter_node *fn)
 
 #define MP3DEC_MAX_FRAME 8192
 
-static void mp3dec_post_select(__a_unused struct sched *s, struct task *t)
+static int mp3dec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        int i, ret;
@@ -88,13 +88,12 @@ static void mp3dec_post_select(__a_unused struct sched *s, struct task *t)
 
 next_buffer:
        pmd->stream.error = 0;
-       t->error = 0;
        iqs = btr_get_input_queue_size(btrn);
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0)
                goto err;
        if (ret == 0)
-               return;
+               return 0;
        btr_merge(btrn, fn->min_iqs);
        len = btr_next_buffer(btrn, &inbuffer);
        /*
@@ -120,7 +119,7 @@ next_frame:
                }
                if (loaded == 0)
                        goto next_buffer;
-               return;
+               return 0;
        }
        pmd->sample_rate = pmd->frame.header.samplerate;
        pmd->channels = MAD_NCHANNELS(&pmd->frame.header);
@@ -140,12 +139,12 @@ decode:
                        if (fn->min_iqs > MP3DEC_MAX_FRAME)
                                goto err;
                        mp3dec_consume(btrn, &pmd->stream, len);
-                       return;
+                       return 0;
                }
                if (pmd->stream.error != MAD_ERROR_BADDATAPTR)
                        goto decode;
                mp3dec_consume(btrn, &pmd->stream, len);
-               return;
+               return 0;
        }
        fn->min_iqs = 0;
        mad_synth_frame(&pmd->synth, &pmd->frame);
@@ -165,8 +164,8 @@ decode:
        goto next_frame;
 err:
        assert(ret < 0);
-       t->error = ret;
        btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 static void mp3dec_open(struct filter_node *fn)
index b405f86..f41150f 100644 (file)
@@ -199,7 +199,7 @@ static void ogg_pre_select(struct sched *s, struct task *t)
        sched_min_delay(s);
 }
 
-static void ogg_post_select(__a_unused struct sched *s, struct task *t)
+static int ogg_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct private_oggdec_data *pod = fn->private_data;
@@ -217,7 +217,7 @@ static void ogg_post_select(__a_unused struct sched *s, struct task *t)
        } else if (ret == 0 && !pod->have_more) /* nothing to do */
                goto out;
        if (btr_get_output_queue_size(btrn) > OGGDEC_MAX_OUTPUT_SIZE)
-               return;
+               return 0;
        if (!pod->vf) {
                if (ret <= 0)
                        goto out;
@@ -254,12 +254,12 @@ static void ogg_post_select(__a_unused struct sched *s, struct task *t)
        if (ret == OV_HOLE) /* avoid buffer underruns */
                fn->min_iqs = 9000;
        if (ret >= 0 || ret == OV_HOLE)
-               return;
+               return 0;
        ret = -E_OGGDEC_BADLINK;
 out:
-       t->error = ret;
        if (ret < 0)
                btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 /**
index 57bdcfa..cd32724 100644 (file)
@@ -157,7 +157,7 @@ err_free:
        return ret;
 }
 
-static void oss_post_select(__a_unused struct sched *s,
+static int oss_post_select(__a_unused struct sched *s,
                struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
@@ -181,7 +181,7 @@ static void oss_post_select(__a_unused struct sched *s,
                ret = oss_init(wn, rate, ch, format);
                if (ret < 0)
                        goto out;
-               return;
+               return 0;
        }
        btr_merge(btrn, wn->min_iqs);
        bytes = btr_next_buffer(btrn, &data);
@@ -199,9 +199,9 @@ static void oss_post_select(__a_unused struct sched *s,
        btr_consume(btrn, ret);
        ret = 0;
 out:
-       t->error = ret;
        if (ret < 0)
                btr_remove_node(&wn->btrn);
+       return ret;
 }
 
 __malloc static void *oss_parse_config_or_die(int argc, char **argv)
index d38e2fb..41b1903 100644 (file)
@@ -301,7 +301,7 @@ static void osx_write_pre_select(struct sched *s, struct task *t)
        sched_request_timeout_ms(50, s);
 }
 
-static void osx_write_post_select(__a_unused struct sched *s, struct task *t)
+static int osx_write_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct writer_node *wn = container_of(t, struct writer_node, task);
        struct private_osx_write_data *powd = wn->private_data;
@@ -314,7 +314,7 @@ static void osx_write_post_select(__a_unused struct sched *s, struct task *t)
        if (!powd) {
                ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
                if (ret == 0)
-                       return;
+                       return 0;
                if (ret < 0)
                        goto fail;
                ret = core_audio_init(wn);
@@ -337,7 +337,7 @@ static void osx_write_post_select(__a_unused struct sched *s, struct task *t)
                ret = 0;
        mutex_unlock(powd->mutex);
        if (ret >= 0)
-               return;
+               return 0;
 fail:
        assert(ret < 0);
        if (powd && powd->callback_btrn) {
@@ -348,7 +348,7 @@ fail:
        }
        btr_remove_node(&wn->btrn);
        PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
-       t->error = ret;
+       return ret;
 }
 
 /**
diff --git a/para.h b/para.h
index 4208ae6..edab487 100644 (file)
--- a/para.h
+++ b/para.h
@@ -109,6 +109,7 @@ void ms2tv(const long unsigned n, struct timeval *tv);
 void compute_chunk_time(long unsigned chunk_num,
                struct timeval *chunk_tv, struct timeval *stream_start,
                struct timeval *result);
+struct timeval *clock_get_realtime(struct timeval *tv);
 
 /** The enum of all status items. */
 enum status_items {STATUS_ITEM_ENUM NUM_STAT_ITEMS};
diff --git a/play.c b/play.c
index cca203b..2cb0536 100644 (file)
--- a/play.c
+++ b/play.c
@@ -7,7 +7,6 @@
 /** \file play.c Paraslash's standalone player. */
 
 #include <regex.h>
-#include <sys/time.h>
 #include <fnmatch.h>
 #include <signal.h>
 
@@ -1196,7 +1195,7 @@ static unsigned get_time_string(struct play_task *pt, char **result)
        );
 }
 
-static void play_post_select(struct sched *s, struct task *t)
+static int play_post_select(struct sched *s, struct task *t)
 {
        struct play_task *pt = container_of(t, struct play_task, task);
        int ret;
@@ -1204,7 +1203,7 @@ static void play_post_select(struct sched *s, struct task *t)
        ret = eof_cleanup(pt);
        if (ret < 0) {
                pt->rq = CRT_TERM_RQ;
-               return;
+               return 0;
        }
        ret = session_post_select(s, t);
        if (ret < 0)
@@ -1234,7 +1233,7 @@ static void play_post_select(struct sched *s, struct task *t)
        }
        ret = 1;
 out:
-       t->error = ret;
+       return ret;
 }
 
 /**
@@ -1255,7 +1254,7 @@ int main(int argc, char *argv[])
        filter_init();
        writer_init();
 
-       gettimeofday(now, NULL);
+       clock_get_realtime(now);
        sched.default_timeout.tv_sec = 5;
 
        parse_config_or_die(argc, argv);
index e1afff5..0759d67 100644 (file)
@@ -37,7 +37,6 @@ static void prebuffer_pre_select(struct sched *s, struct task *t)
        struct prebuffer_filter_args_info *conf = ppd->conf;
        struct timeval diff;
 
-       t->error = 0;
        if (iqs == 0)
                return;
        if (ppd->barrier.tv_sec == 0) {
@@ -57,7 +56,7 @@ static void prebuffer_close(struct filter_node *fn)
        free(fn->private_data);
 }
 
-static void prebuffer_post_select(__a_unused struct sched *s, struct task *t)
+static int prebuffer_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct btr_node *btrn = fn->btrn;
@@ -65,15 +64,14 @@ static void prebuffer_post_select(__a_unused struct sched *s, struct task *t)
        struct private_prebuffer_data *ppd = fn->private_data;
        struct prebuffer_filter_args_info *conf = ppd->conf;
 
-       t->error = 0;
        if (ppd->barrier.tv_sec == 0)
-               return;
+               return 0;
        if (tv_diff(now, &ppd->barrier, NULL) < 0)
-               return;
+               return 0;
        if (iqs < conf->size_arg)
-               return;
-       btr_splice_out_node(btrn);
-       t->error = -E_PREBUFFER_SUCCESS;
+               return 0;
+       btr_splice_out_node(fn->btrn);
+       return -E_PREBUFFER_SUCCESS;
 }
 
 static int prebuffer_parse_config(int argc, char **argv, void **config)
diff --git a/recv.h b/recv.h
index f70cbbe..cc44a60 100644 (file)
--- a/recv.h
+++ b/recv.h
@@ -115,7 +115,7 @@ struct receiver {
         *
         * \sa select(2), struct receiver.
         */
-       void (*post_select)(struct sched *s, struct task *t);
+       int (*post_select)(struct sched *s, struct task *t);
 
        /** The two help texts of this receiver. */
        struct ggo_help help;
index ed9945a..bd8ece9 100644 (file)
@@ -202,7 +202,7 @@ static int resample_frames(int16_t *in, size_t num_frames, bool have_more,
        return data.input_frames_used;
 }
 
-static void resample_post_select(__a_unused struct sched *s, struct task *t)
+static int resample_post_select(__a_unused struct sched *s, struct task *t)
 {
        int ret;
        struct filter_node *fn = container_of(t, struct filter_node, task);
@@ -231,7 +231,8 @@ static void resample_post_select(__a_unused struct sched *s, struct task *t)
                 * btr exec mechanism for the destination samplerate and the
                 * channel count.
                 */
-               return btr_pushdown(btrn);
+               btr_pushdown(btrn);
+               return 0;
        }
        btr_merge(btrn, fn->min_iqs);
        in_bytes = btr_next_buffer(btrn, (char **)&in);
@@ -246,14 +247,14 @@ static void resample_post_select(__a_unused struct sched *s, struct task *t)
                goto out;
        btr_consume(btrn, ret * 2 * ctx->channels);
        btr_add_output((char *)out, num_frames * 2 * ctx->channels, btrn);
-       return;
+       return 0;
 out:
        if (ret < 0) {
-               t->error = ret;
                btr_remove_node(&fn->btrn);
                /* This releases the check_wav btr node */
                check_wav_post_select(ctx->cwc);
        }
+       return ret;
 }
 
 static int resample_parse_config(int argc, char **argv, void **config)
diff --git a/sched.c b/sched.c
index 7ee7702..d42e149 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -8,7 +8,6 @@
 
 #include <regex.h>
 #include <assert.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "ipc.h"
@@ -50,20 +49,12 @@ static inline bool timeout_is_zero(struct sched *s)
 static void sched_preselect(struct sched *s)
 {
        struct task *t, *tmp;
+
        list_for_each_entry_safe(t, tmp, &s->pre_select_list, pre_select_node) {
-               if (t->error < 0) {
-                       unregister_task(t);
-                       continue;
-               }
-               if (t->notification != 0) {
+               if (t->notification != 0)
                        sched_min_delay(s);
-                       break;
-               }
-               if (!t->pre_select)
-                       continue;
-               t->pre_select(s, t);
-               if (timeout_is_zero(s))
-                       break;
+               if (t->pre_select)
+                       t->pre_select(s, t);
        }
 }
 
@@ -71,14 +62,14 @@ static void sched_preselect(struct sched *s)
 static inline void call_post_select(struct sched *s, struct task *t)
 {
 #ifndef SCHED_DEBUG
-       t->post_select(s, t);
+       t->error = t->post_select(s, t);
 #else
        struct timeval t1, t2, diff;
        unsigned long pst;
 
-       gettimeofday(&t1, NULL);
-       t->post_select(s, t);
-       gettimeofday(&t2, NULL);
+       clock_get_realtime(&t1);
+       t->error = t->post_select(s, t);
+       clock_get_realtime(&t2);
        tv_diff(&t1, &t2, &diff);
        pst = tv2ms(&diff);
        if (pst > 50)
@@ -128,30 +119,23 @@ again:
        FD_ZERO(&s->wfds);
        s->select_timeout = s->default_timeout;
        s->max_fileno = -1;
-       gettimeofday(now, NULL);
+       clock_get_realtime(now);
        sched_preselect(s);
-       if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list))
-               return 0;
-       if (!timeout_is_zero(s)) {
-               ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds,
-                       &s->select_timeout);
-               if (ret < 0)
-                       return ret;
-               if (ret == 0) {
-                       /*
-                        * APUE: Be careful not to check the descriptor sets on return
-                        * unless the return value is greater than zero. The return
-                        * state of the descriptor sets is implementation dependent if
-                        * either a signal is caught or the timer expires.
-                        */
-                       FD_ZERO(&s->rfds);
-                       FD_ZERO(&s->wfds);
-               }
-               gettimeofday(now, NULL);
-       } else {
+       ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds,
+               &s->select_timeout);
+       if (ret < 0)
+               return ret;
+       if (ret == 0) {
+               /*
+                * APUE: Be careful not to check the descriptor sets on return
+                * unless the return value is greater than zero. The return
+                * state of the descriptor sets is implementation dependent if
+                * either a signal is caught or the timer expires.
+                */
                FD_ZERO(&s->rfds);
                FD_ZERO(&s->wfds);
        }
+       clock_get_realtime(now);
        sched_post_select(s);
        if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list))
                return 0;
diff --git a/sched.h b/sched.h
index 7a5a4f8..9c5c098 100644 (file)
--- a/sched.h
+++ b/sched.h
@@ -55,11 +55,13 @@ struct task {
         */
        void (*pre_select)(struct sched *s, struct task *t);
        /**
-        * The postselect hook of \a t.
+        * The post select hook of \a t.
         *
-        * Evaluate and act upon the results of the previous select call.
+        * Its purpose is to evaluate and act upon the results of the previous
+        * select call. If this function returns a negative value, the
+        * scheduler unregisters the task.
         */
-       void (*post_select)(struct sched *s, struct task *t);
+       int (*post_select)(struct sched *s, struct task *t);
        /** Whether this task is in error state. */
        int error;
        /** Position of the task in the pre_select list of the scheduler. */
@@ -76,7 +78,7 @@ struct task {
  * This is set by the scheduler at the beginning of its main loop.  It may be
  * used (read-only) from everywhere. As none of the functions called by the
  * scheduler are allowed to block, this value should be accurate enough so that
- * there is no need to call gettimeofday() directly.
+ * there is no need to call clock_gettime() directly.
  */
 extern struct timeval *now;
 
index 2595d9c..f3d5237 100644 (file)
--- a/server.c
+++ b/server.c
@@ -67,7 +67,6 @@
  */
 
 #include <signal.h>
-#include <sys/time.h>
 #include <regex.h>
 #include <osl.h>
 
@@ -279,13 +278,13 @@ static void handle_sighup(void)
                kill(mmd->afs_pid, SIGHUP);
 }
 
-static void signal_post_select(struct sched *s, __a_unused struct task *t)
+static int signal_post_select(struct sched *s, __a_unused struct task *t)
 {
        int signum = para_next_signal(&s->rfds);
 
        switch (signum) {
        case 0:
-               return;
+               return 0;
        case SIGHUP:
                handle_sighup();
                break;
@@ -330,6 +329,7 @@ cleanup:
                shm_detach(mmd);
                exit(EXIT_FAILURE);
        }
+       return 0;
 }
 
 static void init_signal_task(void)
@@ -358,7 +358,7 @@ static void command_pre_select(struct sched *s, struct task *t)
        para_fd_set(sct->listen_fd, &s->rfds, &s->max_fileno);
 }
 
-static void command_post_select(struct sched *s, struct task *t)
+static int command_post_select(struct sched *s, struct task *t)
 {
        struct server_command_task *sct = container_of(t, struct server_command_task, task);
 
@@ -392,7 +392,7 @@ static void command_post_select(struct sched *s, struct task *t)
        if (child_pid) {
                close(new_fd);
                /* parent keeps accepting connections */
-               return;
+               return 0;
        }
        /* mmd might already have changed at this point */
        free(chunk_table);
@@ -406,10 +406,12 @@ static void command_post_select(struct sched *s, struct task *t)
        for (i = sct->argc - 1; i >= 0; i--)
                memset(sct->argv[i], 0, strlen(sct->argv[i]));
        sprintf(sct->argv[0], "para_server (serving %s)", peer_name);
-       return handle_connect(new_fd, peer_name);
+       handle_connect(new_fd, peer_name);
+       /* never reached*/
 out:
        if (ret < 0)
                PARA_CRIT_LOG("%s\n", para_strerror(-ret));
+       return 0;
 }
 
 static void init_server_command_task(int argc, char **argv)
@@ -493,7 +495,7 @@ static void server_init(int argc, char **argv)
        log_welcome("para_server");
        init_ipc_or_die(); /* init mmd struct and mmd->lock */
        /* make sure, the global now pointer is uptodate */
-       gettimeofday(now, NULL);
+       clock_get_realtime(now);
        set_server_start_time(now);
        init_user_list(user_list_file);
        /* become daemon */
index 6bd4114..9bba042 100644 (file)
@@ -238,7 +238,7 @@ static int compute_skip_samples(ogg_page *og, struct private_spxdec_data *psd)
        return ret;
 }
 
-static void speexdec_post_select(__a_unused struct sched *s, struct task *t)
+static int speexdec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct private_spxdec_data *psd = fn->private_data;
@@ -249,7 +249,6 @@ static void speexdec_post_select(__a_unused struct sched *s, struct task *t)
        size_t nbytes;
 
 next_buffer:
-       t->error = 0;
        ret = ns = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        btr_merge(btrn, fn->min_iqs);
        if (!psd->shi.state) {
@@ -290,10 +289,9 @@ next_buffer:
                goto next_buffer;
        ret = ns;
 fail:
-       if (ret < 0) {
-               t->error = ret;
+       if (ret < 0)
                btr_remove_node(&fn->btrn);
-       }
+       return ret;
 }
 
 /**
diff --git a/stdin.c b/stdin.c
index fd803ae..b25a0ba 100644 (file)
--- a/stdin.c
+++ b/stdin.c
@@ -33,7 +33,6 @@ static void stdin_pre_select(struct sched *s, struct task *t)
        struct stdin_task *sit = container_of(t, struct stdin_task, task);
        int ret;
 
-       t->error = 0;
        ret = btr_node_status(sit->btrn, 0, BTR_NT_ROOT);
        if (ret < 0)
                sched_min_delay(s);
@@ -55,22 +54,21 @@ static void stdin_pre_select(struct sched *s, struct task *t)
  * appears to be readable, data is read from stdin and fed into the buffer
  * tree.
  */
-static void stdin_post_select(struct sched *s, struct task *t)
+static int stdin_post_select(struct sched *s, struct task *t)
 {
        struct stdin_task *sit = container_of(t, struct stdin_task, task);
        ssize_t ret;
        size_t sz, n;
        char *buf = NULL;
 
-       t->error = 0;
        ret = btr_node_status(sit->btrn, 0, BTR_NT_ROOT);
        if (ret < 0)
                goto err;
        if (ret == 0)
-               return;
+               return 0;
        sz = btr_pool_get_buffer(sit->btrp, &buf);
        if (sz == 0)
-               return;
+               return 0;
        /*
         * Do not use the maximal size to avoid having only a single buffer
         * reference for the whole pool. This is bad because if that single
@@ -81,11 +79,11 @@ static void stdin_post_select(struct sched *s, struct task *t)
        if (n > 0)
                btr_add_output_pool(sit->btrp, n, sit->btrn);
        if (ret >= 0)
-               return;
+               return 0;
 err:
        btr_remove_node(&sit->btrn);
        //btr_pool_free(sit->btrp);
-       t->error = ret;
+       return ret;
 }
 
 /**
index 9c7e64e..abf3d06 100644 (file)
--- a/stdout.c
+++ b/stdout.c
@@ -30,7 +30,6 @@ static void stdout_pre_select(struct sched *s, struct task *t)
        struct stdout_task *sot = container_of(t, struct stdout_task, task);
        int ret;
 
-       t->error = 0;
        ret = btr_node_status(sot->btrn, 0, BTR_NT_LEAF);
        if (ret > 0)
                para_fd_set(STDOUT_FILENO, &s->wfds, &s->max_fileno);
@@ -47,7 +46,7 @@ static void stdout_pre_select(struct sched *s, struct task *t)
  * This function writes input data from the buffer tree to stdout if \p
  * STDOUT_FILENO is writable.
  */
-static void stdout_post_select(struct sched *s, struct task *t)
+static int stdout_post_select(struct sched *s, struct task *t)
 {
        struct stdout_task *sot = container_of(t, struct stdout_task, task);
        struct btr_node *btrn = sot->btrn;
@@ -55,14 +54,13 @@ static void stdout_post_select(struct sched *s, struct task *t)
        char *buf;
        size_t sz;
 
-       t->error = 0;
        ret = btr_node_status(btrn, 0, BTR_NT_LEAF);
        if (ret < 0)
                goto out;
        if (ret == 0)
-               return;
+               return 0;
        if (!FD_ISSET(STDOUT_FILENO, &s->wfds))
-               return;
+               return 0;
 
        for (;;) {
                sz = btr_next_buffer(btrn, &buf);
@@ -76,7 +74,7 @@ static void stdout_post_select(struct sched *s, struct task *t)
 out:
        if (ret < 0)
                btr_remove_node(&sot->btrn);
-       t->error = ret;
+       return ret;
 }
 /**
  * Initialize a stdout task structure with default values.
index 4d8b8b7..38e25b0 100644 (file)
--- a/string.c
+++ b/string.c
@@ -6,12 +6,18 @@
 
 /** \file string.c Memory allocation and string handling functions. */
 
-#include <sys/time.h> /* gettimeofday */
+#define _GNU_SOURCE
+
 #include <pwd.h>
 #include <sys/utsname.h> /* uname() */
+
 #include <string.h>
 #include <regex.h>
 
+#include <langinfo.h>
+#include <wchar.h>
+#include <wctype.h>
+
 #include "para.h"
 #include "string.h"
 #include "error.h"
@@ -945,3 +951,145 @@ char *key_value_copy(const char *src, size_t len, const char *key)
                return NULL;
        return safe_strdup(src + keylen + 1, len - keylen - 1);
 }
+
+static bool utf8_mode(void)
+{
+       static bool initialized, have_utf8;
+
+       if (!initialized) {
+               char *info = nl_langinfo(CODESET);
+               have_utf8 = (info && strcmp(info, "UTF-8") == 0);
+               initialized = true;
+               PARA_INFO_LOG("%susing UTF-8 character encoding\n",
+                       have_utf8? "" : "not ");
+       }
+       return have_utf8;
+}
+
+/*
+ * glibc's wcswidth returns -1 if the string contains a tab character, which
+ * makes the function next to useless. The two functions below are taken from
+ * mutt.
+ */
+
+#define IsWPrint(wc) (iswprint(wc) || wc >= 0xa0)
+
+static int mutt_wcwidth(wchar_t wc, size_t pos)
+{
+       int n;
+
+       if (wc == 0x09) /* tab */
+               return (pos | 7) + 1 - pos;
+       n = wcwidth(wc);
+       if (IsWPrint(wc) && n > 0)
+               return n;
+       if (!(wc & ~0x7f))
+               return 2;
+       if (!(wc & ~0xffff))
+               return 6;
+       return 10;
+}
+
+static size_t mutt_wcswidth(const wchar_t *s, size_t n)
+{
+       size_t w = 0;
+
+       while (n--)
+               w += mutt_wcwidth(*s++, w);
+       return w;
+}
+
+/**
+ * Skip a given number of cells at the beginning of a string.
+ *
+ * \param s The input string.
+ * \param cells_to_skip Desired number of cells that should be skipped.
+ * \param bytes_to_skip Result.
+ *
+ * This function computes how many input bytes must be skipped to advance a
+ * string by the given width. If the current character encoding is not UTF-8,
+ * this is simply the given number of cells, i.e. \a cells_to_skip. Otherwise,
+ * \a s is treated as a multibyte string and on successful return, \a s +
+ * bytes_to_skip points to the start of a multibyte string such that the total
+ * width of the multibyte characters that are skipped by advancing \a s that
+ * many bytes equals at least \a cells_to_skip.
+ *
+ * \return Standard.
+ */
+int skip_cells(const char *s, size_t cells_to_skip, size_t *bytes_to_skip)
+{
+       wchar_t wc;
+       mbstate_t ps;
+       size_t n, bytes_parsed, cells_skipped;
+
+       *bytes_to_skip = 0;
+       if (cells_to_skip == 0)
+               return 0;
+       if (!utf8_mode()) {
+               *bytes_to_skip = cells_to_skip;
+               return 0;
+       }
+       bytes_parsed = cells_skipped = 0;
+       memset(&ps, 0, sizeof(ps));
+       n = strlen(s);
+       while (cells_to_skip > cells_skipped) {
+               size_t mbret;
+
+               mbret = mbrtowc(&wc, s + bytes_parsed, n - bytes_parsed, &ps);
+               assert(mbret != 0);
+               if (mbret == (size_t)-1 || mbret == (size_t)-2)
+                       return -ERRNO_TO_PARA_ERROR(EILSEQ);
+               bytes_parsed += mbret;
+               cells_skipped += mutt_wcwidth(wc, cells_skipped);
+       }
+       *bytes_to_skip = bytes_parsed;
+       return 1;
+}
+
+/**
+ * Compute the width of an UTF-8 string.
+ *
+ * \param s The string.
+ * \param result The width of \a s is returned here.
+ *
+ * If not in UTF8-mode. this function is just a wrapper for strlen(3).
+ * Otherwise \a s is treated as an UTF-8 string and its display width is
+ * computed. Note that this function may fail if the underlying call to
+ * mbsrtowcs(3) fails, so the caller must check the return value.
+ *
+ * \sa nl_langinfo(3), wcswidth(3).
+ *
+ * \return Standard.
+ */
+__must_check int strwidth(const char *s, size_t *result)
+{
+       const char *src = s;
+       mbstate_t state;
+       static wchar_t *dest;
+       size_t num_wchars;
+
+       /*
+        * Never call any log function here. This may result in an endless loop
+        * as para_gui's para_log() calls this function.
+        */
+
+       if (!utf8_mode()) {
+               *result = strlen(s);
+               return 0;
+       }
+       memset(&state, 0, sizeof(state));
+       *result = 0;
+       num_wchars = mbsrtowcs(NULL, &src, 0, &state);
+       if (num_wchars == (size_t)-1)
+               return -ERRNO_TO_PARA_ERROR(errno);
+       if (num_wchars == 0)
+               return 0;
+       dest = para_malloc(num_wchars * sizeof(*dest));
+       src = s;
+       memset(&state, 0, sizeof(state));
+       num_wchars = mbsrtowcs(dest, &src, num_wchars, &state);
+       assert(num_wchars > 0 && num_wchars != (size_t)-1);
+       *result = mutt_wcswidth(dest, num_wchars);
+       free(dest);
+       return 1;
+}
index 230f654..935c7d4 100644 (file)
--- a/string.h
+++ b/string.h
@@ -102,3 +102,5 @@ void freep(void *arg);
 int compute_word_num(const char *buf, const char *delim, int offset);
 char *safe_strdup(const char *src, size_t len);
 char *key_value_copy(const char *src, size_t len, const char *key);
+int skip_cells(const char *s, size_t cells_to_skip, size_t *result);
+__must_check int strwidth(const char *s, size_t *result);
diff --git a/time.c b/time.c
index 18b5a35..6f6dd49 100644 (file)
--- a/time.c
+++ b/time.c
@@ -191,3 +191,40 @@ void compute_chunk_time(long unsigned chunk_num,
        tv_scale(chunk_num, chunk_tv, &tmp);
        tv_add(&tmp, stream_start, result);
 }
+
+/**
+ * Retrieve the time of the realtime clock.
+ *
+ * \param tv Where to store the result.
+ *
+ * Gets the current value of the system-wide real-time clock (identified by id
+ * \p CLOCK_REALTIME). If \a tv is \p NULL, the value is stored in a static
+ * buffer, otherwise it is stored at the location given by \a tv.
+ *
+ * \return This function aborts on errors. On success it returns a pointer to
+ * memory containing the current time.
+ *
+ * \sa clock_gettime(2), gettimeofday(2).
+ */
+struct timeval *clock_get_realtime(struct timeval *tv)
+{
+       static struct timeval user_friendly;
+
+       if (!tv)
+               tv = &user_friendly;
+#ifdef HAVE_CLOCK_GETTIME
+       {
+               struct timespec t;
+               int ret;
+
+               ret = clock_gettime(CLOCK_REALTIME, &t);
+               assert(ret == 0);
+               tv->tv_sec = t.tv_sec;
+               tv->tv_usec = t.tv_nsec / 1000;
+       }
+#else
+       #include <sys/time.h>
+       gettimeofday(tv, NULL);
+#endif /* HAVE_CLOCK_GETTIME */
+       return tv;
+}
index 6c5ee02..f9c70ec 100644 (file)
@@ -49,7 +49,7 @@ static int udp_check_eof(size_t sz, struct iovec iov[2])
        return -E_RECV_EOF;
 }
 
-static void udp_recv_post_select(__a_unused struct sched *s, struct task *t)
+static int udp_recv_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct receiver_node *rn = container_of(t, struct receiver_node, task);
        struct btr_node *btrn = rn->btrn;
@@ -83,12 +83,12 @@ static void udp_recv_post_select(__a_unused struct sched *s, struct task *t)
        }
        ret = readv_ret;
 out:
-       if (ret >= 0)
-               return;
-       btr_remove_node(&rn->btrn);
-       t->error = ret;
-       close(rn->fd);
-       rn->fd = -1;
+       if (ret < 0) {
+               btr_remove_node(&rn->btrn);
+               close(rn->fd);
+               rn->fd = -1;
+       }
+       return ret;
 }
 
 static void udp_recv_close(struct receiver_node *rn)
index b41c0eb..7930f09 100644 (file)
@@ -8,7 +8,7 @@
 
 
 #include <regex.h>
-#include <sys/time.h>
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/udp.h>
 #include <net/if.h>
diff --git a/vss.c b/vss.c
index cfa64a1..aec357a 100644 (file)
--- a/vss.c
+++ b/vss.c
@@ -1114,12 +1114,11 @@ static void vss_send(struct vss_task *vsst)
        }
 }
 
-static void vss_post_select(struct sched *s, struct task *t)
+static int vss_post_select(struct sched *s, struct task *t)
 {
        int ret, i;
        struct vss_task *vsst = container_of(t, struct vss_task, task);
 
-
        if (mmd->sender_cmd_data.cmd_num >= 0) {
                int num = mmd->sender_cmd_data.cmd_num,
                        sender_num = mmd->sender_cmd_data.sender_num;
@@ -1151,6 +1150,7 @@ static void vss_post_select(struct sched *s, struct task *t)
                        (vss_next() && vss_playing()))
                tv_add(now, &vsst->announce_tv, &vsst->data_send_barrier);
        vss_send(vsst);
+       return 0;
 }
 
 /**
index 716d8dd..83b81fb 100644 (file)
@@ -74,7 +74,7 @@ static void wav_pre_select(struct sched *s, struct task *t)
        sched_min_delay(s);
 }
 
-static void wav_post_select(__a_unused struct sched *s, struct task *t)
+static int wav_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        struct btr_node *btrn = fn->btrn;
@@ -83,12 +83,11 @@ static void wav_post_select(__a_unused struct sched *s, struct task *t)
        char *header, *buf;
        int32_t rate, ch;
 
-       t->error = 0;
        if (iqs == 0) {
                ret = -E_WAV_EOF;
                if (btr_no_parent(btrn))
                        goto err;
-               return;
+               return 0;
        }
        ret = btr_exec_up(btrn, "sample_rate", &buf);
        if (ret < 0) {
@@ -113,13 +112,13 @@ static void wav_post_select(__a_unused struct sched *s, struct task *t)
        btr_add_output(header, WAV_HEADER_LEN, btrn);
        ret = -E_WAV_SUCCESS;
 err:
-       t->error = ret;
        if (ret == -E_WAV_SUCCESS)
                btr_splice_out_node(btrn);
        else {
                btr_remove_node(&fn->btrn);
                PARA_ERROR_LOG("%s\n", para_strerror(-ret));
        }
+       return ret;
 }
 
 /**
index 464db04..f7cb277 100644 (file)
@@ -2,7 +2,7 @@
    "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
-       <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
+       <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
        <title>Paraslash</title>
        <LINK href="para.css" REL="stylesheet" TYPE="text/css">
        <link rel="shortcut icon" href="paraslash.ico">
index c8de7af..94fbcad 100644 (file)
@@ -2,7 +2,7 @@
    "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
-       <meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>
+       <meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
        <title>Paraslash</title>
        <LINK href="../../para.css" REL="stylesheet" TYPE="text/css">
        <link rel="shortcut icon" href="../../paraslash.ico">
index bedc170..3f5f148 100644 (file)
@@ -202,8 +202,16 @@ REFERENCE(Quick start, set up) a typical server and client.
 
 Requirements
 ~~~~~~~~~~~~
+For the impatient:
 
-In any case you'll need
+       git clone git://git.tuebingen.mpg.de/osl
+       cd osl && make && sudo make install && sudo ldconfig
+       sudo apt-get install autoconf libssl-dev help2man gengetopt \
+              libmad0-dev libid3tag0-dev libasound2-dev libvorbis-dev \
+              libfaad-dev libspeex-dev libFLAC-dev libsamplerate-dev \
+              libasound2-dev libao-dev libreadline-dev libncurses-dev
+
+Detailed description: In any case you'll need
 
        - XREFERENCE(http://systemlinux.org/~maan/osl/, libosl).
        The _object storage layer_ library is used by para_server. To
@@ -267,6 +275,10 @@ Optional:
        or decode files encoded with the _Free Lossless Audio Codec_,
        libFLAC (libFLAC-dev) must be installed.
 
+       - XREFERENCE(http://www.mega-nerd.com/SRC/index.html,
+       libsamplerate). The resample filter will only be compiled if
+       this library is installed. Debian package: libsamplerate-dev.
+
        - XREFERENCE(ftp://ftp.alsa-project.org/pub/lib/, alsa-lib). On
        Linux, you'll need to have ALSA's development package
        libasound2-dev installed.
@@ -275,6 +287,9 @@ Optional:
        libao). Needed to build the ao writer (ESD, PulseAudio,...).
        Debian package: libao-dev.
 
+       - XREFERENCE(ftp://ftp.gnu.org/pub/gnu/ncurses, curses). Needed
+       for para_gui. Debian package: libncurses-dev.
+
        - XREFERENCE(http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html,
        GNU Readline). If this library (libreadline-dev) is installed,
        para_client, para_audioc and para_play support interactive
diff --git a/wma.h b/wma.h
index 33e34a3..f0ba7f6 100644 (file)
--- a/wma.h
+++ b/wma.h
@@ -25,7 +25,7 @@ struct asf_header_info {
 };
 
 /* wma_common.c */
-int wma_log2(unsigned int v);
+__a_const int wma_log2(unsigned int v);
 const char *search_pattern(const char *pattern, int pattern_len,
                const char *buf, int buf_size);
 int read_asf_header(const char *buf, int loaded, struct asf_header_info *ahi);
index 20f9df4..8b751f0 100644 (file)
@@ -17,7 +17,6 @@
 
 #define _XOPEN_SOURCE 600
 
-#include <sys/time.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1211,7 +1210,7 @@ static int wmadec_execute(struct btr_node *btrn, const char *cmd, char **result)
 
 #define WMA_OUTPUT_BUFFER_SIZE (128 * 1024)
 
-static void wmadec_post_select(__a_unused struct sched *s, struct task *t)
+static int wmadec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
        int ret, converted, out_size;
@@ -1222,12 +1221,11 @@ static void wmadec_post_select(__a_unused struct sched *s, struct task *t)
 
 next_buffer:
        converted = 0;
-       t->error = 0;
        ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL);
        if (ret < 0)
                goto err;
        if (ret == 0)
-               return;
+               return 0;
        btr_merge(btrn, fn->min_iqs);
        len = btr_next_buffer(btrn, (char **)&in);
        ret = -E_WMADEC_EOF;
@@ -1263,11 +1261,11 @@ next_buffer:
        converted += ret + WMA_FRAME_SKIP;
 success:
        btr_consume(btrn, converted);
-       return;
+       return 0;
 err:
        assert(ret < 0);
-       t->error = ret;
        btr_remove_node(&fn->btrn);
+       return ret;
 }
 
 static void wmadec_open(struct filter_node *fn)
diff --git a/write.c b/write.c
index 3deef14..866ea43 100644 (file)
--- a/write.c
+++ b/write.c
@@ -86,10 +86,10 @@ static void write_pre_select(struct sched *s, struct task *t)
        check_wav_pre_select(s, wt->cwc);
 }
 
-static void write_post_select(__a_unused struct sched *s, struct task *t)
+static int write_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct write_task *wt = container_of(t, struct write_task, task);
-       t->error = check_wav_post_select(wt->cwc);
+       return check_wav_post_select(wt->cwc);
 }
 
 static int setup_and_schedule(void)
diff --git a/write.h b/write.h
index 2573ba5..8292160 100644 (file)
--- a/write.h
+++ b/write.h
@@ -65,7 +65,7 @@ struct writer {
         *
         * Called from the post_select function of the writer node's task.
         */
-       void (*post_select)(struct sched *s, struct task *t);
+       int (*post_select)(struct sched *s, struct task *t);
        /**
         * Close one instance of the writer.
         *
index a4f908a..44ccf88 100644 (file)
@@ -113,8 +113,8 @@ void register_writer_node(struct writer_node *wn, struct btr_node *parent,
                .handler = w->execute, .context = wn));
        strcpy(wn->task.status, name);
        free(name);
-       wn->task.post_select = w->post_select;
        wn->task.pre_select = w->pre_select;
+       wn->task.post_select = w->post_select;
        register_task(s, &wn->task);
 }