Hello community,

here is the log from the commit of package libmpdclient for openSUSE:Factory 
checked in at 2018-10-12 13:10:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libmpdclient (Old)
 and      /work/SRC/openSUSE:Factory/.libmpdclient.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libmpdclient"

Fri Oct 12 13:10:28 2018 rev:2 rq:639905 version:2.15

Changes:
--------
--- /work/SRC/openSUSE:Factory/libmpdclient/libmpdclient.changes        
2017-08-28 15:12:22.217162949 +0200
+++ /work/SRC/openSUSE:Factory/.libmpdclient.new/libmpdclient.changes   
2018-10-12 13:10:33.131311854 +0200
@@ -1,0 +2,8 @@
+Thu Oct  4 08:43:30 UTC 2018 - Tomáš Chvátal <tchva...@suse.com>
+
+- Update to 2.15:
+  * support MPD protocol 0.17
+  * Various compiler warning fixes
+- Use meson macros
+
+-------------------------------------------------------------------

Old:
----
  libmpdclient-2.13.tar.xz

New:
----
  libmpdclient-2.15.tar.xz

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

Other differences:
------------------
++++++ libmpdclient.spec ++++++
--- /var/tmp/diff_new_pack.edgCMF/_old  2018-10-12 13:10:33.763310955 +0200
+++ /var/tmp/diff_new_pack.edgCMF/_new  2018-10-12 13:10:33.763310955 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package libmpdclient
 #
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,22 +12,22 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
+
 %define so_name 2
 Name:           libmpdclient
-Version:        2.13
+Version:        2.15
 Release:        0
 Summary:        Library for interfacing the Music Player Daemon
 License:        BSD-3-Clause
 Group:          Development/Libraries/C and C++
-Url:            http://www.musicpd.org/libs/libmpdclient/
+URL:            http://www.musicpd.org/libs/libmpdclient/
 Source:         
http://www.musicpd.org/download/libmpdclient/2/%{name}-%{version}.tar.xz
 BuildRequires:  meson >= 0.40
 BuildRequires:  ninja
 BuildRequires:  pkgconfig
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 
 %description
 A stable, documented, asynchronous API library for interfacing MPD (Music 
Player Daemon)
@@ -54,42 +54,23 @@
 %setup -q
 
 %build
-meson \
-    --prefix %{_prefix} \
-    --libdir %{_libdir} \
-    --libexecdir %{_libexecdir} \
-    --bindir %{_bindir} \
-    --sbindir %{_sbindir} \
-    --includedir %{_includedir} \
-    --datadir %{_datadir} \
-    --mandir %{_mandir} \
-    --infodir %{_infodir} \
-    --localedir %{_datadir}/locale \
-    --sysconfdir %{_sysconfdir} \
-    --localstatedir %{_localstatedir} \
-    --sharedstatedir %{_sharedstatedir} \
-    --default-library shared \
-    --backend ninja \
-    -D documentation=false \
-    . output
-ninja -C output %{?_smp_flags}
+%meson \
+    -D documentation=false
+%meson_build
 
 %install
-env DESTDIR=%{buildroot} \
-ninja -C output install
-rm -rf %{buildroot}/usr/share/doc
+%meson_install
+rm -rf %{buildroot}%{_datadir}/doc
 
 %post   -n %{name}%{so_name} -p /sbin/ldconfig
-
 %postun -n %{name}%{so_name} -p /sbin/ldconfig
 
 %files -n %{name}%{so_name}
-%defattr(-,root,root)
-%doc AUTHORS COPYING
+%license COPYING
+%doc AUTHORS
 %{_libdir}/%{name}.so.*
 
 %files devel
-%defattr(644, root, root)
 %doc NEWS
 %{_includedir}/mpd
 %{_libdir}/%{name}.so

++++++ libmpdclient-2.13.tar.xz -> libmpdclient-2.15.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/.travis.yml 
new/libmpdclient-2.15/.travis.yml
--- old/libmpdclient-2.13/.travis.yml   1970-01-01 01:00:00.000000000 +0100
+++ new/libmpdclient-2.15/.travis.yml   2018-09-02 22:45:54.000000000 +0200
@@ -0,0 +1,16 @@
+dist: trusty
+language: c
+
+os:
+  - osx
+
+before_install:
+  - test "$TRAVIS_OS_NAME" != "osx" || brew update
+
+install:
+  - test "$TRAVIS_OS_NAME" != "osx" || brew install meson ninja check
+
+script:
+  - OPTIONS="-Dtest=true"
+  - meson . output $OPTIONS
+  - ninja -v -C output test
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/NEWS new/libmpdclient-2.15/NEWS
--- old/libmpdclient-2.13/NEWS  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/NEWS  2018-09-02 22:45:54.000000000 +0200
@@ -1,3 +1,21 @@
+libmpdclient 2.15 (2018/09/02)
+* support MPD protocol 0.21
+  - search: support search expressions
+  - search: descending sort
+  - search: support sorting by "Last-Modified"
+  - song: audio format
+* support MPD protocol 0.17
+  - player: command "seekcur"
+* fix `-Wrestrict` compiler warning
+
+libmpdclient 2.14 (2018/02/11)
+* support MPD protocol 0.21
+  - command "outputset"
+  - mpd_output_get_plugin()
+  - receive output attributes
+* MSVC compatibility
+* improved local and abstract socket support
+
 libmpdclient 2.13 (2017/07/25)
 * fix build with meson > 0.38.1
 * fix connect error "Operation now in progress"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/build/configure.py 
new/libmpdclient-2.15/build/configure.py
--- old/libmpdclient-2.13/build/configure.py    2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/build/configure.py    2018-09-02 22:45:54.000000000 
+0200
@@ -22,7 +22,6 @@
     'release': {
         'options': [
             '--buildtype', 'release',
-            '--unity',
             '-Db_ndebug=true',
             '-Dtest=true',
         ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/include/mpd/audio_format.h 
new/libmpdclient-2.15/include/mpd/audio_format.h
--- old/libmpdclient-2.13/include/mpd/audio_format.h    2017-07-25 
09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/include/mpd/audio_format.h    2018-09-02 
22:45:54.000000000 +0200
@@ -39,6 +39,13 @@
 
 enum {
        /**
+        * The sample format is unknown or unspecified.
+        *
+        * @since libmpdclient 2.15
+        */
+       MPD_SAMPLE_FORMAT_UNDEFINED = 0x00,
+
+       /**
         * 32 bit floating point samples.
         */
        MPD_SAMPLE_FORMAT_FLOAT = 0xe0,
@@ -57,6 +64,8 @@
         * The sample rate in Hz.  A better name for this attribute is
         * "frame rate", because technically, you have two samples per
         * frame in stereo sound.
+        *
+        * The special value 0 means "unknown or unspecified".
         */
        uint32_t sample_rate;
 
@@ -64,7 +73,7 @@
         * The number of significant bits per sample.  Samples are
         * currently always signed.  Supported values are 8, 16, 24,
         * 32 and the special values #MPD_SAMPLE_FORMAT_FLOAT,
-        * #MPD_SAMPLE_FORMAT_DSD.
+        * #MPD_SAMPLE_FORMAT_DSD, #MPD_SAMPLE_FORMAT_UNDEFINED.
         *
         * @since libmpdclient 2.10 added support for #MPD_SAMPLE_FORMAT_FLOAT 
and
         * #MPD_SAMPLE_FORMAT_DSD.
@@ -74,6 +83,8 @@
        /**
         * The number of channels.  Only mono (1) and stereo (2) are
         * fully supported currently.
+        *
+        * The special value 0 means "unknown or unspecified".
         */
        uint8_t channels;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/include/mpd/output.h 
new/libmpdclient-2.15/include/mpd/output.h
--- old/libmpdclient-2.13/include/mpd/output.h  2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/include/mpd/output.h  2018-09-02 22:45:54.000000000 
+0200
@@ -100,6 +100,16 @@
 mpd_output_get_name(const struct mpd_output *output);
 
 /**
+ * @return the plugin of the specified #mpd_output object, or NULL if
+ * none was specified by the server
+ *
+ * @since libmpdclient 2.14, MPD 0.21
+ */
+mpd_pure
+const char *
+mpd_output_get_plugin(const struct mpd_output *output);
+
+/**
  * @return true if this output is enabled
  */
 mpd_pure
@@ -107,6 +117,31 @@
 mpd_output_get_enabled(const struct mpd_output *output);
 
 /**
+ * Obtains the first attribute for this output.  This rewinds the
+ * current attribute pointer to the start.  Call
+ * mpd_output_next_attribute() to obtain more attributes.
+ *
+ * @return a pointer to the first attribute or NULL if there are no
+ * attributes
+ *
+ * @since libmpdclient 2.14, MPD 0.21
+ */
+const struct mpd_pair *
+mpd_output_first_attribute(struct mpd_output *output);
+
+/**
+ * Obtains the next attribute for this output.  Call this function
+ * repeatedly until it returns NULL to get a full list of attributes.
+ *
+ * @return a pointer to the next attribute or NULL if there are no
+ * more attributes
+ *
+ * @since libmpdclient 2.14, MPD 0.21
+ */
+const struct mpd_pair *
+mpd_output_next_attribute(struct mpd_output *output);
+
+/**
  * Sends the "outputs" command to MPD.  Call mpd_recv_output() to
  * read the response.
  *
@@ -197,6 +232,31 @@
 bool
 mpd_run_toggle_output(struct mpd_connection *connection, unsigned output_id);
 
+/**
+ * Sends the "outputset" command to MPD.
+ *
+ * @param connection a valid and connected mpd_connection
+ * @param output_id an identifier for the output device (see
+ * mpd_recv_output())
+ * @param attribute_name the attribute name
+ * @param attribute_value the attribute value
+ * @return true on success
+ *
+ * @since libmpdclient 2.14, MPD 0.21
+ */
+bool
+mpd_send_output_set(struct mpd_connection *connection, unsigned output_id,
+                   const char *attribute_name, const char *attribute_value);
+
+/**
+ * Shortcut for mpd_send_output_set() and mpd_response_finish().
+ *
+ * @since libmpdclient 2.14, MPD 0.21
+ */
+bool
+mpd_run_output_set(struct mpd_connection *connection, unsigned output_id,
+                  const char *attribute_name, const char *attribute_value);
+
 #ifdef __cplusplus
 }
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/include/mpd/player.h 
new/libmpdclient-2.15/include/mpd/player.h
--- old/libmpdclient-2.13/include/mpd/player.h  2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/include/mpd/player.h  2018-09-02 22:45:54.000000000 
+0200
@@ -185,6 +185,24 @@
 mpd_run_seek_id_float(struct mpd_connection *connection,
                      unsigned song_id, float t);
 
+/**
+ * Seeks the current song.
+ *
+ * @param connection the connection to MPD
+ * @param t the position within the song, in seconds
+ * @param relative true makes #t a relative to the current position
+ * @return true on success, false on error
+ *
+ * @since MPD 0.17, libmpdclient 2.15
+ */
+bool
+mpd_send_seek_current(struct mpd_connection *connection,
+                     float t, bool relative);
+
+bool
+mpd_run_seek_current(struct mpd_connection *connection,
+                    float t, bool relative);
+
 bool
 mpd_send_repeat(struct mpd_connection *connection, bool mode);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/include/mpd/search.h 
new/libmpdclient-2.15/include/mpd/search.h
--- old/libmpdclient-2.13/include/mpd/search.h  2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/include/mpd/search.h  2018-09-02 22:45:54.000000000 
+0200
@@ -200,6 +200,20 @@
                                         time_t value);
 
 /**
+ * Add an expression string.
+ *
+ * @param connection a #mpd_connection
+ * @param expression the expression string; must be enclosed in
+ * parantheses
+ * @return true on success, false on error
+ *
+ * @since libmpdclient 2.15, MPD 0.21
+ */
+bool
+mpd_search_add_expression(struct mpd_connection *connection,
+                         const char *expression);
+
+/**
  * Group the results by the specified tag.
  *
  * @param connection a #mpd_connection
@@ -213,18 +227,34 @@
                         enum mpd_tag_type type);
 
 /**
+ * Sort the results by the specified named attribute.
+ *
+ * @param connection a #mpd_connection
+ * @param name the attribute name to sort with; can be a tag name or
+ * "Last-Modified"
+ * @param descending sort in reverse order?
+ * @return true on success, false on error
+ *
+ * @since MPD 0.21, libmpdclient 2.15
+ */
+bool
+mpd_search_add_sort_name(struct mpd_connection *connection,
+                        const char *name, bool descending);
+
+/**
  * Sort the results by the specified tag.
  *
  * @param connection a #mpd_connection
  * @param type the tag type to sort with
- * @param reserved must be false
+ * @param descending sort in reverse order?
  * @return true on success, false on error
  *
- * @since libmpdclient 2.11
+ * @since MPD 0.21, libmpdclient 2.11; #descending since libmpdclient
+ * 2.15
  */
 bool
 mpd_search_add_sort_tag(struct mpd_connection *connection,
-                       enum mpd_tag_type type, bool reserved);
+                       enum mpd_tag_type type, bool descending);
 
 /**
  * Request only a portion of the result set.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/include/mpd/song.h 
new/libmpdclient-2.15/include/mpd/song.h
--- old/libmpdclient-2.13/include/mpd/song.h    2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/include/mpd/song.h    2018-09-02 22:45:54.000000000 
+0200
@@ -1,5 +1,5 @@
 /* libmpdclient
-   (c) 2003-2017 The Music Player Daemon Project
+   (c) 2003-2018 The Music Player Daemon Project
    This project's homepage is: http://www.musicpd.org
 
    Redistribution and use in source and binary forms, with or without
@@ -184,6 +184,16 @@
 mpd_song_get_prio(const struct mpd_song *song);
 
 /**
+ * Returns audio format as determined by MPD's decoder plugin.  May
+ * return NULL if the format is not available or unknown.
+ *
+ * @since libmpdclient 2.15
+ */
+mpd_pure
+const struct mpd_audio_format *
+mpd_song_get_audio_format(const struct mpd_song *song);
+
+/**
  * Begins parsing a new song.
  *
  * @param pair the first pair in this song (name must be "file")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/libmpdclient.ld 
new/libmpdclient-2.15/libmpdclient.ld
--- old/libmpdclient-2.13/libmpdclient.ld       2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/libmpdclient.ld       2018-09-02 22:45:54.000000000 
+0200
@@ -119,7 +119,10 @@
        mpd_output_free;
        mpd_output_get_id;
        mpd_output_get_name;
+       mpd_output_get_plugin;
        mpd_output_get_enabled;
+       mpd_output_first_attribute;
+       mpd_output_next_attribute;
        mpd_send_outputs;
        mpd_recv_output;
        mpd_send_enable_output;
@@ -128,6 +131,8 @@
        mpd_run_disable_output;
        mpd_send_toggle_output;
        mpd_run_toggle_output;
+       mpd_send_output_set;
+       mpd_run_output_set;
 
        /* mpd/parser.h */
        mpd_parser_new;
@@ -169,6 +174,8 @@
        mpd_run_seek_id;
        mpd_send_seek_id_float;
        mpd_run_seek_id_float;
+       mpd_send_seek_current;
+       mpd_run_seek_current;
        mpd_send_repeat;
        mpd_run_repeat;
        mpd_send_random;
@@ -288,7 +295,9 @@
        mpd_search_add_tag_constraint;
        mpd_search_add_any_tag_constraint;
        mpd_search_add_modified_since_constraint;
+       mpd_search_add_expression;
        mpd_search_add_group_tag;
+       mpd_search_add_sort_name;
        mpd_search_add_sort_tag;
        mpd_search_add_window;
        mpd_search_commit;
@@ -312,6 +321,7 @@
        mpd_song_get_pos;
        mpd_song_get_id;
        mpd_song_get_prio;
+       mpd_song_get_audio_format;
        mpd_song_begin;
        mpd_song_feed;
        mpd_recv_song;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/meson.build 
new/libmpdclient-2.15/meson.build
--- old/libmpdclient-2.13/meson.build   2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/meson.build   2018-09-02 22:45:54.000000000 +0200
@@ -1,4 +1,4 @@
-project('libmpdclient', 'c', version: '2.13',
+project('libmpdclient', 'c', version: '2.15',
   default_options: [
     'c_std=c99',
   ],
@@ -18,12 +18,11 @@
 conf.set_quoted('DEFAULT_HOST', get_option('default_host'))
 conf.set('DEFAULT_PORT', get_option('default_port'))
 
-if get_option('tcp')
-  conf.set('ENABLE_TCP', '1')
+conf.set('HAVE_STRNDUP', cc.has_function('strndup', prefix: '#define 
_GNU_SOURCE\n#include <string.h>'))
 
-  if cc.has_function('getaddrinfo')
-    conf.set('HAVE_GETADDRINFO', '1')
-  endif
+if get_option('tcp')
+  conf.set('ENABLE_TCP', true)
+  conf.set('HAVE_GETADDRINFO', cc.has_function('getaddrinfo'))
 endif
 
 configure_file(output: 'config.h', configuration: conf)
@@ -73,11 +72,17 @@
   test_ldflags += [ '-Wl,--version-script=' + join_paths(meson.source_root(), 
'libmpdclient.ld') ]
 endif
 
-foreach f: test_ldflags
-  if cc.has_argument(f)
-    common_ldflags += [ f ]
-  endif
-endforeach
+if meson.version().version_compare('>=0.46.0')
+  # compiler.has_link_argument() was added in Meson 0.46.0
+  foreach f: test_ldflags
+    if cc.has_link_argument(f)
+      common_ldflags += [ f ]
+    endif
+  endforeach
+else
+  # Meson too old: assume the linker supports all flags
+  common_ldflags += test_ldflags
+endif
 
 platform_deps = []
 if host_machine.system() == 'windows'
@@ -94,6 +99,7 @@
 
 libmpdclient = library('mpdclient',
   'src/async.c',
+  'src/audio_format.c',
   'src/ierror.c',
   'src/resolver.c',
   'src/capabilities.c',
@@ -108,6 +114,7 @@
   'src/entity.c',
   'src/idle.c',
   'src/iso8601.c',
+  'src/kvlist.c',
   'src/list.c',
   'src/mixer.c',
   'src/parser.c',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/async.c 
new/libmpdclient-2.15/src/async.c
--- old/libmpdclient-2.13/src/async.c   2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/async.c   2018-09-02 22:45:54.000000000 +0200
@@ -37,13 +37,17 @@
 #include <assert.h>
 #include <stdbool.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <sys/types.h>
 #include <string.h>
 #include <stdarg.h>
 
-#ifndef _WIN32
-#include <sys/socket.h>
+#ifdef _WIN32
+#  include <basetsd.h> /* for SSIZE_T */
+#ifndef __MINGW32__
+typedef SSIZE_T ssize_t;
+#endif
+#else
+#  include <sys/socket.h>
 #endif
 
 #ifndef MSG_DONTWAIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/audio_format.c 
new/libmpdclient-2.15/src/audio_format.c
--- old/libmpdclient-2.13/src/audio_format.c    1970-01-01 01:00:00.000000000 
+0100
+++ new/libmpdclient-2.15/src/audio_format.c    2018-09-02 22:45:54.000000000 
+0200
@@ -0,0 +1,83 @@
+/* libmpdclient
+   (c) 2003-2018 The Music Player Daemon Project
+   This project's homepage is: http://www.musicpd.org
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   - Neither the name of the Music Player Daemon nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "iaf.h"
+#include <mpd/audio_format.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+void
+mpd_parse_audio_format(struct mpd_audio_format *audio_format, const char *p)
+{
+       char *endptr;
+
+       if (strncmp(p, "dsd", 3) == 0) {
+               /* allow format specifications such as "dsd64" which
+                  implies the sample rate */
+
+               unsigned long dsd = strtoul(p + 3, &endptr, 10);
+               if (endptr > p + 3 && *endptr == ':' &&
+                   dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
+                       audio_format->sample_rate = dsd * 44100 / 8;
+                       audio_format->bits = MPD_SAMPLE_FORMAT_DSD;
+
+                       p = endptr + 1;
+                       audio_format->channels = strtoul(p, NULL, 10);
+                       return;
+               }
+       }
+
+       audio_format->sample_rate = strtoul(p, &endptr, 10);
+       if (*endptr == ':') {
+               p = endptr + 1;
+
+               if (p[0] == 'f' && p[1] == ':') {
+                       audio_format->bits = MPD_SAMPLE_FORMAT_FLOAT;
+                       p += 2;
+               } else if (p[0] == 'd' && p[1] == 's' &&
+                          p[2] == 'd' && p[3] == ':') {
+                       audio_format->bits = MPD_SAMPLE_FORMAT_DSD;
+                       p += 4;
+               } else {
+                       audio_format->bits = strtoul(p, &endptr, 10);
+                       p = *endptr == ':' ? endptr + 1 : NULL;
+               }
+
+               audio_format->channels = p != NULL
+                       ? strtoul(p, NULL, 10)
+                       : 0;
+       } else {
+               audio_format->bits = 0;
+               audio_format->channels = 0;
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/coutput.c 
new/libmpdclient-2.15/src/coutput.c
--- old/libmpdclient-2.13/src/coutput.c 2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/coutput.c 2018-09-02 22:45:54.000000000 +0200
@@ -113,3 +113,21 @@
                mpd_send_toggle_output(connection, output_id) &&
                mpd_response_finish(connection);
 }
+
+bool
+mpd_send_output_set(struct mpd_connection *connection, unsigned output_id,
+                   const char *attribute_name, const char *attribute_value)
+{
+       return mpd_send_u_s_s_command(connection, "outputset", output_id,
+                                     attribute_name, attribute_value);
+}
+
+bool
+mpd_run_output_set(struct mpd_connection *connection, unsigned output_id,
+                   const char *attribute_name, const char *attribute_value)
+{
+       return mpd_run_check(connection) &&
+               mpd_send_output_set(connection, output_id,
+                                   attribute_name, attribute_value) &&
+               mpd_response_finish(connection);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/example.c 
new/libmpdclient-2.15/src/example.c
--- old/libmpdclient-2.13/src/example.c 2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/example.c 2018-09-02 22:45:54.000000000 +0200
@@ -40,7 +40,6 @@
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdlib.h>
 
 static int
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/iaf.h 
new/libmpdclient-2.15/src/iaf.h
--- old/libmpdclient-2.13/src/iaf.h     1970-01-01 01:00:00.000000000 +0100
+++ new/libmpdclient-2.15/src/iaf.h     2018-09-02 22:45:54.000000000 +0200
@@ -0,0 +1,49 @@
+/* libmpdclient
+   (c) 2003-2018 The Music Player Daemon Project
+   This project's homepage is: http://www.musicpd.org
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MPD_INTERNAL_AUDIO_FORMAT_H
+#define MPD_INTERNAL_AUDIO_FORMAT_H
+
+#include <mpd/audio_format.h>
+
+#include <stdbool.h>
+
+struct mpd_audio_format;
+
+void
+mpd_parse_audio_format(struct mpd_audio_format *audio_format, const char *p);
+
+static inline bool
+mpd_audio_format_is_empty(const struct mpd_audio_format *audio_format)
+{
+       return audio_format->sample_rate == 0 &&
+               audio_format->bits == MPD_SAMPLE_FORMAT_UNDEFINED &&
+               audio_format->channels == 0;
+}
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/ierror.c 
new/libmpdclient-2.15/src/ierror.c
--- old/libmpdclient-2.13/src/ierror.c  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/ierror.c  2018-09-02 22:45:54.000000000 +0200
@@ -40,7 +40,7 @@
 {
        assert(error != NULL);
 
-       if (error->code != MPD_ERROR_SUCCESS && error->message != NULL)
+       if (error->code != MPD_ERROR_SUCCESS)
                free(error->message);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/internal.h 
new/libmpdclient-2.15/src/internal.h
--- old/libmpdclient-2.13/src/internal.h        2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/src/internal.h        2018-09-02 22:45:54.000000000 
+0200
@@ -33,7 +33,12 @@
 
 #include "ierror.h"
 
+/* for struct timeval */
+#ifdef _WIN32
+#include <winsock2.h>
+#else
 #include <sys/time.h>
+#endif
 
 /**
  * This opaque object represents a connection to a MPD server.  Call
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/kvlist.c 
new/libmpdclient-2.15/src/kvlist.c
--- old/libmpdclient-2.13/src/kvlist.c  1970-01-01 01:00:00.000000000 +0100
+++ new/libmpdclient-2.15/src/kvlist.c  2018-09-02 22:45:54.000000000 +0200
@@ -0,0 +1,147 @@
+/* libmpdclient
+   (c) 2003-2018 The Music Player Daemon Project
+   This project's homepage is: http://www.musicpd.org
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "kvlist.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+struct mpd_kvlist_item {
+       struct mpd_kvlist_item *next;
+       char *key, *value;
+};
+
+static void
+mpd_kvlist_item_free(struct mpd_kvlist_item *i)
+{
+       assert(i != NULL);
+
+       free(i->key);
+       free(i->value);
+       free(i);
+}
+
+void
+mpd_kvlist_init(struct mpd_kvlist *l)
+{
+       assert(l != NULL);
+
+       l->head = NULL;
+       l->tail_r = &l->head;
+       l->cursor = NULL;
+}
+
+void
+mpd_kvlist_deinit(struct mpd_kvlist *l)
+{
+       assert(l != NULL);
+
+       while (l->head != NULL) {
+               struct mpd_kvlist_item *i = l->head;
+               l->head = i->next;
+               mpd_kvlist_item_free(i);
+       }
+}
+
+#ifndef HAVE_STRNDUP
+static char *
+strndup(const char *s, size_t length)
+{
+       char *p = malloc(length + 1);
+       if (p != NULL) {
+               memcpy(p, s, length);
+               p[length] = 0;
+       }
+
+       return p;
+}
+#endif
+
+void
+mpd_kvlist_add(struct mpd_kvlist *l, const char *key, size_t key_length,
+              const char *value)
+{
+       assert(l != NULL);
+       assert(l->tail_r != NULL);
+       assert(key != NULL);
+       assert(value != NULL);
+
+       struct mpd_kvlist_item *i = malloc(sizeof(*i));
+       if (i == NULL)
+               return;
+
+       i->next = NULL;
+       i->key = strndup(key, key_length);
+       i->value = strdup(value);
+       if (i->key == NULL || i->value == NULL) {
+               mpd_kvlist_item_free(i);
+               return;
+       }
+
+       *l->tail_r = i;
+       l->tail_r = &i->next;
+}
+
+static const struct mpd_pair *
+mpd_kvlist_item_to_pair(struct mpd_pair *buffer,
+                       const struct mpd_kvlist_item *item)
+{
+       assert(buffer != NULL);
+       assert(item != NULL);
+
+       buffer->name = item->key;
+       buffer->value = item->value;
+       return buffer;
+}
+
+const struct mpd_pair *
+mpd_kvlist_first(struct mpd_kvlist *l)
+{
+       assert(l != NULL);
+
+       if (l->head == NULL)
+               return NULL;
+
+       l->cursor = l->head;
+       return mpd_kvlist_item_to_pair(&l->pair, l->cursor);
+}
+
+const struct mpd_pair *
+mpd_kvlist_next(struct mpd_kvlist *l)
+{
+       assert(l != NULL);
+       assert(l->cursor != NULL);
+
+       if (l->cursor->next == NULL)
+               return NULL;
+
+       l->cursor = l->cursor->next;
+       return mpd_kvlist_item_to_pair(&l->pair, l->cursor);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/kvlist.h 
new/libmpdclient-2.15/src/kvlist.h
--- old/libmpdclient-2.13/src/kvlist.h  1970-01-01 01:00:00.000000000 +0100
+++ new/libmpdclient-2.15/src/kvlist.h  2018-09-02 22:45:54.000000000 +0200
@@ -0,0 +1,59 @@
+/* libmpdclient
+   (c) 2003-2018 The Music Player Daemon Project
+   This project's homepage is: http://www.musicpd.org
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MPD_KVLIST_H
+#define MPD_KVLIST_H
+
+#include <mpd/pair.h>
+
+#include <stddef.h>
+
+struct mpd_kvlist {
+       struct mpd_kvlist_item *head, **tail_r;
+
+       const struct mpd_kvlist_item *cursor;
+       struct mpd_pair pair;
+};
+
+void
+mpd_kvlist_init(struct mpd_kvlist *l);
+
+void
+mpd_kvlist_deinit(struct mpd_kvlist *l);
+
+void
+mpd_kvlist_add(struct mpd_kvlist *l, const char *key, size_t key_length,
+              const char *value);
+
+const struct mpd_pair *
+mpd_kvlist_first(struct mpd_kvlist *l);
+
+const struct mpd_pair *
+mpd_kvlist_next(struct mpd_kvlist *l);
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/message.c 
new/libmpdclient-2.15/src/message.c
--- old/libmpdclient-2.13/src/message.c 2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/message.c 2018-09-02 22:45:54.000000000 +0200
@@ -67,9 +67,7 @@
                return false;
 
        if (strcmp(pair->name, "message") == 0) {
-               if (output->text != NULL)
-                       free(output->text);
-
+               free(output->text);
                output->text = strdup(pair->value);
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/output.c 
new/libmpdclient-2.15/src/output.c
--- old/libmpdclient-2.13/src/output.c  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/output.c  2018-09-02 22:45:54.000000000 +0200
@@ -32,6 +32,7 @@
 
 #include <mpd/output.h>
 #include <mpd/pair.h>
+#include "kvlist.h"
 
 #include <assert.h>
 #include <string.h>
@@ -40,6 +41,10 @@
 struct mpd_output {
        unsigned id;
        char *name;
+       char *plugin;
+
+       struct mpd_kvlist attributes;
+
        bool enabled;
 };
 
@@ -60,6 +65,8 @@
        output->id = atoi(pair->value);
 
        output->name = NULL;
+       output->plugin = NULL;
+       mpd_kvlist_init(&output->attributes);
        output->enabled = false;
 
        return output;
@@ -72,12 +79,20 @@
                return false;
 
        if (strcmp(pair->name, "outputname") == 0) {
-               if (output->name != NULL)
-                       free(output->name);
-
+               free(output->name);
                output->name = strdup(pair->value);
        } else if (strcmp(pair->name, "outputenabled") == 0)
                output->enabled = atoi(pair->value) != 0;
+       else if (strcmp(pair->name, "plugin") == 0) {
+               free(output->plugin);
+               output->plugin = strdup(pair->value);
+       } else if (strcmp(pair->name, "attribute") == 0) {
+               const char *eq = strchr(pair->value, '=');
+               if (eq != NULL && eq > pair->value)
+                       mpd_kvlist_add(&output->attributes,
+                                      pair->value, eq - pair->value,
+                                      eq + 1);
+       }
 
        return true;
 }
@@ -87,8 +102,9 @@
 {
        assert(output != NULL);
 
-       if (output->name != NULL)
-               free(output->name);
+       free(output->name);
+       free(output->plugin);
+       mpd_kvlist_deinit(&output->attributes);
        free(output);
 }
 
@@ -108,6 +124,14 @@
        return output->name;
 }
 
+const char *
+mpd_output_get_plugin(const struct mpd_output *output)
+{
+       assert(output != NULL);
+
+       return output->plugin;
+}
+
 bool
 mpd_output_get_enabled(const struct mpd_output *output)
 {
@@ -115,3 +139,19 @@
 
        return output->enabled;
 }
+
+const struct mpd_pair *
+mpd_output_first_attribute(struct mpd_output *output)
+{
+       assert(output != NULL);
+
+       return mpd_kvlist_first(&output->attributes);
+}
+
+const struct mpd_pair *
+mpd_output_next_attribute(struct mpd_output *output)
+{
+       assert(output != NULL);
+
+       return mpd_kvlist_next(&output->attributes);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/player.c 
new/libmpdclient-2.15/src/player.c
--- old/libmpdclient-2.13/src/player.c  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/player.c  2018-09-02 22:45:54.000000000 +0200
@@ -217,6 +217,28 @@
 }
 
 bool
+mpd_send_seek_current(struct mpd_connection *connection,
+                     float t, bool relative)
+{
+       char ts[32];
+       if (relative)
+               snprintf(ts, sizeof(ts), "%+.3f", t);
+       else
+               snprintf(ts, sizeof(ts), "%.3f", t);
+
+       return mpd_send_command(connection, "seekcur", ts, NULL);
+}
+
+bool
+mpd_run_seek_current(struct mpd_connection *connection,
+                    float t, bool relative)
+{
+       return mpd_run_check(connection) &&
+               mpd_send_seek_current(connection, t, relative) &&
+               mpd_response_finish(connection);
+}
+
+bool
 mpd_send_repeat(struct mpd_connection *connection, bool mode)
 {
        return mpd_send_int_command(connection, "repeat", mode);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/resolver.c 
new/libmpdclient-2.15/src/resolver.c
--- old/libmpdclient-2.13/src/resolver.c        2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/src/resolver.c        2018-09-02 22:45:54.000000000 
+0200
@@ -29,6 +29,7 @@
 #include "resolver.h"
 #include "config.h"
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -78,14 +79,17 @@
 
        if (host[0] == '/' || host[0] == '@') {
 #ifndef _WIN32
-               size_t path_length = strlen(host);
-               if (path_length >= sizeof(resolver->saun.sun_path)) {
+               const bool is_abstract = *host == '@';
+               /* sun_path must be null-terminated unless it's an abstract
+                  socket */
+               const size_t path_length = strlen(host) + !is_abstract;
+               if (path_length > sizeof(resolver->saun.sun_path)) {
                        free(resolver);
                        return NULL;
                }
 
                resolver->saun.sun_family = AF_UNIX;
-               memcpy(resolver->saun.sun_path, host, path_length + 1);
+               memcpy(resolver->saun.sun_path, host, path_length);
 
                if (host[0] == '@')
                        /* abstract socket */
@@ -93,7 +97,8 @@
 
                resolver->current.family = PF_UNIX;
                resolver->current.protocol = 0;
-               resolver->current.addrlen = sizeof(resolver->saun);
+               resolver->current.addrlen = sizeof(resolver->saun)
+                       - sizeof(resolver->saun.sun_path) + path_length;
                resolver->current.addr = (const struct sockaddr 
*)&resolver->saun;
                resolver->type = TYPE_ONE;
 #else /* _WIN32 */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/search.c 
new/libmpdclient-2.15/src/search.c
--- old/libmpdclient-2.13/src/search.c  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/search.c  2018-09-02 22:45:54.000000000 +0200
@@ -273,6 +273,33 @@
 }
 
 bool
+mpd_search_add_expression(struct mpd_connection *connection,
+                         const char *expression)
+{
+       assert(connection != NULL);
+       assert(expression != NULL);
+
+       char *arg = mpd_sanitize_arg(expression);
+       if (arg == NULL) {
+               mpd_error_code(&connection->error, MPD_ERROR_OOM);
+               return false;
+       }
+
+       const size_t add_length = 2 + strlen(arg) + 1;
+
+       char *dest = mpd_search_prepare_append(connection, add_length);
+       if (dest == NULL) {
+               free(arg);
+               return false;
+       }
+
+       sprintf(dest, " \"%s\"", arg);
+
+       free(arg);
+       return true;
+}
+
+bool
 mpd_search_add_group_tag(struct mpd_connection *connection,
                         enum mpd_tag_type type)
 {
@@ -288,24 +315,32 @@
 }
 
 bool
-mpd_search_add_sort_tag(struct mpd_connection *connection,
-                       enum mpd_tag_type type, bool reserved)
+mpd_search_add_sort_name(struct mpd_connection *connection,
+                        const char *name, bool descending)
 {
        assert(connection != NULL);
-       assert(!reserved);
-
-       (void)reserved;
 
        const size_t size = 64;
        char *dest = mpd_search_prepare_append(connection, size);
        if (dest == NULL)
                return false;
 
-       snprintf(dest, size, " sort %s", mpd_tag_name(type));
+       snprintf(dest, size, " sort %s%s",
+                descending ? "-" : "",
+                name);
        return true;
 }
 
 bool
+mpd_search_add_sort_tag(struct mpd_connection *connection,
+                       enum mpd_tag_type type, bool descending)
+{
+       return mpd_search_add_sort_name(connection,
+                                       mpd_tag_name(type),
+                                       descending);
+}
+
+bool
 mpd_search_add_window(struct mpd_connection *connection,
                      unsigned start, unsigned end)
 {
@@ -350,10 +385,8 @@
 {
        assert(connection != NULL);
 
-       if (connection->request != NULL) {
-               free(connection->request);
-               connection->request = NULL;
-       }
+       free(connection->request);
+       connection->request = NULL;
 }
 
 struct mpd_pair *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/send.c 
new/libmpdclient-2.15/src/send.c
--- old/libmpdclient-2.13/src/send.c    2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/send.c    2018-09-02 22:45:54.000000000 +0200
@@ -40,6 +40,7 @@
 enum {
        INTLEN = (sizeof(int) * CHAR_BIT + 1) / 3 + 1,
        LONGLONGLEN = (sizeof(long long) * CHAR_BIT + 1) / 3 + 1,
+       FLOATLEN = LONGLONGLEN + 8,
 };
 
 static void
@@ -167,7 +168,7 @@
 mpd_send_float_command(struct mpd_connection *connection, const char *command,
                       float arg)
 {
-       char arg_string[INTLEN];
+       char arg_string[FLOATLEN];
 
        snprintf(arg_string, sizeof(arg_string), "%f", arg);
        return mpd_send_command(connection, command, arg_string, NULL);
@@ -177,7 +178,7 @@
 mpd_send_u_f_command(struct mpd_connection *connection, const char *command,
                     unsigned arg1, float arg2)
 {
-       char arg1_string[INTLEN], arg2_string[INTLEN];
+       char arg1_string[INTLEN], arg2_string[FLOATLEN];
 
        snprintf(arg1_string, sizeof(arg1_string), "%u", arg1);
        snprintf(arg2_string, sizeof(arg2_string), "%.3f", arg2);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/socket.c 
new/libmpdclient-2.15/src/socket.c
--- old/libmpdclient-2.13/src/socket.c  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/socket.c  2018-09-02 22:45:54.000000000 +0200
@@ -35,7 +35,6 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <fcntl.h>
-#include <unistd.h>
 
 #ifdef _WIN32
 #  include <winsock2.h>
@@ -48,6 +47,7 @@
 #  include <netdb.h>
 #  include <sys/un.h>
 #  include <errno.h>
+#  include <unistd.h>
 #endif
 
 #ifndef MSG_DONTWAIT
@@ -79,7 +79,7 @@
  * Wait for the socket to become writable.
  */
 static int
-mpd_socket_wait(unsigned fd, struct timeval *tv)
+mpd_socket_wait_writable(unsigned fd, struct timeval *tv)
 {
        fd_set fds;
        int ret;
@@ -88,7 +88,7 @@
                FD_ZERO(&fds);
                FD_SET(fd, &fds);
 
-               ret = select(fd + 1, NULL, &fds, &fds, tv);
+               ret = select(fd + 1, NULL, &fds, NULL, tv);
                if (ret > 0)
                        return 0;
 
@@ -108,7 +108,7 @@
        int s_err = 0;
        socklen_t s_err_size = sizeof(s_err);
 
-       ret = mpd_socket_wait(fd, tv);
+       ret = mpd_socket_wait_writable(fd, tv);
        if (ret < 0)
                return 0;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/song.c 
new/libmpdclient-2.15/src/song.c
--- old/libmpdclient-2.13/src/song.c    2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/song.c    2018-09-02 22:45:54.000000000 +0200
@@ -1,5 +1,5 @@
 /* libmpdclient
-   (c) 2003-2017 The Music Player Daemon Project
+   (c) 2003-2018 The Music Player Daemon Project
    This project's homepage is: http://www.musicpd.org
 
    Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,13 @@
 */
 
 #include <mpd/song.h>
+#include <mpd/audio_format.h>
 #include <mpd/pair.h>
 #include <mpd/recv.h>
 #include "internal.h"
 #include "iso8601.h"
 #include "uri.h"
+#include "iaf.h"
 
 #include <assert.h>
 #include <stdlib.h>
@@ -105,6 +107,11 @@
         */
        bool finished;
 #endif
+
+       /**
+        * The audio format as reported by MPD's decoder plugin.
+        */
+       struct mpd_audio_format audio_format;
 };
 
 static struct mpd_song *
@@ -138,6 +145,8 @@
        song->id = 0;
        song->prio = 0;
 
+       memset(&song->audio_format, 0, sizeof(song->audio_format));
+
 #ifndef NDEBUG
        song->finished = false;
 #endif
@@ -408,6 +417,14 @@
        return song->prio;
 }
 
+const struct mpd_audio_format *
+mpd_song_get_audio_format(const struct mpd_song *song)
+{
+       return !mpd_audio_format_is_empty(&song->audio_format)
+               ? &song->audio_format
+               : NULL;
+}
+
 struct mpd_song *
 mpd_song_begin(const struct mpd_pair *pair)
 {
@@ -455,6 +472,15 @@
                song->end = 0;
 }
 
+static void
+mpd_song_parse_audio_format(struct mpd_song *song, const char *value)
+{
+       assert(song != NULL);
+       assert(value != NULL);
+
+       mpd_parse_audio_format(&song->audio_format, value);
+}
+
 bool
 mpd_song_feed(struct mpd_song *song, const struct mpd_pair *pair)
 {
@@ -496,6 +522,8 @@
                mpd_song_set_id(song, atoi(pair->value));
        else if (strcmp(pair->name, "Prio") == 0)
                mpd_song_set_prio(song, atoi(pair->value));
+       else if (strcmp(pair->name, "Format") == 0)
+               mpd_song_parse_audio_format(song, pair->value);
 
        return true;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/status.c 
new/libmpdclient-2.15/src/status.c
--- old/libmpdclient-2.13/src/status.c  2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/status.c  2018-09-02 22:45:54.000000000 +0200
@@ -33,6 +33,7 @@
 #include <mpd/status.h>
 #include <mpd/pair.h>
 #include <mpd/audio_format.h>
+#include "iaf.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -192,52 +193,6 @@
                return MPD_STATE_UNKNOWN;
 }
 
-static void
-parse_audio_format(struct mpd_audio_format *audio_format, const char *p)
-{
-       char *endptr;
-
-       if (strncmp(p, "dsd", 3) == 0) {
-               /* allow format specifications such as "dsd64" which
-                  implies the sample rate */
-
-               unsigned long dsd = strtoul(p + 3, &endptr, 10);
-               if (endptr > p + 3 && *endptr == ':' &&
-                   dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
-                       audio_format->sample_rate = dsd * 44100 / 8;
-                       audio_format->bits = MPD_SAMPLE_FORMAT_DSD;
-
-                       p = endptr + 1;
-                       audio_format->channels = strtoul(p, NULL, 10);
-                       return;
-               }
-       }
-
-       audio_format->sample_rate = strtoul(p, &endptr, 10);
-       if (*endptr == ':') {
-               p = endptr + 1;
-
-               if (p[0] == 'f' && p[1] == ':') {
-                       audio_format->bits = MPD_SAMPLE_FORMAT_FLOAT;
-                       p += 2;
-               } else if (p[0] == 'd' && p[1] == 's' &&
-                          p[2] == 'd' && p[3] == ':') {
-                       audio_format->bits = MPD_SAMPLE_FORMAT_DSD;
-                       p += 4;
-               } else {
-                       audio_format->bits = strtoul(p, &endptr, 10);
-                       p = *endptr == ':' ? endptr + 1 : NULL;
-               }
-
-               audio_format->channels = p != NULL
-                       ? strtoul(p, NULL, 10)
-                       : 0;
-       } else {
-               audio_format->bits = 0;
-               audio_format->channels = 0;
-       }
-}
-
 void
 mpd_status_feed(struct mpd_status *status, const struct mpd_pair *pair)
 {
@@ -286,9 +241,7 @@
                if (status->elapsed_time == 0)
                        status->elapsed_time = status->elapsed_ms / 1000;
        } else if (strcmp(pair->name, "error") == 0) {
-               if (status->error != NULL)
-                       free(status->error);
-
+               free(status->error);
                status->error = strdup(pair->value);
        } else if (strcmp(pair->name, "xfade") == 0)
                status->crossfade = atoi(pair->value);
@@ -299,11 +252,11 @@
        else if (strcmp(pair->name, "updating_db") == 0)
                status->update_id = atoi(pair->value);
        else if (strcmp(pair->name, "audio") == 0)
-               parse_audio_format(&status->audio_format, pair->value);
+               mpd_parse_audio_format(&status->audio_format, pair->value);
 }
 
 void mpd_status_free(struct mpd_status * status) {
-       if (status->error) free(status->error);
+       free(status->error);
        free(status);
 }
 
@@ -423,9 +376,7 @@
 const struct mpd_audio_format *
 mpd_status_get_audio_format(const struct mpd_status *status)
 {
-       return status->audio_format.sample_rate > 0 ||
-               status->audio_format.bits > 0 ||
-               status->audio_format.channels > 0
+       return !mpd_audio_format_is_empty(&status->audio_format)
                ? &status->audio_format
                : NULL;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/src/sync.c 
new/libmpdclient-2.15/src/sync.c
--- old/libmpdclient-2.13/src/sync.c    2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/src/sync.c    2018-09-02 22:45:54.000000000 +0200
@@ -37,7 +37,6 @@
 #include <sys/select.h>
 #endif
 #include <fcntl.h>
-#include <unistd.h>
 
 static enum mpd_async_event
 mpd_sync_poll(struct mpd_async *async, struct timeval *tv)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/test/capture.c 
new/libmpdclient-2.15/test/capture.c
--- old/libmpdclient-2.13/test/capture.c        2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/test/capture.c        2018-09-02 22:45:54.000000000 
+0200
@@ -31,11 +31,18 @@
 #include <mpd/connection.h>
 #include <mpd/async.h>
 
-#include <sys/socket.h>
-#include <unistd.h>
 #include <stdio.h>
 #include <string.h>
 
+#ifdef _WIN32
+#  include <winsock2.h>
+#  include <basetsd.h> /* for SSIZE_T */
+typedef SSIZE_T ssize_t;
+#else
+#  include <sys/socket.h>
+#  include <unistd.h>
+#endif
+
 struct mpd_connection *
 test_capture_init(struct test_capture *tc)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/test/main.c 
new/libmpdclient-2.15/test/main.c
--- old/libmpdclient-2.13/test/main.c   2017-07-25 09:12:57.000000000 +0200
+++ new/libmpdclient-2.15/test/main.c   2018-09-02 22:45:54.000000000 +0200
@@ -39,7 +39,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdlib.h>
 
 #define BRIGHT 1
@@ -110,6 +109,14 @@
 }
 
 static void
+print_audio_format(const struct mpd_audio_format *audio_format)
+{
+       printf("sampleRate: %i\n", audio_format->sample_rate);
+       printf("bits: %i\n", audio_format->bits);
+       printf("channels: %i\n", audio_format->channels);
+}
+
+static void
 print_status(struct mpd_status *status)
 {
        const struct mpd_audio_format *audio_format;
@@ -132,11 +139,8 @@
        }
 
        audio_format = mpd_status_get_audio_format(status);
-       if (audio_format != NULL) {
-               printf("sampleRate: %i\n", audio_format->sample_rate);
-               printf("bits: %i\n", audio_format->bits);
-               printf("channels: %i\n", audio_format->channels);
-       }
+       if (audio_format != NULL)
+               print_audio_format(audio_format);
 }
 
 static void
@@ -167,6 +171,11 @@
        if (mpd_song_get_duration_ms(song) > 0)
                LOG_INFO("duration: %i", mpd_song_get_duration_ms(song));
 
+       const struct mpd_audio_format *audio_format =
+               mpd_song_get_audio_format(song);
+       if (audio_format != NULL)
+               print_audio_format(audio_format);
+
        LOG_INFO("pos: %u", mpd_song_get_pos(song));
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libmpdclient-2.13/test/t_commands.c 
new/libmpdclient-2.15/test/t_commands.c
--- old/libmpdclient-2.13/test/t_commands.c     2017-07-25 09:12:57.000000000 
+0200
+++ new/libmpdclient-2.15/test/t_commands.c     2018-09-02 22:45:54.000000000 
+0200
@@ -170,6 +170,32 @@
        ck_assert_str_eq(test_capture_receive(&capture), "search base \"foo\" 
sort Date window 7:9\n");
        abort_command(&capture, c);
 
+       /* check backslash escape */
+       ck_assert(mpd_search_db_songs(c, false));
+       ck_assert(mpd_search_add_tag_constraint(c, MPD_OPERATOR_DEFAULT,
+                                               MPD_TAG_ARTIST, "double quote: 
\" and backslash: \\"));
+       ck_assert(mpd_search_commit(c));
+
+       ck_assert_str_eq(test_capture_receive(&capture), "search Artist 
\"double quote: \\\" and backslash: \\\\\"\n");
+       abort_command(&capture, c);
+
+       mpd_connection_free(c);
+       test_capture_deinit(&capture);
+}
+END_TEST
+
+START_TEST(test_expression)
+{
+       struct test_capture capture;
+       struct mpd_connection *c = test_capture_init(&capture);
+
+       ck_assert(mpd_search_db_songs(c, true));
+       ck_assert(mpd_search_add_expression(c, "(Artist == \"Queen\")"));
+       ck_assert(mpd_search_commit(c));
+
+       ck_assert_str_eq(test_capture_receive(&capture), "find \"(Artist == 
\\\"Queen\\\")\"\n");
+       abort_command(&capture, c);
+
        mpd_connection_free(c);
        test_capture_deinit(&capture);
 }
@@ -238,6 +264,18 @@
        ck_assert_str_eq(test_capture_receive(&capture), "seekid \"2\" 
\"120.500\"\n");
        abort_command(&capture, c);
 
+       ck_assert(mpd_send_seek_current(c, 42, false));
+       ck_assert_str_eq(test_capture_receive(&capture), "seekcur 
\"42.000\"\n");
+       abort_command(&capture, c);
+
+       ck_assert(mpd_send_seek_current(c, 42, true));
+       ck_assert_str_eq(test_capture_receive(&capture), "seekcur 
\"+42.000\"\n");
+       abort_command(&capture, c);
+
+       ck_assert(mpd_send_seek_current(c, -42, false));
+       ck_assert_str_eq(test_capture_receive(&capture), "seekcur 
\"-42.000\"\n");
+       abort_command(&capture, c);
+
        mpd_connection_free(c);
        test_capture_deinit(&capture);
 }
@@ -262,6 +300,7 @@
 
        TCase *tc_search = tcase_create("search");
        tcase_add_test(tc_search, test_search);
+       tcase_add_test(tc_search, test_expression);
        tcase_add_test(tc_search, test_list);
        tcase_add_test(tc_search, test_count);
        suite_add_tcase(s, tc_search);


Reply via email to