directory.c 4.06 KB
Newer Older
1 2 3
/*
 * Copyright (C) 2003-2009 The Music Player Daemon Project
 * http://www.musicpd.org
Warren Dukes's avatar
Warren Dukes committed
4 5 6 7 8 9 10 11 12 13
 *
 * 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
 * (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.
14 15 16 17
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Warren Dukes's avatar
Warren Dukes committed
18 19 20
 */

#include "directory.h"
21
#include "song.h"
22
#include "path.h"
23

24 25
#include <glib.h>

26 27
#include <assert.h>
#include <string.h>
28
#include <stdlib.h>
29

30
struct directory *
31
directory_new(const char *path, struct directory *parent)
Avuton Olrich's avatar
Avuton Olrich committed
32
{
33
	struct directory *directory;
34
	size_t pathlen = strlen(path);
Warren Dukes's avatar
Warren Dukes committed
35

36 37
	assert(path != NULL);
	assert((*path == 0) == (parent == NULL));
Warren Dukes's avatar
Warren Dukes committed
38

39 40
	directory = g_malloc0(sizeof(*directory) -
			      sizeof(directory->path) + pathlen + 1);
41
	directory->parent = parent;
42
	memcpy(directory->path, path, pathlen + 1);
Warren Dukes's avatar
Warren Dukes committed
43 44 45 46

	return directory;
}

47
void
48
directory_free(struct directory *directory)
Avuton Olrich's avatar
Avuton Olrich committed
49
{
50 51 52 53 54 55
	for (unsigned i = 0; i < directory->songs.nr; ++i)
		song_free(directory->songs.base[i]);

	for (unsigned i = 0; i < directory->children.nr; ++i)
		directory_free(directory->children.base[i]);

56
	dirvec_destroy(&directory->children);
57
	songvec_destroy(&directory->songs);
58
	g_free(directory);
59
	/* this resets last dir returned */
60
	/*directory_get_path(NULL); */
Warren Dukes's avatar
Warren Dukes committed
61 62
}

63 64 65
const char *
directory_get_name(const struct directory *directory)
{
66
	return g_basename(directory->path);
67 68
}

69
void
70
directory_prune_empty(struct directory *directory)
Avuton Olrich's avatar
Avuton Olrich committed
71
{
72 73 74 75
	int i;
	struct dirvec *dv = &directory->children;

	for (i = dv->nr; --i >= 0; ) {
76
		directory_prune_empty(dv->base[i]);
77
		if (directory_is_empty(dv->base[i]))
78
			dirvec_delete(dv, dv->base[i]);
Warren Dukes's avatar
Warren Dukes committed
79
	}
80 81
	if (!dv->nr)
		dirvec_destroy(dv);
Warren Dukes's avatar
Warren Dukes committed
82 83
}

84
struct directory *
85
directory_lookup_directory(struct directory *directory, const char *uri)
86
{
87 88
	struct directory *cur = directory;
	struct directory *found = NULL;
89 90
	char *duplicated;
	char *locate;
Warren Dukes's avatar
Warren Dukes committed
91

92
	assert(uri != NULL);
93

94
	if (isRootDirectory(uri))
Warren Dukes's avatar
Warren Dukes committed
95 96
		return directory;

97
	duplicated = g_strdup(uri);
98 99 100 101
	locate = strchr(duplicated, '/');
	while (1) {
		if (locate)
			*locate = '\0';
102
		if (!(found = directory_get_child(cur, duplicated)))
103
			break;
104
		assert(cur == found->parent);
105 106 107 108 109 110
		cur = found;
		if (!locate)
			break;
		*locate = '/';
		locate = strchr(locate + 1, '/');
	}
Warren Dukes's avatar
Warren Dukes committed
111

112
	g_free(duplicated);
113

114
	return found;
115 116
}

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
struct song *
directory_lookup_song(struct directory *directory, const char *uri)
{
	char *duplicated, *base;
	struct song *song;

	assert(directory != NULL);
	assert(uri != NULL);

	duplicated = g_strdup(uri);
	base = strrchr(duplicated, '/');

	if (base != NULL) {
		*base++ = 0;
		directory = directory_lookup_directory(directory, duplicated);
		if (directory == NULL) {
			g_free(duplicated);
			return NULL;
		}
	} else
		base = duplicated;

	song = songvec_find(&directory->songs, base);
	assert(song == NULL || song->parent == directory);

	g_free(duplicated);
	return song;

}

147
void
148
directory_sort(struct directory *directory)
Avuton Olrich's avatar
Avuton Olrich committed
149
{
150 151
	int i;
	struct dirvec *dv = &directory->children;
Avuton Olrich's avatar
Avuton Olrich committed
152

153
	dirvec_sort(dv);
154
	songvec_sort(&directory->songs);
Warren Dukes's avatar
Warren Dukes committed
155

156
	for (i = dv->nr; --i >= 0; )
157
		directory_sort(dv->base[i]);
Warren Dukes's avatar
Warren Dukes committed
158 159
}

160
int
161 162 163 164
directory_walk(struct directory *directory,
	       int (*forEachSong)(struct song *, void *),
	       int (*forEachDir)(struct directory *, void *),
	       void *data)
Warren Dukes's avatar
Warren Dukes committed
165
{
166
	struct dirvec *dv = &directory->children;
167
	int err = 0;
168
	size_t j;
Avuton Olrich's avatar
Avuton Olrich committed
169

170 171
	if (forEachDir && (err = forEachDir(directory, data)) < 0)
		return err;
Avuton Olrich's avatar
Avuton Olrich committed
172 173

	if (forEachSong) {
174 175 176
		err = songvec_for_each(&directory->songs, forEachSong, data);
		if (err < 0)
			return err;
Avuton Olrich's avatar
Avuton Olrich committed
177 178
	}

179
	for (j = 0; err >= 0 && j < dv->nr; ++j)
180
		err = directory_walk(dv->base[j], forEachSong,
181
						forEachDir, data);
Avuton Olrich's avatar
Avuton Olrich committed
182

183
	return err;
Warren Dukes's avatar
Warren Dukes committed
184
}