X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/460b9539a7c15580e41a71bbc0f47ae776238915..768d7355deef8b14f6d2d5bdc9bc8d5f01d2d0aa:/lib/queue.c diff --git a/lib/queue.c b/lib/queue.c index c7d32a4..466fe7b 100644 --- a/lib/queue.c +++ b/lib/queue.c @@ -24,27 +24,15 @@ #include #include #include -#include -#include #include -#include -#include -#include #include "mem.h" #include "queue.h" #include "log.h" -#include "configuration.h" #include "split.h" #include "syscalls.h" -#include "charset.h" #include "table.h" -#include "inputline.h" #include "printf.h" -#include "plugin.h" -#include "basen.h" -#include "eventlog.h" -#include "disorder.h" const char *playing_states[] = { "failed", @@ -59,29 +47,6 @@ const char *playing_states[] = { "unplayed" }; -/* the head of the queue is played next, so normally we add to the tail */ -struct queue_entry qhead = { &qhead, &qhead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -/* the head of the recent list is the oldest thing, the tail the most recently - * played */ -struct queue_entry phead = { &phead, &phead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -static long pcount; - -/* add new entry @n@ to a doubly linked list just after @b@ */ -static void l_add(struct queue_entry *b, struct queue_entry *n) { - n->prev = b; - n->next = b->next; - n->next->prev = n; - n->prev->next = n; -} - -/* remove an entry from a doubly-linked list */ -static void l_remove(struct queue_entry *node) { - node->next->prev = node->prev; - node->prev->next = node->next; -} - #define VALUE(q, offset, type) *(type *)((char *)q + offset) static int unmarshall_long(char *data, struct queue_entry *q, @@ -224,30 +189,6 @@ int queue_unmarshall_vec(struct queue_entry *q, int nvec, char **vec, return 0; } -void queue_fix_sofar(struct queue_entry *q) { - long sofar; - - /* Fake up SOFAR field for currently-playing tracks that don't have it filled - * in by the speaker process. XXX this horrible bodge should go away when we - * have a more general implementation of pausing as that field will always - * have to be right for the playing track. */ - if((q->state == playing_started - || q->state == playing_paused) - && q->type & DISORDER_PLAYER_PAUSES - && (q->type & DISORDER_PLAYER_TYPEMASK) != DISORDER_PLAYER_RAW) { - if(q->lastpaused) { - if(q->uptopause == -1) /* Don't know how far thru. */ - sofar = -1; - else if(q->lastresumed) /* Has been paused and resumed. */ - sofar = q->uptopause + time(0) - q->lastresumed; - else /* Currently paused. */ - sofar = q->uptopause; - } else /* Never been paused. */ - sofar = time(0) - q->played; - q->sofar = sofar; - } -} - char *queue_marshall(const struct queue_entry *q) { unsigned n; const char *vec[sizeof fields / sizeof *fields], *v; @@ -271,237 +212,6 @@ char *queue_marshall(const struct queue_entry *q) { return r; } -static void queue_read_error(const char *msg, - void *u) { - fatal(0, "error parsing queue %s: %s", (const char *)u, msg); -} - -static void queue_do_read(struct queue_entry *head, const char *path) { - char *buffer; - FILE *fp; - struct queue_entry *q; - - if(!(fp = fopen(path, "r"))) { - if(errno == ENOENT) - return; /* no queue */ - fatal(errno, "error opening %s", path); - } - head->next = head->prev = head; - while(!inputline(path, fp, &buffer, '\n')) { - q = xmalloc(sizeof *q); - queue_unmarshall(q, buffer, queue_read_error, (void *)path); - if(head == &qhead - && (!q->track - || !q->when)) - fatal(0, "incomplete queue entry in %s", path); - l_add(head->prev, q); - } - if(ferror(fp)) fatal(errno, "error reading %s", path); - fclose(fp); -} - -void queue_read(void) { - queue_do_read(&qhead, config_get_file("queue")); -} - -void recent_read(void) { - struct queue_entry *q; - - queue_do_read(&phead, config_get_file("recent")); - /* reset pcount after loading */ - pcount = 0; - q = phead.next; - while(q != &phead) { - ++pcount; - q = q->next; - } -} - -static void queue_do_write(const struct queue_entry *head, const char *path) { - char *tmp; - FILE *fp; - struct queue_entry *q; - - byte_xasprintf(&tmp, "%s.new", path); - if(!(fp = fopen(tmp, "w"))) fatal(errno, "error opening %s", tmp); - for(q = head->next; q != head; q = q->next) - if(fprintf(fp, "%s\n", queue_marshall(q)) < 0) - fatal(errno, "error writing %s", tmp); - if(fclose(fp) < 0) fatal(errno, "error closing %s", tmp); - if(rename(tmp, path) < 0) fatal(errno, "error replacing %s", path); -} - -void queue_write(void) { - queue_do_write(&qhead, config_get_file("queue")); -} - -void recent_write(void) { - queue_do_write(&phead, config_get_file("recent")); -} - -void queue_id(struct queue_entry *q) { - static unsigned long serial; - unsigned long a[3]; - char buffer[128]; - - a[0] = serial++ & 0xFFFFFFFFUL; - a[1] = time(0) & 0xFFFFFFFFUL; - a[2] = getpid() & 0xFFFFFFFFUL; - basen(a, 3, buffer, sizeof buffer, 62); - q->id = xstrdup(buffer); -} - -struct queue_entry *queue_add(const char *track, const char *submitter, - int where) { - struct queue_entry *q; - - q = xmalloc(sizeof *q); - q->track = xstrdup(track); - q->submitter = submitter ? xstrdup(submitter) : 0; - q->state = playing_unplayed; - queue_id(q); - time(&q->when); - switch(where) { - case WHERE_START: - l_add(&qhead, q); - break; - case WHERE_END: - l_add(qhead.prev, q); - break; - case WHERE_BEFORE_RANDOM: - if(qhead.prev == &qhead /* Empty queue. */ - || qhead.prev->state != playing_random) /* No random track */ - l_add(qhead.prev, q); - else - l_add(qhead.prev->prev, q); /* Before random track. */ - break; - } - /* submitter will be a null pointer for a scratch */ - if(submitter) - notify_queue(track, submitter); - eventlog_raw("queue", queue_marshall(q), (const char *)0); - return q; -} - -int queue_move(struct queue_entry *q, int delta, const char *who) { - int moved = 0; - char buffer[20]; - - /* not the most efficient approach but hopefuly relatively comprehensible: - * the idea is that for each step we determine which nodes are affected, and - * fill in all the links starting at the 'prev' end and moving towards the - * 'next' end. */ - - while(delta > 0 && q->prev != &qhead) { - struct queue_entry *n, *p, *pp; - - n = q->next; - p = q->prev; - pp = p->prev; - pp->next = q; - q->prev = pp; - q->next = p; - p->prev = q; - p->next = n; - n->prev = p; - --delta; - ++moved; - } - - while(delta < 0 && q->next != &qhead) { - struct queue_entry *n, *p, *nn; - - p = q->prev; - n = q->next; - nn = n->next; - p->next = n; - n->prev = p; - n->next = q; - q->prev = n; - q->next = nn; - nn->prev = q; - ++delta; - --moved; - } - - if(moved) { - info("user %s moved %s", who, q->id); - notify_queue_move(q->track, who); - sprintf(buffer, "%d", moved); - eventlog("moved", who, (char *)0); - } - - return delta; -} - -static int find_in_list(struct queue_entry *needle, - int nqs, struct queue_entry **qs) { - int n; - - for(n = 0; n < nqs; ++n) - if(qs[n] == needle) - return 1; - return 0; -} - -void queue_moveafter(struct queue_entry *target, - int nqs, struct queue_entry **qs, - const char *who) { - struct queue_entry *q; - int n; - - /* Normalize */ - if(!target) - target = &qhead; - else - while(find_in_list(target, nqs, qs)) - target = target->prev; - /* Do the move */ - for(n = 0; n < nqs; ++n) { - q = qs[n]; - l_remove(q); - l_add(target, q); - target = q; - /* Log the individual tracks */ - info("user %s moved %s", who, q->id); - notify_queue_move(q->track, who); - } - /* Report that the queue changed to the event log */ - eventlog("moved", who, (char *)0); -} - -void queue_remove(struct queue_entry *which, const char *who) { - if(who) { - info("user %s removed %s", who, which->id); - notify_queue_move(which->track, who); - } - eventlog("removed", which->id, who, (const char *)0); - l_remove(which); -} - -struct queue_entry *queue_find(const char *key) { - struct queue_entry *q; - - for(q = qhead.next; - q != &qhead && strcmp(q->track, key) && strcmp(q->id, key); - q = q->next) - ; - return q != &qhead ? q : 0; -} - -void queue_played(struct queue_entry *q) { - while(pcount && pcount >= config->history) { - eventlog("recent_removed", phead.next->id, (char *)0); - l_remove(phead.next); - pcount--; - } - if(config->history) { - eventlog_raw("recent_added", queue_marshall(q), (char *)0); - l_add(phead.prev, q); - ++pcount; - } -} - /* Local Variables: c-basic-offset:2 @@ -509,4 +219,3 @@ comment-column:40 fill-column:79 End: */ -/* arch-tag:62474dd3e75e5483b61b6befe2c523cc */