X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/05b75f8d50b83e943af3be4071449304d82dbdcd..16b0fea8ae1a581d568dbee2efa2932aa4e6fcce:/lib/queue.c diff --git a/lib/queue.c b/lib/queue.c index 0849070..c592f5a 100644 --- a/lib/queue.c +++ b/lib/queue.c @@ -1,23 +1,23 @@ /* * This file is part of DisOrder. - * Copyright (C) 2004-2008 Richard Kettlewell + * Copyright (C) 2004-2009, 2011, 2013 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. If not, see . + */ +/** @file lib/queue.c + * @brief Track queues */ - #include "common.h" #include @@ -30,8 +30,9 @@ #include "syscalls.h" #include "table.h" #include "printf.h" +#include "vector.h" -const char *playing_states[] = { +const char *const playing_states[] = { "failed", "isscratch", "no_player", @@ -44,9 +45,21 @@ const char *playing_states[] = { "unplayed" }; +/** @brief String values for @c origin field */ +const char *const track_origins[] = { + "adopted", + "picked", + "random", + "scheduled", + "scratch", +}; + #define VALUE(q, offset, type) *(type *)((char *)q + offset) -/* add new entry @n@ to a doubly linked list just after @b@ */ +/** @brief Insert queue entry @p n just after @p b + * @param b Insert after this entry + * @param n New entry to insert + */ void queue_insert_entry(struct queue_entry *b, struct queue_entry *n) { n->prev = b; n->next = b->next; @@ -64,8 +77,9 @@ static int unmarshall_long(char *data, struct queue_entry *q, size_t offset, void (*error_handler)(const char *, void *), void *u) { + char errbuf[1024]; if(xstrtol(&VALUE(q, offset, long), data, 0, 0)) { - error_handler(strerror(errno), u); + error_handler(format_error(ec_errno, errno, errbuf, sizeof errbuf), u); return -1; } return 0; @@ -77,17 +91,23 @@ static const char *marshall_long(const struct queue_entry *q, size_t offset) { n = byte_snprintf(buffer, sizeof buffer, "%ld", VALUE(q, offset, long)); if(n < 0) - fatal(errno, "error converting int"); + disorder_fatal(errno, "error converting int"); else if((size_t)n >= sizeof buffer) - fatal(0, "long converted to decimal is too long"); + disorder_fatal(0, "long converted to decimal is too long"); return xstrdup(buffer); } +static void free_none(struct queue_entry attribute((unused)) *q, + size_t attribute((unused)) offset) { +} + +#define free_long free_none + static int unmarshall_string(char *data, struct queue_entry *q, size_t offset, void attribute((unused)) (*error_handler)(const char *, void *), void attribute((unused)) *u) { - VALUE(q, offset, char *) = data; + VALUE(q, offset, char *) = xstrdup(data); return 0; } @@ -95,14 +115,19 @@ static const char *marshall_string(const struct queue_entry *q, size_t offset) { return VALUE(q, offset, char *); } +static void free_string(struct queue_entry *q, size_t offset) { + xfree(VALUE(q, offset, char *)); +} + static int unmarshall_time_t(char *data, struct queue_entry *q, size_t offset, void (*error_handler)(const char *, void *), void *u) { long_long ul; + char errbuf[1024]; if(xstrtoll(&ul, data, 0, 0)) { - error_handler(strerror(errno), u); + error_handler(format_error(ec_errno, errno, errbuf, sizeof errbuf), u); return -1; } VALUE(q, offset, time_t) = ul; @@ -116,12 +141,14 @@ static const char *marshall_time_t(const struct queue_entry *q, size_t offset) { n = byte_snprintf(buffer, sizeof buffer, "%"PRIdMAX, (intmax_t)VALUE(q, offset, time_t)); if(n < 0) - fatal(errno, "error converting time"); + disorder_fatal(errno, "error converting time"); else if((size_t)n >= sizeof buffer) - fatal(0, "time converted to decimal is too long"); + disorder_fatal(0, "time converted to decimal is too long"); return xstrdup(buffer); } +#define free_time_t free_none + static int unmarshall_state(char *data, struct queue_entry *q, size_t offset, void (*error_handler)(const char *, void *), @@ -139,23 +166,59 @@ static int unmarshall_state(char *data, struct queue_entry *q, return 0; } +static int unmarshall_origin(char *data, struct queue_entry *q, + size_t offset, + void (*error_handler)(const char *, void *), + void *u) { + int n; + + if((n = table_find(track_origins, 0, sizeof (char *), + sizeof track_origins / sizeof *track_origins, + data)) < 0) { + D(("origin=[%s] n=%d", data, n)); + error_handler("invalid origin", u); + return -1; + } + VALUE(q, offset, enum track_origin) = n; + return 0; +} + static const char *marshall_state(const struct queue_entry *q, size_t offset) { return playing_states[VALUE(q, offset, enum playing_state)]; } -#define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h } +static const char *marshall_origin(const struct queue_entry *q, size_t offset) { + return track_origins[VALUE(q, offset, enum track_origin)]; +} + +#define free_state free_none +#define free_origin free_none -static const struct field { +#define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h, free_##h } + +/** @brief A field in a @ref queue_entry */ +static const struct queue_field { + /** @brief Field name */ const char *name; + + /** @brief Offset of value in @ref queue_entry structure */ size_t offset; + + /** @brief Marshaling function */ const char *(*marshall)(const struct queue_entry *q, size_t offset); + + /** @brief Unmarshaling function */ int (*unmarshall)(char *data, struct queue_entry *q, size_t offset, void (*error_handler)(const char *, void *), void *u); + + /** @brief Destructor */ + void (*free)(struct queue_entry *q, size_t offset); } fields[] = { /* Keep this table sorted. */ F(expected, time_t), F(id, string), + F(origin, origin), F(played, time_t), F(scratched, string), F(sofar, long), @@ -165,16 +228,20 @@ static const struct field { F(when, time_t), F(wstat, long) }; +#define NFIELDS (sizeof fields / sizeof *fields) int queue_unmarshall(struct queue_entry *q, const char *s, void (*error_handler)(const char *, void *), void *u) { char **vec; - int nvec; + int nvec, rc; + q->pid = -1; /* =none */ if(!(vec = split(s, &nvec, SPLIT_QUOTES, error_handler, u))) return -1; - return queue_unmarshall_vec(q, nvec, vec, error_handler, u); + rc = queue_unmarshall_vec(q, nvec, vec, error_handler, u); + free_strings(nvec, vec); + return rc; } int queue_unmarshall_vec(struct queue_entry *q, int nvec, char **vec, @@ -223,6 +290,17 @@ char *queue_marshall(const struct queue_entry *q) { return r; } +void queue_free(struct queue_entry *q, int rest) { + unsigned n; + if(!q) + return; + if(rest) + queue_free(q->next, rest); + for(n = 0; n < NFIELDS; ++n) + fields[n].free(q, fields[n].offset); + xfree(q); +} + /* Local Variables: c-basic-offset:2