Commit 69a42fc9 authored by Max Kellermann's avatar Max Kellermann

db/simple/Directory: LookupDirectory() return remaining URI

Code can now be reused in LookupSong().
parent 525789cd
......@@ -120,38 +120,49 @@ Directory::PruneEmpty()
}
}
Directory *
Directory::LookupResult
Directory::LookupDirectory(const char *uri)
{
assert(holding_db_lock());
assert(uri != nullptr);
if (isRootDirectory(uri))
return this;
return { this, nullptr };
char *duplicated = xstrdup(uri), *name = duplicated;
Directory *d = this;
while (1) {
while (true) {
char *slash = strchr(name, '/');
if (slash == name) {
d = nullptr;
if (slash == name)
break;
}
if (slash != nullptr)
*slash = '\0';
d = d->FindChild(name);
if (d == nullptr || slash == nullptr)
Directory *tmp = d->FindChild(name);
if (tmp == nullptr)
/* not found */
break;
d = tmp;
if (slash == nullptr) {
/* found everything */
name = nullptr;
break;
}
name = slash + 1;
}
free(duplicated);
return d;
const char *rest = name == nullptr
? nullptr
: uri + (name - duplicated);
return { d, rest };
}
void
......@@ -197,26 +208,16 @@ Directory::LookupSong(const char *uri)
assert(holding_db_lock());
assert(uri != nullptr);
char *duplicated = xstrdup(uri);
char *base = strrchr(duplicated, '/');
Directory *d = this;
if (base != nullptr) {
*base++ = 0;
d = d->LookupDirectory(duplicated);
if (d == nullptr) {
free(duplicated);
return nullptr;
}
} else
base = duplicated;
Song *song = d->FindSong(base);
assert(song == nullptr || song->parent == d);
auto r = LookupDirectory(uri);
if (r.uri == nullptr)
/* it's a directory */
return nullptr;
free(duplicated);
return song;
if (strchr(r.uri, '/') != nullptr)
/* refers to a URI "below" the actual song */
return nullptr;
return r.directory->FindSong(r.uri);
}
static int
......
......@@ -149,6 +149,21 @@ public:
return child;
}
struct LookupResult {
/**
* The last directory that was found. If the given
* URI could not be resolved at all, then this is the
* root directory.
*/
Directory *directory;
/**
* The remaining URI part (without leading slash) or
* nullptr if the given URI was consumed completely.
*/
const char *uri;
};
/**
* Looks up a directory by its relative URI.
*
......@@ -156,7 +171,7 @@ public:
* @return the Directory, or nullptr if none was found
*/
gcc_pure
Directory *LookupDirectory(const char *uri);
LookupResult LookupDirectory(const char *uri);
gcc_pure
bool IsEmpty() const {
......
......@@ -244,28 +244,33 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
{
ScopeDatabaseLock protect;
const Directory *directory = root->LookupDirectory(selection.uri.c_str());
if (directory == nullptr) {
auto r = root->LookupDirectory(selection.uri.c_str());
if (r.uri == nullptr) {
/* it's a directory */
if (selection.recursive && visit_directory &&
!visit_directory(r.directory->Export(), error))
return false;
return r.directory->Walk(selection.recursive, selection.filter,
visit_directory, visit_song,
visit_playlist,
error);
}
if (strchr(r.uri, '/') == nullptr) {
if (visit_song) {
Song *song = root->LookupSong(selection.uri.c_str());
Song *song = r.directory->FindSong(r.uri);
if (song != nullptr) {
const LightSong song2 = song->Export();
return !selection.Match(song2) ||
visit_song(song2, error);
}
}
error.Set(db_domain, DB_NOT_FOUND, "No such directory");
return false;
}
if (selection.recursive && visit_directory &&
!visit_directory(directory->Export(), error))
return false;
return directory->Walk(selection.recursive, selection.filter,
visit_directory, visit_song, visit_playlist,
error);
error.Set(db_domain, DB_NOT_FOUND, "No such directory");
return false;
}
bool
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment