From deacf28a1585f85fe3f5e8b66fc2ada772323c24 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 21 Jun 2009 12:59:07 +0200 Subject: [PATCH] connection: moved pair receiving code to recv.c --- Makefile.am | 2 + include/mpd/client.h | 1 + include/mpd/recv.h | 76 +++++++++++++++++++ src/connection.c | 137 ---------------------------------- src/recv.c | 172 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 137 deletions(-) create mode 100644 include/mpd/recv.h create mode 100644 src/recv.c diff --git a/Makefile.am b/Makefile.am index 4f00b79..20b3c69 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,7 @@ mpdinclude_HEADERS = \ include/mpd/list.h \ include/mpd/parser.h \ include/mpd/protocol.h \ + include/mpd/recv.h \ include/mpd/response.h \ include/mpd/run.h \ include/mpd/send.h \ @@ -47,6 +48,7 @@ src_libmpdclient_la_SOURCES = \ src/list.c \ src/parser.c \ src/quote.c src/quote.h \ + src/recv.c \ src/response.c \ src/run.c \ src/search.c \ diff --git a/include/mpd/client.h b/include/mpd/client.h index c7aebce..aa545eb 100644 --- a/include/mpd/client.h +++ b/include/mpd/client.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/include/mpd/recv.h b/include/mpd/recv.h new file mode 100644 index 0000000..fea5ee8 --- /dev/null +++ b/include/mpd/recv.h @@ -0,0 +1,76 @@ +/* libmpdclient + (c) 2003-2009 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_RECV_H +#define MPD_RECV_H + +struct mpd_pair; +struct mpd_connection; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Reads the next #mpd_pair from the server. Returns NULL if there + * are no more pairs. + * + * The caller is responsible for freeing the returned object with + * mpd_pair_free(). + */ +struct mpd_pair * +mpd_recv_pair(struct mpd_connection *connection); + +/** + * Same as mpd_recv_pair(), but discards all pairs not matching the + * specified name. + */ +struct mpd_pair * +mpd_recv_pair_named(struct mpd_connection *connection, const char *name); + +/** + * Similar to mpd_recv_pair_named(), but duplicates the string and + * frees the #mpd_pair object. The caller has to free the return + * value with free(). + */ +char * +mpd_recv_value_named(struct mpd_connection *connection, const char *name); + +/** + * Unreads a #mpd_pair. You may unread only the one pair you just got + * from mpd_recv_pair(). Unreading the "NULL" pair is allowed, to + * allow you to call mpd_recv_pair() again at the end of a response. + */ +void +mpd_enqueue_pair(struct mpd_connection *connection, struct mpd_pair *pair); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/connection.c b/src/connection.c index b820f22..41d95f4 100644 --- a/src/connection.c +++ b/src/connection.c @@ -285,140 +285,3 @@ mpd_cmp_server_version(const struct mpd_connection *connection, unsigned major, else return -1; } - -struct mpd_pair * -mpd_recv_pair(struct mpd_connection *connection) -{ - struct mpd_pair *pair; - char *line; - enum mpd_parser_result result; - const char *msg; - - if (mpd_error_is_defined(&connection->error)) - return NULL; - - if (connection->pair != PAIR_NONE) { - /* dequeue the pair from mpd_enqueue_pair() */ - pair = connection->pair; - connection->pair = PAIR_NONE; - return pair; - } - - - if (!connection->receiving || - (connection->sending_command_list && - connection->command_list_remaining > 0 && - connection->discrete_finished)) { - mpd_error_code(&connection->error, MPD_ERROR_STATE); - mpd_error_message(&connection->error, - "already done processing current command"); - return NULL; - } - - line = mpd_sync_recv_line(connection->async, &connection->timeout); - if (line == NULL) - return NULL; - - result = mpd_parser_feed(connection->parser, line); - switch (result) { - case MPD_PARSER_MALFORMED: - mpd_error_code(&connection->error, MPD_ERROR_MALFORMED); - mpd_error_printf(&connection->error, - "Failed to parse MPD response"); - return NULL; - - case MPD_PARSER_SUCCESS: - if (!mpd_parser_is_discrete(connection->parser)) { - if (connection->sending_command_list && - connection->command_list_remaining > 0) { - mpd_error_code(&connection->error, - MPD_ERROR_MALFORMED); - mpd_error_message(&connection->error, - "expected more list_OK's"); - connection->command_list_remaining = 0; - } - - connection->receiving = false; - connection->discrete_finished = false; - } else { - if (!connection->sending_command_list || - connection->command_list_remaining == 0) { - mpd_error_code(&connection->error, - MPD_ERROR_MALFORMED); - mpd_error_message(&connection->error, - "got an unexpected list_OK"); - } else { - connection->discrete_finished = true; - --connection->command_list_remaining; - } - } - - return NULL; - - case MPD_PARSER_ERROR: - connection->receiving = false; - mpd_error_ack(&connection->error, - mpd_parser_get_ack(connection->parser), - mpd_parser_get_at(connection->parser)); - msg = mpd_parser_get_message(connection->parser); - if (msg == NULL) - msg = "Unspecified MPD error"; - mpd_error_message(&connection->error, msg); - return NULL; - - case MPD_PARSER_PAIR: - pair = mpd_pair_new(mpd_parser_get_name(connection->parser), - mpd_parser_get_value(connection->parser)); - if (pair == NULL) - mpd_error_code(&connection->error, MPD_ERROR_OOM); - return pair; - } - - /* unreachable */ - assert(false); - return NULL; -} - -struct mpd_pair * -mpd_recv_pair_named(struct mpd_connection *connection, const char *name) -{ - struct mpd_pair *pair; - - while ((pair = mpd_recv_pair(connection)) != NULL) { - if (strcmp(pair->name, name) == 0) - return pair; - - mpd_pair_free(pair); - } - - return NULL; -} - -char * -mpd_recv_value_named(struct mpd_connection *connection, const char *name) -{ - struct mpd_pair *pair; - char *value; - - pair = mpd_recv_pair_named(connection, name); - if (pair == NULL) - return NULL; - - value = strdup(pair->value); - mpd_pair_free(pair); - - if (value == NULL) - mpd_error_code(&connection->error, MPD_ERROR_OOM); - - return value; -} - -void -mpd_enqueue_pair(struct mpd_connection *connection, struct mpd_pair *pair) -{ - assert(connection != NULL); - assert(pair == NULL || (pair->name != NULL && pair->value != NULL)); - assert(connection->pair == PAIR_NONE); - - connection->pair = pair; -} diff --git a/src/recv.c b/src/recv.c new file mode 100644 index 0000000..2a271a0 --- /dev/null +++ b/src/recv.c @@ -0,0 +1,172 @@ +/* libmpdclient + (c) 2003-2009 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 +#include +#include +#include "internal.h" +#include "sync.h" + +#include + +struct mpd_pair * +mpd_recv_pair(struct mpd_connection *connection) +{ + struct mpd_pair *pair; + char *line; + enum mpd_parser_result result; + const char *msg; + + if (mpd_error_is_defined(&connection->error)) + return NULL; + + if (connection->pair != PAIR_NONE) { + /* dequeue the pair from mpd_enqueue_pair() */ + pair = connection->pair; + connection->pair = PAIR_NONE; + return pair; + } + + + if (!connection->receiving || + (connection->sending_command_list && + connection->command_list_remaining > 0 && + connection->discrete_finished)) { + mpd_error_code(&connection->error, MPD_ERROR_STATE); + mpd_error_message(&connection->error, + "already done processing current command"); + return NULL; + } + + line = mpd_sync_recv_line(connection->async, &connection->timeout); + if (line == NULL) + return NULL; + + result = mpd_parser_feed(connection->parser, line); + switch (result) { + case MPD_PARSER_MALFORMED: + mpd_error_code(&connection->error, MPD_ERROR_MALFORMED); + mpd_error_printf(&connection->error, + "Failed to parse MPD response"); + return NULL; + + case MPD_PARSER_SUCCESS: + if (!mpd_parser_is_discrete(connection->parser)) { + if (connection->sending_command_list && + connection->command_list_remaining > 0) { + mpd_error_code(&connection->error, + MPD_ERROR_MALFORMED); + mpd_error_message(&connection->error, + "expected more list_OK's"); + connection->command_list_remaining = 0; + } + + connection->receiving = false; + connection->discrete_finished = false; + } else { + if (!connection->sending_command_list || + connection->command_list_remaining == 0) { + mpd_error_code(&connection->error, + MPD_ERROR_MALFORMED); + mpd_error_message(&connection->error, + "got an unexpected list_OK"); + } else { + connection->discrete_finished = true; + --connection->command_list_remaining; + } + } + + return NULL; + + case MPD_PARSER_ERROR: + connection->receiving = false; + mpd_error_ack(&connection->error, + mpd_parser_get_ack(connection->parser), + mpd_parser_get_at(connection->parser)); + msg = mpd_parser_get_message(connection->parser); + if (msg == NULL) + msg = "Unspecified MPD error"; + mpd_error_message(&connection->error, msg); + return NULL; + + case MPD_PARSER_PAIR: + pair = mpd_pair_new(mpd_parser_get_name(connection->parser), + mpd_parser_get_value(connection->parser)); + if (pair == NULL) + mpd_error_code(&connection->error, MPD_ERROR_OOM); + return pair; + } + + /* unreachable */ + assert(false); + return NULL; +} + +struct mpd_pair * +mpd_recv_pair_named(struct mpd_connection *connection, const char *name) +{ + struct mpd_pair *pair; + + while ((pair = mpd_recv_pair(connection)) != NULL) { + if (strcmp(pair->name, name) == 0) + return pair; + + mpd_pair_free(pair); + } + + return NULL; +} + +char * +mpd_recv_value_named(struct mpd_connection *connection, const char *name) +{ + struct mpd_pair *pair; + char *value; + + pair = mpd_recv_pair_named(connection, name); + if (pair == NULL) + return NULL; + + value = strdup(pair->value); + mpd_pair_free(pair); + + if (value == NULL) + mpd_error_code(&connection->error, MPD_ERROR_OOM); + + return value; +} + +void +mpd_enqueue_pair(struct mpd_connection *connection, struct mpd_pair *pair) +{ + assert(connection != NULL); + assert(pair == NULL || (pair->name != NULL && pair->value != NULL)); + assert(connection->pair == PAIR_NONE); + + connection->pair = pair; +}