diff options
author | Max Kellermann <max@duempel.org> | 2014-08-11 22:08:26 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-08-11 22:38:58 +0200 |
commit | 5d2506e69713cd8fd6086fd574b79e9de5364a4c (patch) | |
tree | 0b67fa0d4c85bf72174869db802d22cf19290bbc /src | |
parent | 14908b7f285305fe4a1e0a14f8be5751027d8164 (diff) | |
download | mpd-5d2506e69713cd8fd6086fd574b79e9de5364a4c.tar.gz mpd-5d2506e69713cd8fd6086fd574b79e9de5364a4c.tar.xz mpd-5d2506e69713cd8fd6086fd574b79e9de5364a4c.zip |
SongFilter: new filter "modified-since"
Diffstat (limited to 'src')
-rw-r--r-- | src/SongFilter.cxx | 75 | ||||
-rw-r--r-- | src/SongFilter.hxx | 8 |
2 files changed, 83 insertions, 0 deletions
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx index 7a8e6fd12..794cb9208 100644 --- a/src/SongFilter.cxx +++ b/src/SongFilter.cxx @@ -48,6 +48,9 @@ locate_parse_type(const char *str) if (strcmp(str, "base") == 0) return LOCATE_TAG_BASE_TYPE; + if (strcmp(str, "modified-since") == 0) + return LOCATE_TAG_MODIFIED_SINCE; + return tag_name_parse_i(str); } @@ -66,6 +69,11 @@ SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case) { } +SongFilter::Item::Item(unsigned _tag, time_t _time) + :tag(_tag), time(_time) +{ +} + bool SongFilter::Item::StringMatch(const char *s) const { @@ -128,6 +136,9 @@ SongFilter::Item::Match(const DetachedSong &song) const if (tag == LOCATE_TAG_BASE_TYPE) return uri_is_child_or_same(value.c_str(), song.GetURI()); + if (tag == LOCATE_TAG_MODIFIED_SINCE) + return song.GetLastModified() >= time; + if (tag == LOCATE_TAG_FILE_TYPE) return StringMatch(song.GetURI()); @@ -142,6 +153,9 @@ SongFilter::Item::Match(const LightSong &song) const return uri_is_child_or_same(value.c_str(), uri.c_str()); } + if (tag == LOCATE_TAG_MODIFIED_SINCE) + return song.mtime >= time; + if (tag == LOCATE_TAG_FILE_TYPE) { const auto uri = song.GetURI(); return StringMatch(uri.c_str()); @@ -160,6 +174,58 @@ SongFilter::~SongFilter() /* this destructor exists here just so it won't get inlined */ } +#if !defined(__GLIBC__) && !defined(WIN32) + +/** + * Determine the time zone offset in a portable way. + */ +gcc_const +static time_t +GetTimeZoneOffset() +{ + time_t t = 1234567890; + struct tm tm; + tm.tm_isdst = 0; + gmtime_r(&t, &tm); + return t - mktime(&tm); +} + +#endif + +gcc_pure +static time_t +ParseTimeStamp(const char *s) +{ + assert(s != nullptr); + + char *endptr; + unsigned long long value = strtoull(s, &endptr, 10); + if (*endptr == 0 && endptr > s) + /* it's an integral UNIX time stamp */ + return (time_t)value; + +#ifdef WIN32 + /* TODO: emulate strptime()? */ + return 0; +#else + /* try ISO 8601 */ + + struct tm tm; + const char *end = strptime(s, "%FT%TZ", &tm); + if (end == nullptr || *end != 0) + return 0; + +#ifdef __GLIBC__ + /* timegm() is a GNU extension */ + return timegm(&tm); +#else + tm.tm_isdst = 0; + return mktime(&tm) + GetTimeZoneOffset(); +#endif /* !__GLIBC__ */ + +#endif /* !WIN32 */ +} + bool SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) { @@ -175,6 +241,15 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case) fold_case = false; } + if (tag == LOCATE_TAG_MODIFIED_SINCE) { + time_t t = ParseTimeStamp(value); + if (t == 0) + return false; + + items.push_back(Item(tag, t)); + return true; + } + items.push_back(Item(tag, value, fold_case)); return true; } diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx index ca7d7bd90..f51bd85c6 100644 --- a/src/SongFilter.hxx +++ b/src/SongFilter.hxx @@ -26,11 +26,13 @@ #include <string> #include <stdint.h> +#include <time.h> /** * Limit the search to files within the given directory. */ #define LOCATE_TAG_BASE_TYPE (TAG_NUM_OF_ITEM_TYPES + 1) +#define LOCATE_TAG_MODIFIED_SINCE (TAG_NUM_OF_ITEM_TYPES + 2) #define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10 #define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20 @@ -51,9 +53,15 @@ public: std::string value; + /** + * For #LOCATE_TAG_MODIFIED_SINCE + */ + time_t time; + public: gcc_nonnull(3) Item(unsigned tag, const char *value, bool fold_case=false); + Item(unsigned tag, time_t time); Item(const Item &other) = delete; Item(Item &&) = default; |