Hello community,

here is the log from the commit of package mpd for openSUSE:Factory checked in 
at 2019-12-28 13:40:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mpd (Old)
 and      /work/SRC/openSUSE:Factory/.mpd.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mpd"

Sat Dec 28 13:40:46 2019 rev:15 rq:759768 version:0.21.18

Changes:
--------
--- /work/SRC/openSUSE:Factory/mpd/mpd.changes  2019-12-21 12:29:49.247318709 
+0100
+++ /work/SRC/openSUSE:Factory/.mpd.new.6675/mpd.changes        2019-12-28 
13:40:56.998946016 +0100
@@ -1,0 +2,14 @@
+Sat Dec 28 10:42:29 UTC 2019 - Илья Индиго <[email protected]>
+
+- Update to 0.21.18
+  * https://raw.githubusercontent.com/MusicPlayerDaemon/MPD/v0.21.18/NEWS
+  * protocol
+    * work around Mac OS X bug in the ISO 8601 parser
+  * output
+    * alsa: fix hang bug with ALSA "null" outputs
+  * storage
+    * curl: fix crash bug
+  * drop support for CURL versions older than 7.32.0
+  * reduce unnecessary CPU wakeups
+
+-------------------------------------------------------------------

Old:
----
  mpd-0.21.17.tar.xz

New:
----
  mpd-0.21.18.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mpd.spec ++++++
--- /var/tmp/diff_new_pack.94Uwgg/_old  2019-12-28 13:40:57.818946430 +0100
+++ /var/tmp/diff_new_pack.94Uwgg/_new  2019-12-28 13:40:57.846946444 +0100
@@ -20,7 +20,7 @@
 %bcond_with    faad
 %bcond_without mpd_iso9660
 Name:           mpd
-Version:        0.21.17
+Version:        0.21.18
 Release:        0
 Summary:        Music Player Daemon
 License:        GPL-2.0-or-later

++++++ mpd-0.21.17.tar.xz -> mpd-0.21.18.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/.travis.yml new/mpd-0.21.18/.travis.yml
--- old/mpd-0.21.17/.travis.yml 2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/.travis.yml 2019-12-24 16:13:16.000000000 +0100
@@ -2,6 +2,28 @@
 
 matrix:
   include:
+    # Ubuntu Bionic (18.04) with GCC 7
+    - os: linux
+      dist: bionic
+      addons:
+        apt:
+          sources:
+            - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by 
Meson)
+          packages:
+            - libgtest-dev
+            - libboost-dev
+            - python3.6
+            - python3-urllib3
+            - ninja-build
+      before_install:
+        - wget https://bootstrap.pypa.io/get-pip.py
+        - /usr/bin/python3.6 get-pip.py --user
+      install:
+        - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson
+      env:
+        - MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH"
+
+    # Ubuntu Trusty (16.04) with GCC 6
     - os: linux
       dist: trusty
       addons:
@@ -25,8 +47,9 @@
         - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson
       env:
         # use gold as workaround for 
https://sourceware.org/bugzilla/show_bug.cgi?id=17068
-        - MATRIX_EVAL="export CC=gcc-6 CXX=g++-6 LDFLAGS=-fuse-ld=gold 
PATH=$HOME/.local/bin:$PATH"
+        - MATRIX_EVAL="export CC='ccache gcc-6' CXX='ccache g++-6' 
LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH"
 
+    # Ubuntu Trusty (16.04) with GCC 8
     - os: linux
       dist: trusty
       addons:
@@ -50,25 +73,37 @@
         - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson
       env:
         # use gold as workaround for 
https://sourceware.org/bugzilla/show_bug.cgi?id=17068
-        - MATRIX_EVAL="export CC=gcc-8 CXX=g++-8 LDFLAGS=-fuse-ld=gold 
PATH=$HOME/.local/bin:$PATH"
+        - MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' 
LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH"
 
     - os: osx
-      osx_image: xcode9.3beta
+      osx_image: xcode9.4
+      addons:
+        homebrew:
+          packages:
+            - ccache
+            - meson
       env:
-        - MATRIX_EVAL=""
+        - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH 
HOMEBREW_NO_ANALYTICS=1"
 
 cache:
-  - apt
-  - ccache
+  apt: true
+  ccache: true
+  directories:
+    - $HOME/Library/Caches/Homebrew
+
+before_cache:
+  - test "$TRAVIS_OS_NAME" != "osx" || brew cleanup
 
 before_install:
   - eval "${MATRIX_EVAL}"
-  # C++14
-  - test "$TRAVIS_OS_NAME" != "osx" || brew update
 
 install:
   # C++14
-  - test "$TRAVIS_OS_NAME" != "osx" || brew install ccache meson
+
+  # Work around "Target /usr/local/lib/libgtest.a is a symlink
+  # belonging to nss. You can unlink it" during gtest install
+  - test "$TRAVIS_OS_NAME" != "osx" || brew unlink nss
+
   - test "$TRAVIS_OS_NAME" != "osx" || brew install --HEAD 
https://gist.githubusercontent.com/Kronuz/96ac10fbd8472eb1e7566d740c4034f8/raw/gtest.rb
 
 before_script:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/NEWS new/mpd-0.21.18/NEWS
--- old/mpd-0.21.17/NEWS        2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/NEWS        2019-12-24 16:13:16.000000000 +0100
@@ -1,3 +1,13 @@
+ver 0.21.18 (2019/12/24)
+* protocol
+  - work around Mac OS X bug in the ISO 8601 parser
+* output
+  - alsa: fix hang bug with ALSA "null" outputs
+* storage
+  - curl: fix crash bug
+* drop support for CURL versions older than 7.32.0
+* reduce unnecessary CPU wakeups
+
 ver 0.21.17 (2019/12/16)
 * protocol
   - relax the ISO 8601 parser: allow omitting field separators, the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/android/AndroidManifest.xml 
new/mpd-0.21.18/android/AndroidManifest.xml
--- old/mpd-0.21.17/android/AndroidManifest.xml 2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/android/AndroidManifest.xml 2019-12-24 16:13:16.000000000 
+0100
@@ -2,8 +2,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android";
           package="org.musicpd"
           android:installLocation="auto"
-          android:versionCode="40"
-          android:versionName="0.21.17">
+          android:versionCode="41"
+          android:versionName="0.21.18">
 
   <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/doc/conf.py new/mpd-0.21.18/doc/conf.py
--- old/mpd-0.21.17/doc/conf.py 2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/doc/conf.py 2019-12-24 16:13:16.000000000 +0100
@@ -38,7 +38,7 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.21.17'
+version = '0.21.18'
 # The full version, including alpha/beta/rc tags.
 release = version
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/meson.build new/mpd-0.21.18/meson.build
--- old/mpd-0.21.17/meson.build 2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/meson.build 2019-12-24 16:13:16.000000000 +0100
@@ -1,7 +1,7 @@
 project(
   'mpd',
   ['c', 'cpp'],
-  version: '0.21.17',
+  version: '0.21.18',
   meson_version: '>= 0.49.0',
   default_options: [
     'c_std=c99',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/event/Loop.cxx 
new/mpd-0.21.18/src/event/Loop.cxx
--- old/mpd-0.21.17/src/event/Loop.cxx  2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/event/Loop.cxx  2019-12-24 16:13:16.000000000 +0100
@@ -137,7 +137,8 @@
 ExportTimeoutMS(std::chrono::steady_clock::duration timeout)
 {
        return timeout >= timeout.zero()
-               ? 
int(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count())
+               /* round up (+1) to avoid unnecessary wakeups */
+               ? 
int(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()) + 1
                : -1;
 }
 
@@ -220,7 +221,6 @@
        } while (!quit);
 
 #ifndef NDEBUG
-       assert(busy);
        assert(thread.IsInside());
 #endif
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/event/MultiSocketMonitor.cxx 
new/mpd-0.21.18/src/event/MultiSocketMonitor.cxx
--- old/mpd-0.21.17/src/event/MultiSocketMonitor.cxx    2019-12-16 
23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/event/MultiSocketMonitor.cxx    2019-12-24 
16:13:16.000000000 +0100
@@ -22,6 +22,10 @@
 
 #include <algorithm>
 
+#ifdef USE_EPOLL
+#include <errno.h>
+#endif
+
 #ifndef _WIN32
 #include <poll.h>
 #endif
@@ -37,17 +41,42 @@
        assert(GetEventLoop().IsInside());
 
        fds.clear();
+#ifdef USE_EPOLL
+       always_ready_fds.clear();
+#endif
        IdleMonitor::Cancel();
        timeout_event.Cancel();
        ready = refresh = false;
 }
 
+bool
+MultiSocketMonitor::AddSocket(SocketDescriptor fd, unsigned events) noexcept
+{
+       fds.emplace_front(*this, fd);
+       bool success = fds.front().Schedule(events);
+       if (!success) {
+               fds.pop_front();
+
+#ifdef USE_EPOLL
+               if (errno == EPERM)
+                       /* not supported by epoll (e.g. "/dev/null"):
+                          add it to the "always ready" list */
+                       always_ready_fds.push_front({fd, events});
+#endif
+       }
+
+       return success;
+}
+
 void
 MultiSocketMonitor::ClearSocketList() noexcept
 {
        assert(GetEventLoop().IsInside());
 
        fds.clear();
+#ifdef USE_EPOLL
+       always_ready_fds.clear();
+#endif
 }
 
 #ifndef _WIN32
@@ -55,6 +84,10 @@
 void
 MultiSocketMonitor::ReplaceSocketList(pollfd *pfds, unsigned n) noexcept
 {
+#ifdef USE_EPOLL
+       always_ready_fds.clear();
+#endif
+
        pollfd *const end = pfds + n;
 
        UpdateSocketList([pfds, end](SocketDescriptor fd) -> unsigned {
@@ -64,9 +97,7 @@
                        if (i == end)
                                return 0;
 
-                       auto events = i->events;
-                       i->events = 0;
-                       return events;
+                       return std::exchange(i->events, 0);
                });
 
        for (auto i = pfds; i != end; ++i)
@@ -79,7 +110,20 @@
 void
 MultiSocketMonitor::Prepare() noexcept
 {
-       const auto timeout = PrepareSockets();
+       auto timeout = PrepareSockets();
+
+#ifdef USE_EPOLL
+       if (!always_ready_fds.empty()) {
+               /* if there was at least one file descriptor not
+                  supported by epoll, install a very short timeout
+                  because we assume it's always ready */
+               constexpr std::chrono::steady_clock::duration ready_timeout =
+                       std::chrono::milliseconds(1);
+               if (timeout < timeout.zero() || timeout > ready_timeout)
+                       timeout = ready_timeout;
+       }
+#endif
+
        if (timeout >= timeout.zero())
                timeout_event.Schedule(timeout);
        else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/event/MultiSocketMonitor.hxx 
new/mpd-0.21.18/src/event/MultiSocketMonitor.hxx
--- old/mpd-0.21.17/src/event/MultiSocketMonitor.hxx    2019-12-16 
23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/event/MultiSocketMonitor.hxx    2019-12-24 
16:13:16.000000000 +0100
@@ -50,12 +50,10 @@
                unsigned revents;
 
        public:
-               SingleFD(MultiSocketMonitor &_multi, SocketDescriptor _fd,
-                        unsigned events) noexcept
+               SingleFD(MultiSocketMonitor &_multi,
+                        SocketDescriptor _fd) noexcept
                        :SocketMonitor(_fd, _multi.GetEventLoop()),
-                       multi(_multi), revents(0) {
-                       Schedule(events);
-               }
+                       multi(_multi), revents(0) {}
 
                SocketDescriptor GetSocket() const noexcept {
                        return SocketMonitor::GetSocket();
@@ -86,8 +84,6 @@
                }
        };
 
-       friend class SingleFD;
-
        TimerEvent timeout_event;
 
        /**
@@ -106,6 +102,21 @@
 
        std::forward_list<SingleFD> fds;
 
+#ifdef USE_EPOLL
+       struct AlwaysReady {
+               const SocketDescriptor fd;
+               const unsigned revents;
+       };
+
+       /**
+        * A list of file descriptors which are always ready.  This is
+        * a kludge needed because the ALSA output plugin gives us a
+        * file descriptor to /dev/null, which is incompatible with
+        * epoll (epoll_ctl() returns -EPERM).
+        */
+       std::forward_list<AlwaysReady> always_ready_fds;
+#endif
+
 public:
        static constexpr unsigned READ = SocketMonitor::READ;
        static constexpr unsigned WRITE = SocketMonitor::WRITE;
@@ -147,9 +158,7 @@
         *
         * May only be called from PrepareSockets().
         */
-       void AddSocket(SocketDescriptor fd, unsigned events) noexcept {
-               fds.emplace_front(*this, fd, events);
-       }
+       bool AddSocket(SocketDescriptor fd, unsigned events) noexcept;
 
        /**
         * Remove all sockets.
@@ -204,6 +213,11 @@
                                i.ClearReturnedEvents();
                        }
                }
+
+#ifdef USE_EPOLL
+               for (const auto &i : always_ready_fds)
+                       f(i.fd, i.revents);
+#endif
        }
 
 protected:
@@ -232,7 +246,6 @@
 
        void OnTimeout() noexcept {
                SetReady();
-               IdleMonitor::Schedule();
        }
 
        virtual void OnIdle() noexcept final;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/event/SocketMonitor.cxx 
new/mpd-0.21.18/src/event/SocketMonitor.cxx
--- old/mpd-0.21.17/src/event/SocketMonitor.cxx 2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/event/SocketMonitor.cxx 2019-12-24 16:13:16.000000000 
+0100
@@ -68,20 +68,24 @@
        Steal().Close();
 }
 
-void
+bool
 SocketMonitor::Schedule(unsigned flags) noexcept
 {
        assert(IsDefined());
 
        if (flags == GetScheduledFlags())
-               return;
+               return true;
 
+       bool success;
        if (scheduled_flags == 0)
-               loop.AddFD(fd.Get(), flags, *this);
+               success = loop.AddFD(fd.Get(), flags, *this);
        else if (flags == 0)
-               loop.RemoveFD(fd.Get(), *this);
+               success = loop.RemoveFD(fd.Get(), *this);
        else
-               loop.ModifyFD(fd.Get(), flags, *this);
+               success = loop.ModifyFD(fd.Get(), flags, *this);
 
-       scheduled_flags = flags;
+       if (success)
+               scheduled_flags = flags;
+
+       return success;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/event/SocketMonitor.hxx 
new/mpd-0.21.18/src/event/SocketMonitor.hxx
--- old/mpd-0.21.17/src/event/SocketMonitor.hxx 2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/event/SocketMonitor.hxx 2019-12-24 16:13:16.000000000 
+0100
@@ -98,18 +98,22 @@
                return scheduled_flags;
        }
 
-       void Schedule(unsigned flags) noexcept;
+       /**
+        * @return true on success, false on error (with errno set if
+        * USE_EPOLL is defined)
+        */
+       bool Schedule(unsigned flags) noexcept;
 
        void Cancel() noexcept {
                Schedule(0);
        }
 
-       void ScheduleRead() noexcept {
-               Schedule(GetScheduledFlags() | READ | HANGUP | ERROR);
+       bool ScheduleRead() noexcept {
+               return Schedule(GetScheduledFlags() | READ | HANGUP | ERROR);
        }
 
-       void ScheduleWrite() noexcept {
-               Schedule(GetScheduledFlags() | WRITE);
+       bool ScheduleWrite() noexcept {
+               return Schedule(GetScheduledFlags() | WRITE);
        }
 
        void CancelRead() noexcept {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/input/plugins/CurlInputPlugin.cxx 
new/mpd-0.21.18/src/input/plugins/CurlInputPlugin.cxx
--- old/mpd-0.21.17/src/input/plugins/CurlInputPlugin.cxx       2019-12-16 
23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/input/plugins/CurlInputPlugin.cxx       2019-12-24 
16:13:16.000000000 +0100
@@ -180,7 +180,6 @@
 {
        BlockingCall(GetEventLoop(), [this](){
                        FreeEasy();
-                       (*curl_init)->InvalidateSockets();
                });
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/lib/curl/Global.cxx 
new/mpd-0.21.18/src/lib/curl/Global.cxx
--- old/mpd-0.21.17/src/lib/curl/Global.cxx     2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/lib/curl/Global.cxx     2019-12-24 16:13:16.000000000 
+0100
@@ -181,8 +181,6 @@
        assert(easy != nullptr);
 
        curl_multi_remove_handle(multi.Get(), easy);
-
-       InvalidateSockets();
 }
 
 static CurlRequest *
@@ -227,12 +225,12 @@
                return;
        }
 
-       if (timeout_ms < 10)
-               /* CURL 7.21.1 likes to report "timeout=0", which
+       if (timeout_ms < 1)
+               /* CURL's threaded resolver sets a timeout of 0ms, which
                   means we're running in a busy loop.  Quite a bad
                   idea to waste so much CPU.  Let's use a lower limit
-                  of 10ms. */
-               timeout_ms = 10;
+                  of 1ms. */
+               timeout_ms = 1;
 
        timeout_event.Schedule(std::chrono::milliseconds(timeout_ms));
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/lib/curl/Global.hxx 
new/mpd-0.21.18/src/lib/curl/Global.hxx
--- old/mpd-0.21.17/src/lib/curl/Global.hxx     2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/lib/curl/Global.hxx     2019-12-24 16:13:16.000000000 
+0100
@@ -74,16 +74,6 @@
                SocketAction(CURL_SOCKET_TIMEOUT, 0);
        }
 
-       /**
-        * This is a kludge to allow pausing/resuming a stream with
-        * libcurl < 7.32.0.  Read the curl_easy_pause manpage for
-        * more information.
-        */
-       void ResumeSockets() {
-               int running_handles;
-               curl_multi_socket_all(multi.Get(), &running_handles);
-       }
-
 private:
        void UpdateTimeout(long timeout_ms) noexcept;
        static int TimerFunction(CURLM *global, long timeout_ms,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/lib/curl/Request.cxx 
new/mpd-0.21.18/src/lib/curl/Request.cxx
--- old/mpd-0.21.17/src/lib/curl/Request.cxx    2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/lib/curl/Request.cxx    2019-12-24 16:13:16.000000000 
+0100
@@ -30,7 +30,6 @@
 #include "config.h"
 #include "Request.hxx"
 #include "Global.hxx"
-#include "Version.hxx"
 #include "Handler.hxx"
 #include "event/Call.hxx"
 #include "util/RuntimeError.hxx"
@@ -124,12 +123,6 @@
 
        curl_easy_pause(easy.Get(), CURLPAUSE_CONT);
 
-       if (IsCurlOlderThan(0x072000))
-               /* libcurl older than 7.32.0 does not update
-                  its sockets after curl_easy_pause(); force
-                  libcurl to do it now */
-               global.ResumeSockets();
-
        global.InvalidateSockets();
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/lib/curl/meson.build 
new/mpd-0.21.18/src/lib/curl/meson.build
--- old/mpd-0.21.17/src/lib/curl/meson.build    2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/lib/curl/meson.build    2019-12-24 16:13:16.000000000 
+0100
@@ -1,4 +1,4 @@
-curl_dep = dependency('libcurl', version: '>= 7.18', required: 
get_option('curl'))
+curl_dep = dependency('libcurl', version: '>= 7.32', required: 
get_option('curl'))
 conf.set('ENABLE_CURL', curl_dep.found())
 if not curl_dep.found()
   subdir_done()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/player/Thread.cxx 
new/mpd-0.21.18/src/player/Thread.cxx
--- old/mpd-0.21.17/src/player/Thread.cxx       2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/player/Thread.cxx       2019-12-24 16:13:16.000000000 
+0100
@@ -46,6 +46,7 @@
 #include "CrossFade.hxx"
 #include "tag/Tag.hxx"
 #include "Idle.hxx"
+#include "util/Compiler.h"
 #include "util/Domain.hxx"
 #include "thread/Name.hxx"
 #include "Log.hxx"
@@ -1171,6 +1172,7 @@
                        }
 
                        /* fall through */
+                       gcc_fallthrough;
 
                case PlayerCommand::PAUSE:
                        next_song.reset();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/storage/plugins/CurlStorage.cxx 
new/mpd-0.21.18/src/storage/plugins/CurlStorage.cxx
--- old/mpd-0.21.17/src/storage/plugins/CurlStorage.cxx 2019-12-16 
23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/storage/plugins/CurlStorage.cxx 2019-12-24 
16:13:16.000000000 +0100
@@ -109,7 +109,9 @@
                             BIND_THIS_METHOD(OnDeferredStart)),
                 request(curl, uri, *this) {
                // TODO: use CurlInputStream's configuration
+       }
 
+       void DeferStart() noexcept {
                /* start the transfer inside the IOThread */
                defer_start.Schedule();
        }
@@ -283,6 +285,7 @@
        }
 
        using BlockingHttpRequest::GetEasy;
+       using BlockingHttpRequest::DeferStart;
        using BlockingHttpRequest::Wait;
 
 protected:
@@ -430,6 +433,7 @@
        }
 
        const StorageFileInfo &Perform() {
+               DeferStart();
                Wait();
                return info;
        }
@@ -481,6 +485,7 @@
                 base_path(UriPathOrSlash(uri)) {}
 
        std::unique_ptr<StorageDirectoryReader> Perform() {
+               DeferStart();
                Wait();
                return ToReader();
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/time/ISO8601.cxx 
new/mpd-0.21.18/src/time/ISO8601.cxx
--- old/mpd-0.21.17/src/time/ISO8601.cxx        2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/src/time/ISO8601.cxx        2019-12-24 16:13:16.000000000 
+0100
@@ -58,6 +58,8 @@
        return FormatISO8601(GmTime(tp));
 }
 
+#ifndef _WIN32
+
 static std::pair<unsigned, unsigned>
 ParseTimeZoneOffsetRaw(const char *&s)
 {
@@ -108,6 +110,67 @@
        return d;
 }
 
+static const char *
+ParseTimeOfDay(const char *s, struct tm &tm,
+              std::chrono::system_clock::duration &precision) noexcept
+{
+       /* this function always checks "end==s" to work around a
+          strptime() bug on OS X: if nothing could be parsed,
+          strptime() returns the input string (indicating success)
+          instead of nullptr (indicating error) */
+
+       const char *end = strptime(s, "%H", &tm);
+       if (end == nullptr || end == s)
+               return end;
+
+       s = end;
+       precision = std::chrono::hours(1);
+
+       if (*s == ':') {
+               /* with field separators: now a minute must follow */
+
+               ++s;
+
+               end = strptime(s, "%M", &tm);
+               if (end == nullptr || end == s)
+                       return nullptr;
+
+               s = end;
+               precision = std::chrono::minutes(1);
+
+               /* the "seconds" field is optional */
+               if (*s != ':')
+                       return s;
+
+               ++s;
+
+               end = strptime(s, "%S", &tm);
+               if (end == nullptr || end == s)
+                       return nullptr;
+
+               precision = std::chrono::seconds(1);
+               return end;
+       }
+
+       /* without field separators */
+
+       end = strptime(s, "%M", &tm);
+       if (end == nullptr || end == s)
+               return s;
+
+       s = end;
+       precision = std::chrono::minutes(1);
+
+       end = strptime(s, "%S", &tm);
+       if (end == nullptr || end == s)
+               return s;
+
+       precision = std::chrono::seconds(1);
+       return end;
+}
+
+#endif
+
 std::pair<std::chrono::system_clock::time_point,
          std::chrono::system_clock::duration>
 ParseISO8601(const char *s)
@@ -138,22 +201,9 @@
        if (*s == 'T') {
                ++s;
 
-               if ((end = strptime(s, "%T", &tm)) != nullptr)
-                       precision = std::chrono::seconds(1);
-               else if ((end = strptime(s, "%H%M%S", &tm)) != nullptr)
-                       /* no field separators */
-                       precision = std::chrono::seconds(1);
-               else if ((end = strptime(s, "%H%M", &tm)) != nullptr)
-                       /* no field separators */
-                       precision = std::chrono::minutes(1);
-               else if ((end = strptime(s, "%H:%M", &tm)) != nullptr)
-                       precision = std::chrono::minutes(1);
-               else if ((end = strptime(s, "%H", &tm)) != nullptr)
-                       precision = std::chrono::hours(1);
-               else
+               s = ParseTimeOfDay(s, tm, precision);
+               if (s == nullptr)
                        throw std::runtime_error("Failed to parse time of day");
-
-               s = end;
        }
 
        auto tp = TimeGm(tm);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/util/Compiler.h 
new/mpd-0.21.18/src/util/Compiler.h
--- old/mpd-0.21.17/src/util/Compiler.h 2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/util/Compiler.h 2019-12-24 16:13:16.000000000 +0100
@@ -143,6 +143,14 @@
 #define gcc_flatten
 #endif
 
+#if GCC_CHECK_VERSION(7,0)
+#define gcc_fallthrough __attribute__((fallthrough))
+#elif CLANG_CHECK_VERSION(10,0)
+#define gcc_fallthrough [[fallthrough]]
+#else
+#define gcc_fallthrough
+#endif
+
 #ifndef __cplusplus
 /* plain C99 has "restrict" */
 #define gcc_restrict restrict
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/src/util/format.c 
new/mpd-0.21.18/src/util/format.c
--- old/mpd-0.21.17/src/util/format.c   2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/src/util/format.c   2019-12-24 16:13:16.000000000 +0100
@@ -19,6 +19,7 @@
  */
 
 #include "format.h"
+#include "util/Compiler.h"
 
 #include <stdbool.h>
 #include <stdio.h>
@@ -238,6 +239,7 @@
                        }
 
                        /* fall through */
+                       gcc_fallthrough;
 
                default:
                        /* pass-through non-escaped portions of the format 
string */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/test/RunCurl.cxx 
new/mpd-0.21.18/test/RunCurl.cxx
--- old/mpd-0.21.17/test/RunCurl.cxx    1970-01-01 01:00:00.000000000 +0100
+++ new/mpd-0.21.18/test/RunCurl.cxx    2019-12-24 16:13:16.000000000 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2003-2019 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include "ShutdownHandler.hxx"
+#include "lib/curl/Global.hxx"
+#include "lib/curl/Request.hxx"
+#include "lib/curl/Handler.hxx"
+#include "event/Loop.hxx"
+#include "util/PrintException.hxx"
+
+#include <stdio.h>
+
+class MyHandler final : public CurlResponseHandler {
+       EventLoop &event_loop;
+
+       std::exception_ptr error;
+
+public:
+       explicit MyHandler(EventLoop &_event_loop) noexcept
+               :event_loop(_event_loop) {}
+
+       void Finish() {
+               if (error)
+                       std::rethrow_exception(error);
+       }
+
+       /* virtual methods from CurlResponseHandler */
+       void OnHeaders(unsigned status,
+                      std::multimap<std::string, std::string> &&headers) 
override {
+               fprintf(stderr, "status: %u\n", status);
+               for (const auto &i : headers)
+                       fprintf(stderr, "%s: %s\n",
+                               i.first.c_str(), i.second.c_str());
+       }
+
+       void OnData(ConstBuffer<void> data) override {
+               if (fwrite(data.data, data.size, 1, stdout) != 1)
+                       throw std::runtime_error("Failed to write");
+       }
+
+       void OnEnd() override {
+               event_loop.Break();
+       }
+
+       void OnError(std::exception_ptr e) noexcept override {
+               error = std::move(e);
+               event_loop.Break();
+       }
+};
+
+int
+main(int argc, char **argv) noexcept
+try {
+       if (argc != 2) {
+               fprintf(stderr, "Usage: RunCurl URI\n");
+               return EXIT_FAILURE;
+       }
+
+       const char *const uri = argv[1];
+
+       EventLoop event_loop;
+       const ShutdownHandler shutdown_handler(event_loop);
+       CurlGlobal curl_global(event_loop);
+
+       MyHandler handler(event_loop);
+       CurlRequest request(curl_global, uri, handler);
+       request.Start();
+
+       event_loop.Run();
+
+       handler.Finish();
+
+       return EXIT_SUCCESS;
+} catch (...) {
+       PrintException(std::current_exception());
+       return EXIT_FAILURE;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/test/meson.build 
new/mpd-0.21.18/test/meson.build
--- old/mpd-0.21.17/test/meson.build    2019-12-16 23:32:44.000000000 +0100
+++ new/mpd-0.21.18/test/meson.build    2019-12-24 16:13:16.000000000 +0100
@@ -334,6 +334,18 @@
 )
 
 if curl_dep.found()
+  executable(
+    'RunCurl',
+    'RunCurl.cxx',
+    'ShutdownHandler.cxx',
+    '../src/Log.cxx',
+    '../src/LogBackend.cxx',
+    include_directories: inc,
+    dependencies: [
+      curl_dep,
+    ],
+  )
+
   test('test_icy_parser', executable(
     'test_icy_parser',
     'test_icy_parser.cxx',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mpd-0.21.17/test/run_storage.cxx 
new/mpd-0.21.18/test/run_storage.cxx
--- old/mpd-0.21.17/test/run_storage.cxx        2019-12-16 23:32:44.000000000 
+0100
+++ new/mpd-0.21.18/test/run_storage.cxx        2019-12-24 16:13:16.000000000 
+0100
@@ -90,6 +90,29 @@
        return EXIT_SUCCESS;
 }
 
+static int
+Stat(Storage &storage, const char *path)
+{
+       const auto info = storage.GetInfo(path, false);
+       switch (info.type) {
+       case StorageFileInfo::Type::OTHER:
+               printf("other\n");
+               break;
+
+       case StorageFileInfo::Type::REGULAR:
+               printf("regular\n");
+               break;
+
+       case StorageFileInfo::Type::DIRECTORY:
+               printf("directory\n");
+               break;
+       }
+
+       printf("size: %llu\n", (unsigned long long)info.size);
+
+       return EXIT_SUCCESS;
+}
+
 int
 main(int argc, char **argv)
 try {
@@ -117,6 +140,18 @@
                                           storage_uri);
 
                return Ls(*storage, path);
+       } else if (strcmp(command, "stat") == 0) {
+               if (argc != 4) {
+                       fprintf(stderr, "Usage: run_storage stat URI PATH\n");
+                       return EXIT_FAILURE;
+               }
+
+               const char *const path = argv[3];
+
+               auto storage = MakeStorage(io_thread.GetEventLoop(),
+                                          storage_uri);
+
+               return Stat(*storage, path);
        } else {
                fprintf(stderr, "Unknown command\n");
                return EXIT_FAILURE;


Reply via email to