Replace manual option handling by use of glib
[lcid-xwax.git] / library.c
blobd64e96ed14cad84302d5a2b1a67e1966b820a811
1 /*
2 * Copyright (C) 2008 Mark Hills <mark@pogo.org.uk>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License version 2 for more details.
13 * You should have received a copy of the GNU General Public License
14 * version 2 along with this program; if not, write to the Free
15 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 * MA 02110-1301, USA.
20 #include <ctype.h>
21 #include <dirent.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
29 #include "library.h"
30 #include "record.h"
33 #define BLOCK 256 // number of library entries
35 #define MIN(a, b) (a<b?a:b)
38 static int strmatch(char *little, char *big)
40 size_t n, m, match, little_len;
42 little_len = strlen(little);
44 for(n = 0; n + little_len <= strlen(big); n++) {
46 match = 1;
48 for(m = 0; m < little_len; m++) {
49 if(tolower(little[m]) != tolower(big[n + m])) {
50 match = 0;
51 break;
55 if(match)
56 return 1;
59 return 0;
62 /* Copy src (ms characters) to dest (length md, including '\0'), and
63 * ensure the result is safe and null terminated */
66 static int strmcpy(char *dest, int md, char *src, int ms)
68 strncpy(dest, src, MIN(ms, md));
69 if(ms < md)
70 dest[ms] = '\0';
71 else
72 dest[md - 1] = '\0';
74 return 0;
78 static struct record_t* extract_info(const char* pathname, char *filename)
80 char *c, *mi, *dt, *end;
82 c = filename;
83 end = filename;
85 while(*c != '\0') {
86 end = c;
87 c++;
90 end++;
92 c = filename;
93 mi = end;
95 while(c < end - 3) {
96 if(c[0] == ' ' && (c[1] == '-' || c[1] == '_') && c[2] == ' ') {
97 mi = c;
98 break;
101 c++;
104 dt = strrchr(filename, '.');
106 struct record_t *lr = NULL;
108 char* artist = filename;
110 if(mi == end) {
111 lr = record_init(pathname, artist, "", NULL);
112 } else {
113 *mi = '\0';
115 if(dt)
116 *dt = '\0';
118 char* title = mi + 3;
120 lr = record_init(pathname, artist, title, NULL);
123 return lr;
126 void library_init(struct library_t *li)
128 li->records = g_ptr_array_new();
131 void clear_record(gpointer data, gpointer user_data)
133 record_destroy(data);
136 void library_clear(struct library_t *li)
138 g_ptr_array_foreach(li->records, clear_record, NULL);
140 g_ptr_array_free(li->records, FALSE);
144 void library_add(struct library_t *li, struct record_t *lr)
146 g_ptr_array_add(li->records, lr);
149 int library_import(struct library_t *li, char *path)
151 DIR *dir;
152 struct dirent *de;
153 struct record_t* record = NULL;
154 struct stat st;
156 fprintf(stderr, "Scanning directory '%s'...\n", path);
158 dir = opendir(path);
159 if(!dir) {
160 fprintf(stderr, "Failed to scan; aborting.\n");
161 return -1;
164 while((de = readdir(dir)) != NULL) {
166 if(de->d_name[0] == '.') // hidden or '.' or '..'
167 continue;
169 char* pathname = g_newa(char, strlen(path) + 1 + strlen(de->d_name) + 1);
170 sprintf(pathname, "%s%c%s", path, G_DIR_SEPARATOR, de->d_name);
172 if(stat(pathname, &st) == -1) {
173 perror("stat");
174 continue;
177 // If the entry is a directory, recursively import the contents
178 // of the directory. Otherwise, assume a file.
180 if(S_ISDIR(st.st_mode)) {
181 library_import(li, pathname);
183 } else {
184 record = extract_info(pathname, de->d_name);
185 library_add(li, record);
189 closedir(dir);
191 return 0;
194 unsigned int library_get_count(struct library_t* li)
196 return li->records->len;
199 struct record_t* library_get_record(struct library_t* li, const guint index)
201 return g_ptr_array_index(li->records, index);
204 void library_get_listing(struct library_t *li, struct listing_t *ls)
206 int n;
208 for(n = 0; n < library_get_count(li); n++)
209 listing_add(ls, library_get_record(li, n));
213 void listing_init(struct listing_t *ls)
215 ls->records = g_ptr_array_new();
219 void listing_clear(struct listing_t *ls)
221 g_ptr_array_free(ls->records, FALSE);
225 void listing_blank(struct listing_t *ls)
227 if(ls->records->len != 0)
228 g_ptr_array_remove_range(ls->records, 0, listing_get_count(ls) - 1);
231 size_t listing_get_count(const struct listing_t* ls)
233 return ls->records->len;
236 guint listing_get_field_size(const struct listing_t* ls, const unsigned int index)
238 return 200;
241 void listing_add(struct listing_t *ls, struct record_t *lr)
243 g_ptr_array_add(ls->records, lr);
246 struct record_t* listing_get_record(const struct listing_t* ls, guint index)
248 return g_ptr_array_index(ls->records, index);
251 gint compare_records(gconstpointer a, gconstpointer b)
253 return strcmp(record_get_name(a), record_get_name(b));
256 void listing_sort(struct listing_t *ls)
258 g_ptr_array_sort(ls->records, compare_records);
261 int listing_match(struct listing_t *src, struct listing_t *dest, char *match)
263 int n;
264 struct record_t *re;
266 fprintf(stderr, "Matching '%s'\n", match);
268 for(n = 0; n < listing_get_count(src); n++) {
269 re = listing_get_record(src, n);
271 if(strmatch(match, record_get_name(re)))
272 listing_add(dest, re);
275 return 0;
278 void listing_debug(struct listing_t *ls)
280 int n;
282 struct record_t* record = NULL;
284 for(n = 0; (record = listing_get_record(ls, n)); n++)
286 fprintf(stderr, "%d: %s\n", n, record_get_name(record));