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);