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.
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,
27 #include <sys/types.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
++) {
48 for(m
= 0; m
< little_len
; m
++) {
49 if(tolower(little
[m
]) != tolower(big
[n
+ m
])) {
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));
78 static struct record_t
* extract_info(const char* pathname
, char *filename
)
80 char *c
, *mi
, *dt
, *end
;
96 if(c
[0] == ' ' && (c
[1] == '-' || c
[1] == '_') && c
[2] == ' ') {
104 dt
= strrchr(filename
, '.');
106 struct record_t
*lr
= NULL
;
108 char* artist
= filename
;
111 lr
= record_init(pathname
, artist
, "", NULL
);
118 char* title
= mi
+ 3;
120 lr
= record_init(pathname
, artist
, title
, NULL
);
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
)
153 struct record_t
* record
= NULL
;
156 fprintf(stderr
, "Scanning directory '%s'...\n", path
);
160 fprintf(stderr
, "Failed to scan; aborting.\n");
164 while((de
= readdir(dir
)) != NULL
) {
166 if(de
->d_name
[0] == '.') // hidden or '.' or '..'
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) {
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
);
184 record
= extract_info(pathname
, de
->d_name
);
185 library_add(li
, record
);
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
)
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
)
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
)
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
);
278 void listing_debug(struct listing_t
*ls
)
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
));