460b9539 |
1 | /* |
2 | * This file is part of DisOrder. |
3 | * Copyright (C) 2004, 2005, 2006 Richard Kettlewell |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, but |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
18 | * USA |
19 | */ |
20 | |
21 | #include <config.h> |
22 | #include "types.h" |
23 | |
24 | #include <string.h> |
25 | #include <stdio.h> |
26 | #include <errno.h> |
460b9539 |
27 | #include <stddef.h> |
460b9539 |
28 | |
29 | #include "mem.h" |
30 | #include "queue.h" |
31 | #include "log.h" |
460b9539 |
32 | #include "split.h" |
33 | #include "syscalls.h" |
460b9539 |
34 | #include "table.h" |
460b9539 |
35 | #include "printf.h" |
460b9539 |
36 | |
37 | const char *playing_states[] = { |
38 | "failed", |
39 | "isscratch", |
40 | "no_player", |
41 | "ok", |
42 | "paused", |
43 | "quitting", |
44 | "random", |
45 | "scratched", |
46 | "started", |
47 | "unplayed" |
48 | }; |
49 | |
460b9539 |
50 | #define VALUE(q, offset, type) *(type *)((char *)q + offset) |
51 | |
52 | static int unmarshall_long(char *data, struct queue_entry *q, |
53 | size_t offset, |
54 | void (*error_handler)(const char *, void *), |
55 | void *u) { |
56 | if(xstrtol(&VALUE(q, offset, long), data, 0, 0)) { |
57 | error_handler(strerror(errno), u); |
58 | return -1; |
59 | } |
60 | return 0; |
61 | } |
62 | |
63 | static const char *marshall_long(const struct queue_entry *q, size_t offset) { |
64 | char buffer[256]; |
65 | int n; |
66 | |
67 | n = byte_snprintf(buffer, sizeof buffer, "%ld", VALUE(q, offset, long)); |
68 | if(n < 0) |
69 | fatal(errno, "error converting int"); |
70 | else if((size_t)n >= sizeof buffer) |
71 | fatal(0, "long converted to decimal is too long"); |
72 | return xstrdup(buffer); |
73 | } |
74 | |
75 | static int unmarshall_string(char *data, struct queue_entry *q, |
76 | size_t offset, |
77 | void attribute((unused)) (*error_handler)(const char *, void *), |
78 | void attribute((unused)) *u) { |
79 | VALUE(q, offset, char *) = data; |
80 | return 0; |
81 | } |
82 | |
83 | static const char *marshall_string(const struct queue_entry *q, size_t offset) { |
84 | return VALUE(q, offset, char *); |
85 | } |
86 | |
87 | static int unmarshall_time_t(char *data, struct queue_entry *q, |
88 | size_t offset, |
89 | void (*error_handler)(const char *, void *), |
90 | void *u) { |
91 | long_long ul; |
92 | |
93 | if(xstrtoll(&ul, data, 0, 0)) { |
94 | error_handler(strerror(errno), u); |
95 | return -1; |
96 | } |
97 | VALUE(q, offset, time_t) = ul; |
98 | return 0; |
99 | } |
100 | |
101 | static const char *marshall_time_t(const struct queue_entry *q, size_t offset) { |
102 | char buffer[256]; |
103 | int n; |
104 | |
105 | n = byte_snprintf(buffer, sizeof buffer, |
106 | "%"PRIdMAX, (intmax_t)VALUE(q, offset, time_t)); |
107 | if(n < 0) |
108 | fatal(errno, "error converting time"); |
109 | else if((size_t)n >= sizeof buffer) |
110 | fatal(0, "time converted to decimal is too long"); |
111 | return xstrdup(buffer); |
112 | } |
113 | |
114 | static int unmarshall_state(char *data, struct queue_entry *q, |
115 | size_t offset, |
116 | void (*error_handler)(const char *, void *), |
117 | void *u) { |
118 | int n; |
119 | |
120 | if((n = table_find(playing_states, 0, sizeof (char *), |
121 | sizeof playing_states / sizeof *playing_states, |
122 | data)) < 0) { |
123 | D(("state=[%s] n=%d", data, n)); |
124 | error_handler("invalid state", u); |
125 | return -1; |
126 | } |
127 | VALUE(q, offset, enum playing_state) = n; |
128 | return 0; |
129 | } |
130 | |
131 | static const char *marshall_state(const struct queue_entry *q, size_t offset) { |
132 | return playing_states[VALUE(q, offset, enum playing_state)]; |
133 | } |
134 | |
135 | #define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h } |
136 | |
137 | static const struct field { |
138 | const char *name; |
139 | size_t offset; |
140 | const char *(*marshall)(const struct queue_entry *q, size_t offset); |
141 | int (*unmarshall)(char *data, struct queue_entry *q, size_t offset, |
142 | void (*error_handler)(const char *, void *), |
143 | void *u); |
144 | } fields[] = { |
145 | /* Keep this table sorted. */ |
146 | F(expected, time_t), |
147 | F(id, string), |
148 | F(played, time_t), |
149 | F(scratched, string), |
150 | F(sofar, long), |
151 | F(state, state), |
152 | F(submitter, string), |
153 | F(track, string), |
154 | F(when, time_t), |
155 | F(wstat, long) |
156 | }; |
157 | |
158 | int queue_unmarshall(struct queue_entry *q, const char *s, |
159 | void (*error_handler)(const char *, void *), |
160 | void *u) { |
161 | char **vec; |
162 | int nvec; |
163 | |
164 | if(!(vec = split(s, &nvec, SPLIT_QUOTES, error_handler, u))) |
165 | return -1; |
166 | return queue_unmarshall_vec(q, nvec, vec, error_handler, u); |
167 | } |
168 | |
169 | int queue_unmarshall_vec(struct queue_entry *q, int nvec, char **vec, |
170 | void (*error_handler)(const char *, void *), |
171 | void *u) { |
172 | int n; |
173 | |
174 | if(nvec % 2 != 0) { |
175 | error_handler("invalid marshalled queue format", u); |
176 | return -1; |
177 | } |
178 | while(*vec) { |
179 | D(("key %s value %s", vec[0], vec[1])); |
180 | if((n = TABLE_FIND(fields, struct field, name, *vec)) < 0) { |
181 | error_handler("unknown key in queue data", u); |
182 | return -1; |
183 | } else { |
184 | if(fields[n].unmarshall(vec[1], q, fields[n].offset, error_handler, u)) |
185 | return -1; |
186 | } |
187 | vec += 2; |
188 | } |
189 | return 0; |
190 | } |
191 | |
460b9539 |
192 | char *queue_marshall(const struct queue_entry *q) { |
193 | unsigned n; |
194 | const char *vec[sizeof fields / sizeof *fields], *v; |
195 | char *r, *s; |
196 | size_t len = 1; |
197 | |
198 | for(n = 0; n < sizeof fields / sizeof *fields; ++n) |
199 | if((v = fields[n].marshall(q, fields[n].offset))) { |
200 | vec[n] = quoteutf8(v); |
201 | len += strlen(vec[n]) + strlen(fields[n].name) + 2; |
202 | } else |
203 | vec[n] = 0; |
204 | s = r = xmalloc_noptr(len); |
205 | for(n = 0; n < sizeof fields / sizeof *fields; ++n) |
206 | if(vec[n]) { |
207 | *s++ = ' '; |
208 | s += strlen(strcpy(s, fields[n].name)); |
209 | *s++ = ' '; |
210 | s += strlen(strcpy(s, vec[n])); |
211 | } |
212 | return r; |
213 | } |
214 | |
460b9539 |
215 | /* |
216 | Local Variables: |
217 | c-basic-offset:2 |
218 | comment-column:40 |
219 | fill-column:79 |
220 | End: |
221 | */ |