Replace manual option handling by use of glib
[lcid-xwax.git] / track_cache.c
blob9855c6945af03304ef5d8a5250a2d6d1ffa81634
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <glib/gstdio.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include <string.h>
11 #include "include.h"
12 #include "track.h"
13 #include "track_cache.h"
15 static const char* cache_directory = NULL;
16 static const char cache_file_temp_ending[] = ".temp";
17 #define DEFAULT_CACHE_DIRECTORY "~/.cache/xwax/track"
19 void track_cache_log(const char* format, ...)
21 gchar* wholeMessage = g_strconcat("Track cache: ", format, "\n", NULL);
23 va_list ap;
24 va_start(ap, format);
26 g_vfprintf(stderr, wholeMessage, ap);
28 va_end(ap);
29 g_free(wholeMessage);
32 void track_cache_set_directory(const char* directory)
34 cache_directory = directory;
36 track_cache_log("Set cache directory to \'%s\'", cache_directory);
39 static gboolean parse_cache(GOptionContext *context, GOptionGroup *group, gpointer data, GError **error)
41 if(isempty(data))
42 track_cache_set_directory(DEFAULT_CACHE_DIRECTORY);
44 track_cache_set_directory(data);
45 return TRUE;
48 static GOptionEntry cacheOptions[] =
50 { "cache", 'c', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, &parse_cache, "Directory to cache decoded audio files", DEFAULT_CACHE_DIRECTORY},
51 { NULL }
54 GOptionGroup* get_cache_option_group()
56 GOptionGroup* group = g_option_group_new
58 "cache",
59 "Cache control options",
60 "Show cache control help options",
61 NULL,
62 NULL
64 g_option_group_add_entries(group, cacheOptions);
65 return group;
68 gboolean track_cache_is_enabled()
70 return !isempty(cache_directory);
73 const char* track_cache_get_directory()
75 return cache_directory;
78 struct cached_track
80 gchar* path;
81 gchar* id;
84 struct cache_read
86 int fd;
87 FILE* file;
90 const char* cached_track_get_id(const cached_track* cache)
92 return cache->id;
95 void cached_track_set_id(const char* path, cached_track* cache)
97 gchar* localPath = g_strdup(path);
98 char* args[] = {"./xwax_hash", "get", localPath, NULL };
99 gint status = 0;
100 GError* error = NULL;
101 gchar* stdout = NULL;
102 gchar* stderr = NULL;
104 gboolean success = g_spawn_sync
106 NULL, //working_directory
107 args,
108 NULL, //envp
109 G_SPAWN_SEARCH_PATH | G_SPAWN_FILE_AND_ARGV_ZERO, //flags
110 NULL,
111 NULL,
112 &stdout,
113 &stderr,
114 &status,
115 &error
118 g_free(localPath);
120 if(success && status == 0)
122 cache->id = stdout;
123 track_cache_log("Successfull retrieved id %s", stdout);
125 else
127 track_cache_log("Could not retrieve id of file %s", path);
128 cache->id = NULL;
132 cached_track* cached_track_init(const char* path)
134 if(!track_cache_is_enabled())
135 return NULL;
137 cached_track* cache = g_new(cached_track, 1);
138 cached_track_set_id(path, cache);
140 //could not get id
141 if(isempty(cached_track_get_id(cache)))
142 return NULL;
144 cache->path = g_build_filename(track_cache_get_directory(), cached_track_get_id(cache), NULL);
146 return cache;
149 int cached_track_file_open(const cached_track* cache, int flags, int perm)
151 return g_open(cache->path, flags, perm);
154 int cached_track_file_open_read(const cached_track* cache)
156 return cached_track_file_open(cache, O_RDONLY | O_NONBLOCK /*| O_SEQUENTIAL | O_BINARY*/, S_IRUSR);
159 gchar* cached_track_file_get_temp_name(const cached_track* cache)
161 return g_strconcat(cache->path, cache_file_temp_ending, NULL);
164 int cached_track_file_open_write(const cached_track* cache)
166 gchar* tempFile = cached_track_file_get_temp_name(cache);
167 int fd = g_open(tempFile, O_WRONLY | O_APPEND | O_NONBLOCK /*| O_BINARY */ | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
168 g_free(tempFile);
169 return fd;
172 void cached_track_file_close(const int fd)
174 close(fd);
177 void cached_track_file_write_close(const cached_track* cache, const int fd)
179 cached_track_file_close(fd);
180 g_rename(cached_track_file_get_temp_name(cache), cache->path);
183 cache_read* cache_read_init(const cached_track* cache)
185 cache_read* read = g_new(cache_read, 1);
186 read->fd = cached_track_file_open_read(cache);
188 if(read->fd == -1)
190 switch(errno)
192 case EACCES:
193 fprintf(stderr, "EACCES\n");
194 break;
195 case EEXIST:
196 fprintf(stderr, "EEXIST\n");
197 break;
198 case EFAULT:
199 fprintf(stderr, "EFAULT\n");
200 break;
201 case EISDIR:
202 fprintf(stderr, "EISDIR\n");
203 break;
204 case ELOOP:
205 fprintf(stderr, "ELOOP\n");
206 break;
207 case EMFILE:
208 fprintf(stderr, "EMFILE\n");
209 break;
210 case ENAMETOOLONG:
211 fprintf(stderr, "ENAMETOOLONG\n");
212 break;
213 case ENFILE:
214 fprintf(stderr, "ENFILE\n");
215 break;
216 case ENODEV:
217 fprintf(stderr, "ENODEV\n");
218 break;
219 case ENOENT:
220 fprintf(stderr, "ENOENT\n");
221 break;
222 case ENOMEM:
223 fprintf(stderr, "ENOMEM\n");
224 break;
225 case ENOSPC:
226 fprintf(stderr, "ENOSPC\n");
227 break;
228 case ENOTDIR:
229 fprintf(stderr, "ENOTDIR\n");
230 break;
231 case ENXIO:
232 fprintf(stderr, "ENXIO\n");
233 break;
234 case EOVERFLOW:
235 fprintf(stderr, "EOVERFLOW\n");
236 break;
237 case EPERM:
238 fprintf(stderr, "EPERM\n");
239 break;
240 case EROFS:
241 fprintf(stderr, "EROFS\n");
242 break;
243 case ETXTBSY:
244 fprintf(stderr, "ETXTBSY\n");
245 break;
246 case EWOULDBLOCK:
247 fprintf(stderr, "EWOULDBLOCK\n");
248 break;
251 g_free(read);
252 return NULL;
255 read->file = fdopen(read->fd, "r");
257 track_cache_log("Found in cache");
259 return read;
262 gboolean cached_track_file_exists(const cached_track* cache)
264 return g_file_test(cache->path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR);
267 cache_read* cached_track_read(const cached_track* cache)
269 if(!track_cache_is_enabled())
270 return NULL;
272 if(!cache)
273 return NULL;
275 if(!cached_track_file_exists(cache))
276 return NULL;
278 return cache_read_init(cache);
281 void cached_track_write(const cached_track* cache, const struct track_t *tr)
283 if(!track_cache_is_enabled())
284 return;
286 if(!cache)
287 return;
289 if(cached_track_file_exists(cache))
290 return;
292 int fd = cached_track_file_open_write(cache);
294 if(fd < 0)
295 return; //TODO: messup here
297 FILE* fp = fdopen(fd, "wa");
299 long bytesLeft = tr->bytes;
301 struct track_block_t* block = NULL;
302 unsigned int byteUse;
304 //ATTENTION:
305 //Do not rely on tr->blocks here because it
306 //does only reflect the overall track memory allocation
307 for(guint index = 0; /*index < tr->block->len &&*/ bytesLeft > 0; index++)
309 block = track_get_block(tr, index);
311 byteUse = track_block_get_used_bytes(tr, index);
313 for(guint pcmIndex = 0; pcmIndex < byteUse / TRACK_PCM_DATA_SIZE; pcmIndex++)
315 fwrite(&block->pcm[pcmIndex], 1 , TRACK_PCM_DATA_SIZE, fp);
318 bytesLeft -= byteUse;
321 fflush(fp);
323 cached_track_file_write_close(cache, fd);
326 void cached_track_destroy(cached_track* cache)
328 if(!cache)
329 return;
331 g_free(cache->path);
332 g_free(cache->id);
333 g_free(cache);
336 int cache_read_get_fd(const cache_read* read)
338 return read->fd;
341 int cache_read_block(cache_read* read, signed short* pcm, guint pcmCount)
343 return fread(pcm, TRACK_PCM_DATA_SIZE, pcmCount, read->file) * TRACK_PCM_DATA_SIZE;
346 void cache_read_destroy(cache_read* read)
348 if(!read)
349 return;
351 cached_track_file_close(read->fd);
352 g_free(read);