| File: | build-analysis/../src/clients/lib/xmmsclient/result.c |
| Warning: | line 576, column 6 Use of memory after it is freed |
| 1 | /* XMMS2 - X Music Multiplexer System | |||||
| 2 | * Copyright (C) 2003-2017 XMMS2 Team | |||||
| 3 | * | |||||
| 4 | * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! | |||||
| 5 | * | |||||
| 6 | * This library is free software; you can redistribute it and/or | |||||
| 7 | * modify it under the terms of the GNU Lesser General Public | |||||
| 8 | * License as published by the Free Software Foundation; either | |||||
| 9 | * version 2.1 of the License, or (at your option) any later version. | |||||
| 10 | * | |||||
| 11 | * This library is distributed in the hope that it will be useful, | |||||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| 14 | * Lesser General Public License for more details. | |||||
| 15 | */ | |||||
| 16 | ||||||
| 17 | #include <stdio.h> | |||||
| 18 | #include <stdlib.h> | |||||
| 19 | #include <sys/types.h> | |||||
| 20 | #include <string.h> | |||||
| 21 | #include <ctype.h> | |||||
| 22 | ||||||
| 23 | #include <sys/types.h> | |||||
| 24 | ||||||
| 25 | #include <xmmsclient/xmmsclient.h> | |||||
| 26 | #include <xmmsclientpriv/xmmsclient.h> | |||||
| 27 | #include <xmmsclientpriv/xmmsclient_ipc.h> | |||||
| 28 | #include <xmmsc/xmmsc_idnumbers.h> | |||||
| 29 | #include <xmmsc/xmmsc_errorcodes.h> | |||||
| 30 | #include <xmmsc/xmmsc_stdint.h> | |||||
| 31 | #include <xmmsc/xmmsc_stdbool.h> | |||||
| 32 | #include <xmmscpriv/xmmsv_c2c.h> | |||||
| 33 | ||||||
| 34 | typedef enum { | |||||
| 35 | XMMSC_RESULT_CALLBACK_DEFAULT, | |||||
| 36 | XMMSC_RESULT_CALLBACK_RAW, | |||||
| 37 | XMMSC_RESULT_CALLBACK_C2C | |||||
| 38 | } xmmsc_result_callback_type_t; | |||||
| 39 | ||||||
| 40 | typedef struct xmmsc_result_callback_St { | |||||
| 41 | xmmsc_result_callback_type_t type; | |||||
| 42 | xmmsc_result_notifier_t func; | |||||
| 43 | ||||||
| 44 | void *user_data; | |||||
| 45 | xmmsc_user_data_free_func_t free_func; | |||||
| 46 | } xmmsc_result_callback_t; | |||||
| 47 | ||||||
| 48 | static void xmmsc_result_restart (xmmsc_result_t *res); | |||||
| 49 | static void xmmsc_result_notifier_add (xmmsc_result_t *res, xmmsc_result_callback_t *cb); | |||||
| 50 | static void xmmsc_result_notifier_remove (xmmsc_result_t *res, x_list_t *node); | |||||
| 51 | static void xmmsc_result_notifier_delete (xmmsc_result_t *res, x_list_t *node); | |||||
| 52 | static void xmmsc_result_notifier_delete_all (xmmsc_result_t *res); | |||||
| 53 | ||||||
| 54 | static xmmsc_result_callback_t *xmmsc_result_callback_new_default (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f); | |||||
| 55 | static xmmsc_result_callback_t *xmmsc_result_callback_new_raw (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f); | |||||
| 56 | static xmmsc_result_callback_t *xmmsc_result_callback_new_c2c (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f); | |||||
| 57 | ||||||
| 58 | struct xmmsc_result_St { | |||||
| 59 | xmmsc_connection_t *c; | |||||
| 60 | ||||||
| 61 | /** refcounting */ | |||||
| 62 | int ref; | |||||
| 63 | ||||||
| 64 | xmmsc_result_type_t type; | |||||
| 65 | ||||||
| 66 | /** notifiers */ | |||||
| 67 | x_list_t *notifiers; | |||||
| 68 | ||||||
| 69 | xmmsc_ipc_t *ipc; | |||||
| 70 | ||||||
| 71 | bool_Bool parsed; | |||||
| 72 | bool_Bool is_c2c; | |||||
| 73 | ||||||
| 74 | uint32_t cookie; | |||||
| 75 | uint32_t restart_signal; | |||||
| 76 | ||||||
| 77 | xmmsv_t *data; | |||||
| 78 | ||||||
| 79 | xmmsc_visualization_t *visc; | |||||
| 80 | }; | |||||
| 81 | ||||||
| 82 | /** | |||||
| 83 | * @defgroup Result Result | |||||
| 84 | * @brief Result manipulation and error handling | |||||
| 85 | * @ingroup XMMSClient | |||||
| 86 | * | |||||
| 87 | * Each command to the server will return a #xmmsc_result_t | |||||
| 88 | * to the programmer. This object will be used to see the results | |||||
| 89 | * off the call. It will handle errors and the results. | |||||
| 90 | * | |||||
| 91 | * results could be used in both sync and async fashions. Here | |||||
| 92 | * is a sync example: | |||||
| 93 | * @code | |||||
| 94 | * xmmsc_result_t *res; | |||||
| 95 | * xmmsv_t *val; | |||||
| 96 | * uint32_t id; | |||||
| 97 | * res = xmmsc_playback_get_current_id (connection); | |||||
| 98 | * xmmsc_result_wait (res); | |||||
| 99 | * if (!val = xmmsc_result_get_value (res)) { | |||||
| 100 | * printf ("error: failed to retrieve value!"); | |||||
| 101 | * } | |||||
| 102 | * if (xmmsv_is_error (val)) { | |||||
| 103 | * printf ("error: %s", xmmsv_get_error (val)); | |||||
| 104 | * } | |||||
| 105 | * xmmsv_get_uint (val, &id); | |||||
| 106 | * xmmsc_result_unref (res); | |||||
| 107 | * printf ("current id is: %d", id); | |||||
| 108 | * @endcode | |||||
| 109 | * | |||||
| 110 | * an async example is a bit more complex... | |||||
| 111 | * @code | |||||
| 112 | * static void handler (xmmsv_t *val, void *userdata) { | |||||
| 113 | * uint32_t id; | |||||
| 114 | * if (xmmsv_is_error (val)) { | |||||
| 115 | * printf ("error: %s", xmmsv_get_error (val)); | |||||
| 116 | * } | |||||
| 117 | * xmmsv_get_uint (val, &id); | |||||
| 118 | * printf ("current id is: %d", id); | |||||
| 119 | * } | |||||
| 120 | * | |||||
| 121 | * int main () { | |||||
| 122 | * // Connect blah blah ... | |||||
| 123 | * xmmsc_result_t *res; | |||||
| 124 | * res = xmmsc_playback_get_current_id (connection); | |||||
| 125 | * xmmsc_result_notifier_set (res, handler); | |||||
| 126 | * xmmsc_result_unref (res); | |||||
| 127 | * } | |||||
| 128 | * @endcode | |||||
| 129 | * When the answer arrives handler will be called. with the resulting #xmmsv_t | |||||
| 130 | * @{ | |||||
| 131 | **/ | |||||
| 132 | ||||||
| 133 | /** | |||||
| 134 | * References the #xmmsc_result_t | |||||
| 135 | * | |||||
| 136 | * @param result the result to reference. | |||||
| 137 | * @return result | |||||
| 138 | */ | |||||
| 139 | xmmsc_result_t * | |||||
| 140 | xmmsc_result_ref (xmmsc_result_t *res) | |||||
| 141 | { | |||||
| 142 | x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 142); return (((void*)0)); }; | |||||
| 143 | res->ref++; | |||||
| 144 | ||||||
| 145 | return res; | |||||
| 146 | } | |||||
| 147 | ||||||
| 148 | /** | |||||
| 149 | * @todo Deallocate all types here | |||||
| 150 | */ | |||||
| 151 | static void | |||||
| 152 | xmmsc_result_free (xmmsc_result_t *res) | |||||
| 153 | { | |||||
| 154 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 154); return; }; | |||||
| 155 | ||||||
| 156 | /* Free memory! */ | |||||
| 157 | if (res->ipc) { | |||||
| 158 | xmmsc_ipc_result_unregister (res->ipc, res); | |||||
| 159 | } | |||||
| 160 | ||||||
| 161 | if (res->data) { | |||||
| 162 | xmmsv_unref (res->data); | |||||
| 163 | } | |||||
| 164 | ||||||
| 165 | xmmsc_result_notifier_delete_all (res); | |||||
| 166 | ||||||
| 167 | free (res); | |||||
| 168 | } | |||||
| 169 | ||||||
| 170 | /** | |||||
| 171 | * Get the class of the result (default, signal, broadcast). | |||||
| 172 | * @returns The class of the result of type #xmmsc_result_type_t | |||||
| 173 | */ | |||||
| 174 | xmmsc_result_type_t | |||||
| 175 | xmmsc_result_get_class (xmmsc_result_t *res) | |||||
| 176 | { | |||||
| 177 | x_return_val_if_fail (res, XMMSC_RESULT_CLASS_DEFAULT)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 177); return (XMMSC_RESULT_CLASS_DEFAULT); }; | |||||
| 178 | ||||||
| 179 | return res->type; | |||||
| 180 | } | |||||
| 181 | ||||||
| 182 | /** | |||||
| 183 | * Disconnect all notifiers for a signal or a broadcast result. | |||||
| 184 | * @param res The result to disconnect, must be of class signal or broadcast. | |||||
| 185 | */ | |||||
| 186 | void | |||||
| 187 | xmmsc_result_disconnect (xmmsc_result_t *res) | |||||
| 188 | { | |||||
| 189 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 189); return; }; | |||||
| 190 | ||||||
| 191 | switch (res->type) { | |||||
| 192 | case XMMSC_RESULT_CLASS_SIGNAL: | |||||
| 193 | case XMMSC_RESULT_CLASS_BROADCAST: | |||||
| 194 | case XMMSC_RESULT_CLASS_DEFAULT: | |||||
| 195 | xmmsc_result_notifier_delete_all (res); | |||||
| 196 | break; | |||||
| 197 | default: | |||||
| 198 | x_api_error_if (1, "invalid result type",)if (1) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "%s was called %s" , __FUNCTION__, ("invalid result type")); return ; }; | |||||
| 199 | } | |||||
| 200 | } | |||||
| 201 | ||||||
| 202 | static void | |||||
| 203 | xmmsc_result_restart (xmmsc_result_t *res) | |||||
| 204 | { | |||||
| 205 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 205); return; }; | |||||
| 206 | x_return_if_fail (res->c)if (!(res->c)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "res->c", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 206); return; }; | |||||
| 207 | ||||||
| 208 | if (res->type != XMMSC_RESULT_CLASS_SIGNAL) { | |||||
| 209 | x_api_warning ("result is not restartable")xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "%s was called %s" , __FUNCTION__, ("result is not restartable")); | |||||
| 210 | return; | |||||
| 211 | } | |||||
| 212 | ||||||
| 213 | res->cookie = xmmsc_write_signal_msg (res->c, res->restart_signal); | |||||
| 214 | } | |||||
| 215 | ||||||
| 216 | static bool_Bool | |||||
| 217 | xmmsc_result_parse_msg (xmmsc_result_t *res, xmms_ipc_msg_t *msg) | |||||
| 218 | { | |||||
| 219 | if (xmms_ipc_msg_get_cmd (msg) == XMMS_IPC_COMMAND_ERROR) { | |||||
| 220 | /* If special error msg, extract the error and save in result */ | |||||
| 221 | const char *errstr; | |||||
| 222 | xmmsv_t *error; | |||||
| 223 | ||||||
| 224 | if (!xmms_ipc_msg_get_value (msg, &error)) { | |||||
| 225 | xmmsc_result_seterror (res, "No error value!"); | |||||
| 226 | } else { | |||||
| 227 | if (!xmmsv_get_error (error, &errstr)) { | |||||
| 228 | xmmsc_result_seterror (res, "No error message!"); | |||||
| 229 | } else { | |||||
| 230 | xmmsc_result_seterror (res, errstr); | |||||
| 231 | } | |||||
| 232 | ||||||
| 233 | xmmsv_unref (error); | |||||
| 234 | } | |||||
| 235 | ||||||
| 236 | res->parsed = true1; | |||||
| 237 | return true1; | |||||
| 238 | } else if (xmms_ipc_msg_get_value (msg, &res->data)) { | |||||
| 239 | /* Expected message data retrieved! */ | |||||
| 240 | res->parsed = true1; | |||||
| 241 | return true1; | |||||
| 242 | } else { | |||||
| 243 | /* FIXME: shouldn't parsed be false then? */ | |||||
| 244 | return false0; | |||||
| 245 | } | |||||
| 246 | } | |||||
| 247 | ||||||
| 248 | ||||||
| 249 | /** | |||||
| 250 | * return the cookie of a resultset. | |||||
| 251 | */ | |||||
| 252 | uint32_t | |||||
| 253 | xmmsc_result_cookie_get (xmmsc_result_t *res) | |||||
| 254 | { | |||||
| 255 | x_return_val_if_fail (res, 0)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 255); return (0); }; | |||||
| 256 | ||||||
| 257 | return res->cookie; | |||||
| 258 | } | |||||
| 259 | ||||||
| 260 | /** | |||||
| 261 | * Set a result to be a client-to-client result. | |||||
| 262 | */ | |||||
| 263 | void | |||||
| 264 | xmmsc_result_c2c_set (xmmsc_result_t *res) | |||||
| 265 | { | |||||
| 266 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 266); return; }; | |||||
| 267 | ||||||
| 268 | res->is_c2c = true1; | |||||
| 269 | } | |||||
| 270 | ||||||
| 271 | void | |||||
| 272 | xmmsc_result_visc_set (xmmsc_result_t *res, xmmsc_visualization_t *visc) | |||||
| 273 | { | |||||
| 274 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 274); return; }; | |||||
| 275 | x_return_if_fail (!res->visc)if (!(!res->visc)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "!res->visc", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 275); return; }; | |||||
| 276 | res->visc = visc; | |||||
| 277 | } | |||||
| 278 | ||||||
| 279 | xmmsc_visualization_t * | |||||
| 280 | xmmsc_result_visc_get (xmmsc_result_t *res) | |||||
| 281 | { | |||||
| 282 | x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 282); return (((void*)0)); }; | |||||
| 283 | x_return_val_if_fail (res->visc, NULL)if (!(res->visc)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "res->visc", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 283); return (((void *)0)); }; | |||||
| 284 | return res->visc; | |||||
| 285 | } | |||||
| 286 | ||||||
| 287 | xmmsc_connection_t * | |||||
| 288 | xmmsc_result_get_connection (xmmsc_result_t *res) | |||||
| 289 | { | |||||
| 290 | x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 290); return (((void*)0)); }; | |||||
| 291 | x_return_val_if_fail (res->c, NULL)if (!(res->c)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "res->c", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 291); return (((void *)0)); }; | |||||
| 292 | return res->c; | |||||
| 293 | } | |||||
| 294 | ||||||
| 295 | /** | |||||
| 296 | * Decreases the references for the #xmmsc_result_t | |||||
| 297 | * When the number of references reaches 0 it will | |||||
| 298 | * be freed. And thus all data you extracted from it | |||||
| 299 | * will be deallocated. | |||||
| 300 | */ | |||||
| 301 | ||||||
| 302 | void | |||||
| 303 | xmmsc_result_unref (xmmsc_result_t *res) | |||||
| 304 | { | |||||
| 305 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 305); return; }; | |||||
| 306 | x_api_error_if (res->ref < 1, "with a freed result",)if (res->ref < 1) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "%s was called %s", __FUNCTION__, ("with a freed result")); return ; }; | |||||
| 307 | ||||||
| 308 | res->ref--; | |||||
| 309 | if (res->ref == 0) { | |||||
| 310 | xmmsc_result_free (res); | |||||
| 311 | } | |||||
| 312 | } | |||||
| 313 | ||||||
| 314 | /* Macro magic to define the xmmsc_result_*_notifier_set. */ | |||||
| 315 | #define GEN_RESULT_NOTIFIER_SET_FUNC(type)void xmmsc_result_notifier_set_type (xmmsc_result_t *res, xmmsc_result_notifier_t func, void *user_data) { xmmsc_result_notifier_set_type_full (res, func, user_data, ((void*)0)); } \ | |||||
| 316 | void \ | |||||
| 317 | xmmsc_result_notifier_set_##type (xmmsc_result_t *res, \ | |||||
| 318 | xmmsc_result_notifier_t func, \ | |||||
| 319 | void *user_data) \ | |||||
| 320 | { \ | |||||
| 321 | xmmsc_result_notifier_set_##type##_full (res, func, user_data, NULL((void*)0)); \ | |||||
| 322 | } | |||||
| 323 | ||||||
| 324 | /* And more macro magic to define the xmmsc_result_*_notifier_set_full. */ | |||||
| 325 | #define GEN_RESULT_NOTIFIER_SET_FULL_FUNC(type)void xmmsc_result_notifier_set_type_full (xmmsc_result_t *res , xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 325); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 325); return; }; cb = xmmsc_result_callback_new_type (func, user_data, free_func); xmmsc_result_notifier_add (res, cb); } \ | |||||
| 326 | void \ | |||||
| 327 | xmmsc_result_notifier_set_##type##_full (xmmsc_result_t *res, \ | |||||
| 328 | xmmsc_result_notifier_t func, \ | |||||
| 329 | void *user_data, \ | |||||
| 330 | xmmsc_user_data_free_func_t free_func) \ | |||||
| 331 | { \ | |||||
| 332 | xmmsc_result_callback_t *cb; \ | |||||
| 333 | \ | |||||
| 334 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 334); return; }; \ | |||||
| 335 | x_return_if_fail (func)if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 335); return; }; \ | |||||
| 336 | \ | |||||
| 337 | cb = xmmsc_result_callback_new_##type (func, user_data, free_func); \ | |||||
| 338 | xmmsc_result_notifier_add (res, cb); \ | |||||
| 339 | } | |||||
| 340 | ||||||
| 341 | /** | |||||
| 342 | * Set up a default callback for the result retrieval. This callback | |||||
| 343 | * will be called when the answer arrives. | |||||
| 344 | * The callback receives the value as sent by the server or another | |||||
| 345 | * client, that is, for c2c messages only the payload is passed to the | |||||
| 346 | * callback. | |||||
| 347 | * @param res a #xmmsc_result_t that you got from a command dispatcher. | |||||
| 348 | * @param func the function that should be called when we receive the answer | |||||
| 349 | * @param user_data optional user data to the callback | |||||
| 350 | */ | |||||
| 351 | ||||||
| 352 | GEN_RESULT_NOTIFIER_SET_FUNC (default)void xmmsc_result_notifier_set_default (xmmsc_result_t *res, xmmsc_result_notifier_t func, void *user_data) { xmmsc_result_notifier_set_default_full (res, func, user_data, ((void*)0)); } | |||||
| 353 | ||||||
| 354 | /** | |||||
| 355 | * Set up a default callback for the result retrieval. This callback | |||||
| 356 | * will be called when the answer arrives. This function differs from | |||||
| 357 | * xmmsc_result_default_notifier_set in the additional free_func parameter, | |||||
| 358 | * which allows to pass a pointer to a function which will be called | |||||
| 359 | * to free the user_data when needed. | |||||
| 360 | * @param res a #xmmsc_result_t that you got from a command dispatcher. | |||||
| 361 | * @param func the function that should be called when we receive the answer | |||||
| 362 | * @param user_data optional user data to the callback | |||||
| 363 | * @param free_func optional function that should be called to free the user_data | |||||
| 364 | */ | |||||
| 365 | ||||||
| 366 | GEN_RESULT_NOTIFIER_SET_FULL_FUNC (default)void xmmsc_result_notifier_set_default_full (xmmsc_result_t * res, xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 366); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 366); return; }; cb = xmmsc_result_callback_new_default (func , user_data, free_func); xmmsc_result_notifier_add (res, cb); } | |||||
| 367 | ||||||
| 368 | /** | |||||
| 369 | * Set up a raw callback for the result retrieval. This callback | |||||
| 370 | * will be called when the answer arrives. | |||||
| 371 | * The client receives the value sent by the server or, for | |||||
| 372 | * client-to-client messages, the full message, whose fields can | |||||
| 373 | * be extracted with the appropriate functions. | |||||
| 374 | * @param res a #xmmsc_result_t that you got from a command dispatcher. | |||||
| 375 | * @param func the function that should be called when we receive the answer | |||||
| 376 | * @param user_data optional user data to the callback | |||||
| 377 | * | |||||
| 378 | * \sa xmmsv_c2c_message_get_payload and others. | |||||
| 379 | */ | |||||
| 380 | ||||||
| 381 | GEN_RESULT_NOTIFIER_SET_FUNC (raw)void xmmsc_result_notifier_set_raw (xmmsc_result_t *res, xmmsc_result_notifier_t func, void *user_data) { xmmsc_result_notifier_set_raw_full ( res, func, user_data, ((void*)0)); } | |||||
| 382 | ||||||
| 383 | /** | |||||
| 384 | * Set up a raw callback for the result retrieval. This callback | |||||
| 385 | * will be called when the answer arrives. This function differs from | |||||
| 386 | * xmmsc_result_raw_notifier_set in the additional free_func parameter, | |||||
| 387 | * which allows to pass a pointer to a function which will be called | |||||
| 388 | * to free the user_data when needed. | |||||
| 389 | * @param res a #xmmsc_result_t that you got from a command dispatcher. | |||||
| 390 | * @param func the function that should be called when we receive the answer | |||||
| 391 | * @param user_data optional user data to the callback | |||||
| 392 | * @param free_func optional function that should be called to free the user_data | |||||
| 393 | */ | |||||
| 394 | ||||||
| 395 | GEN_RESULT_NOTIFIER_SET_FULL_FUNC (raw)void xmmsc_result_notifier_set_raw_full (xmmsc_result_t *res, xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 395); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 395); return; }; cb = xmmsc_result_callback_new_raw (func, user_data , free_func); xmmsc_result_notifier_add (res, cb); } | |||||
| 396 | ||||||
| 397 | /** | |||||
| 398 | * Set up a c2c callback for the result retrieval. This callback | |||||
| 399 | * will be called when the answer arrives. | |||||
| 400 | * This callback always receives values formatted as client-to-client | |||||
| 401 | * messages, whose fields can be extracted with the appropriate functions. | |||||
| 402 | * For values sent by the server, the sender id and message id fields | |||||
| 403 | * will be zero. | |||||
| 404 | * @param res a #xmmsc_result_t that you got from a command dispatcher. | |||||
| 405 | * @param func the function that should be called when we receive the answer | |||||
| 406 | * @param user_data optional user data to the callback | |||||
| 407 | * | |||||
| 408 | * \sa xmmsv_c2c_message_get_payload and others. | |||||
| 409 | */ | |||||
| 410 | ||||||
| 411 | GEN_RESULT_NOTIFIER_SET_FUNC (c2c)void xmmsc_result_notifier_set_c2c (xmmsc_result_t *res, xmmsc_result_notifier_t func, void *user_data) { xmmsc_result_notifier_set_c2c_full ( res, func, user_data, ((void*)0)); } | |||||
| 412 | ||||||
| 413 | /** | |||||
| 414 | * Set up a c2c callback for the result retrieval. This callback | |||||
| 415 | * will be called when the answer arrives. This function differs from | |||||
| 416 | * xmmsc_result_c2c_notifier_set in the additional free_func parameter, | |||||
| 417 | * which allows to pass a pointer to a function which will be called | |||||
| 418 | * to free the user_data when needed. | |||||
| 419 | * @param res a #xmmsc_result_t that you got from a command dispatcher. | |||||
| 420 | * @param func the function that should be called when we receive the answer | |||||
| 421 | * @param user_data optional user data to the callback | |||||
| 422 | * @param free_func optional function that should be called to free the user_data | |||||
| 423 | */ | |||||
| 424 | ||||||
| 425 | GEN_RESULT_NOTIFIER_SET_FULL_FUNC (c2c)void xmmsc_result_notifier_set_c2c_full (xmmsc_result_t *res, xmmsc_result_notifier_t func, void *user_data, xmmsc_user_data_free_func_t free_func) { xmmsc_result_callback_t *cb; if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 425); return; }; if (!(func)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "func", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 425); return; }; cb = xmmsc_result_callback_new_c2c (func, user_data , free_func); xmmsc_result_notifier_add (res, cb); } | |||||
| 426 | ||||||
| 427 | /** | |||||
| 428 | * Block for the reply. In a synchronous application this | |||||
| 429 | * can be used to wait for the result. Will return when | |||||
| 430 | * the server replyed. | |||||
| 431 | */ | |||||
| 432 | ||||||
| 433 | void | |||||
| 434 | xmmsc_result_wait (xmmsc_result_t *res) | |||||
| 435 | { | |||||
| 436 | const char *err = NULL((void*)0); | |||||
| 437 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 437); return; }; | |||||
| 438 | x_return_if_fail (res->ipc)if (!(res->ipc)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "res->ipc", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 438); return; }; | |||||
| 439 | ||||||
| 440 | while (!res->parsed && !(err = xmmsc_ipc_error_get (res->ipc))) { | |||||
| 441 | xmmsc_ipc_wait_for_event (res->ipc, 5); | |||||
| 442 | } | |||||
| 443 | ||||||
| 444 | if (err) { | |||||
| 445 | /* FIXME: xmmsv_unref (res->data) or not allocated ? */ | |||||
| 446 | res->data = xmmsv_new_error (err); | |||||
| 447 | } | |||||
| 448 | } | |||||
| 449 | ||||||
| 450 | /** | |||||
| 451 | * @defgroup ResultValueRetrieval ResultValueRetrieval | |||||
| 452 | * @ingroup Result | |||||
| 453 | * @brief Explains how you can retrive values from a #xmmsc_result_t | |||||
| 454 | * @{ | |||||
| 455 | */ | |||||
| 456 | ||||||
| 457 | /** | |||||
| 458 | * Get the value from a result. The reference is still owned by the | |||||
| 459 | * result. | |||||
| 460 | * | |||||
| 461 | * @param res a #xmmsc_result_t containing the value. | |||||
| 462 | * @returns A borrowed reference to the value received by the result. | |||||
| 463 | */ | |||||
| 464 | xmmsv_t * | |||||
| 465 | xmmsc_result_get_value (xmmsc_result_t *res) | |||||
| 466 | { | |||||
| 467 | x_return_val_if_fail (res, NULL)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 467); return (((void*)0)); }; | |||||
| 468 | x_return_val_if_fail (res->parsed, NULL)if (!(res->parsed)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "res->parsed", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 468); return (((void *)0)); }; | |||||
| 469 | ||||||
| 470 | return res->data; | |||||
| 471 | } | |||||
| 472 | ||||||
| 473 | /** @} */ | |||||
| 474 | ||||||
| 475 | /** @} */ | |||||
| 476 | ||||||
| 477 | /** @internal */ | |||||
| 478 | ||||||
| 479 | /* Kept as a proxy for external use */ | |||||
| 480 | void | |||||
| 481 | xmmsc_result_seterror (xmmsc_result_t *res, const char *errstr) | |||||
| 482 | { | |||||
| 483 | if (res->data) { | |||||
| 484 | xmmsv_unref (res->data); | |||||
| 485 | } | |||||
| 486 | res->data = xmmsv_new_error (errstr); | |||||
| 487 | } | |||||
| 488 | ||||||
| 489 | void | |||||
| 490 | xmmsc_result_restartable (xmmsc_result_t *res, uint32_t signalid) | |||||
| 491 | { | |||||
| 492 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 492); return; }; | |||||
| 493 | ||||||
| 494 | res->restart_signal = signalid; | |||||
| 495 | } | |||||
| 496 | ||||||
| 497 | /** | |||||
| 498 | * Helper for xmmsc_result_run. | |||||
| 499 | * Correctly calls a callback based on its type. | |||||
| 500 | * @param res The result that owns the callback | |||||
| 501 | * @param cb The callback to be called | |||||
| 502 | * @return The result of the callback | |||||
| 503 | */ | |||||
| 504 | static int | |||||
| 505 | xmmsc_result_run_callback (xmmsc_result_t *res, xmmsc_result_callback_t *cb) | |||||
| 506 | { | |||||
| 507 | int ret; | |||||
| 508 | xmmsv_t *val = NULL((void*)0); | |||||
| 509 | ||||||
| 510 | if (res->is_c2c && !xmmsv_is_error (res->data)) { | |||||
| 511 | if (cb->type == XMMSC_RESULT_CALLBACK_DEFAULT) { | |||||
| 512 | /* For default callbacks, pass the payload in c2c | |||||
| 513 | * messages. | |||||
| 514 | */ | |||||
| 515 | val = xmmsv_ref (xmmsv_c2c_message_get_payload (res->data)); | |||||
| 516 | } | |||||
| 517 | } else { | |||||
| 518 | if (cb->type == XMMSC_RESULT_CALLBACK_C2C) { | |||||
| 519 | /* For c2c callbacks and non-c2c messages, build a | |||||
| 520 | * message with pseudo c2c metadata. | |||||
| 521 | */ | |||||
| 522 | val = xmmsv_c2c_message_format (0, 0, 0, res->data); | |||||
| 523 | } | |||||
| 524 | } | |||||
| 525 | ||||||
| 526 | if (!val) { | |||||
| 527 | val = xmmsv_ref (res->data); | |||||
| 528 | } | |||||
| 529 | ||||||
| 530 | ret = cb->func (val, cb->user_data); | |||||
| 531 | ||||||
| 532 | xmmsv_unref (val); | |||||
| 533 | return ret; | |||||
| 534 | } | |||||
| 535 | ||||||
| 536 | /** | |||||
| 537 | * @internal | |||||
| 538 | */ | |||||
| 539 | void | |||||
| 540 | xmmsc_result_run (xmmsc_result_t *res, xmms_ipc_msg_t *msg) | |||||
| 541 | { | |||||
| 542 | x_list_t *n, *next; | |||||
| 543 | xmmsc_result_callback_t *cb; | |||||
| 544 | ||||||
| 545 | x_return_if_fail (res)if (!(res)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "res", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 545); return; }; | |||||
| ||||||
| 546 | x_return_if_fail (msg)if (!(msg)) { xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "msg", __FUNCTION__, "../src/clients/lib/xmmsclient/result.c" , 546); return; }; | |||||
| 547 | ||||||
| 548 | if (!xmmsc_result_parse_msg (res, msg)) { | |||||
| 549 | xmms_ipc_msg_destroy (msg); | |||||
| 550 | return; | |||||
| 551 | } | |||||
| 552 | ||||||
| 553 | xmms_ipc_msg_destroy (msg); | |||||
| 554 | ||||||
| 555 | xmmsc_result_ref (res); | |||||
| 556 | ||||||
| 557 | /* Run all notifiers and check for positive return values */ | |||||
| 558 | n = res->notifiers; | |||||
| 559 | while (n) { | |||||
| 560 | int keep; | |||||
| 561 | ||||||
| 562 | next = x_list_next (n)((n) ? (((x_list_t *)(n))->next) : ((void*)0)); | |||||
| 563 | cb = n->data; | |||||
| 564 | ||||||
| 565 | keep = xmmsc_result_run_callback (res, cb); | |||||
| 566 | if (!keep || res->type == XMMSC_RESULT_CLASS_DEFAULT) { | |||||
| 567 | xmmsc_result_notifier_delete (res, n); | |||||
| 568 | } | |||||
| 569 | ||||||
| 570 | n = next; | |||||
| 571 | } | |||||
| 572 | ||||||
| 573 | /* If this result is a signal, and we still have some notifiers | |||||
| 574 | * we need to restart the signal. | |||||
| 575 | */ | |||||
| 576 | if (res->notifiers && res->type == XMMSC_RESULT_CLASS_SIGNAL) { | |||||
| ||||||
| 577 | /* We restart the signal using the same result. */ | |||||
| 578 | xmmsc_result_restart (res); | |||||
| 579 | } | |||||
| 580 | ||||||
| 581 | if (res->type != XMMSC_RESULT_CLASS_DEFAULT && !res->is_c2c) { | |||||
| 582 | /* We keep the results alive with signals and broadcasts, | |||||
| 583 | but we just renew the value because it went out of scope. | |||||
| 584 | (freeing the payload, forget about it). | |||||
| 585 | The exception being for c2c results of the BROADCAST class | |||||
| 586 | (those associated with messages and replies), which may be | |||||
| 587 | used synchronously as if they belonged to the DEFAULT class. | |||||
| 588 | */ | |||||
| 589 | xmmsv_unref (res->data); | |||||
| 590 | res->data = NULL((void*)0); | |||||
| 591 | } | |||||
| 592 | ||||||
| 593 | xmmsc_result_unref (res); | |||||
| 594 | } | |||||
| 595 | ||||||
| 596 | /** | |||||
| 597 | * Allocates new #xmmsc_result_t and references it. | |||||
| 598 | * Should not be used from a client. | |||||
| 599 | * @internal | |||||
| 600 | */ | |||||
| 601 | ||||||
| 602 | xmmsc_result_t * | |||||
| 603 | xmmsc_result_new (xmmsc_connection_t *c, xmmsc_result_type_t type, | |||||
| 604 | uint32_t cookie) | |||||
| 605 | { | |||||
| 606 | xmmsc_result_t *res; | |||||
| 607 | ||||||
| 608 | res = x_new0 (xmmsc_result_t, 1)calloc (1, sizeof (xmmsc_result_t) * (1)); | |||||
| 609 | if (!res) { | |||||
| 610 | x_oom ()xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d" , __FUNCTION__, "../src/clients/lib/xmmsclient/result.c", 610 ); | |||||
| 611 | return NULL((void*)0); | |||||
| 612 | } | |||||
| 613 | ||||||
| 614 | res->c = c; | |||||
| 615 | ||||||
| 616 | res->data = NULL((void*)0); | |||||
| 617 | res->type = type; | |||||
| 618 | res->cookie = cookie; | |||||
| 619 | ||||||
| 620 | /* user must give this back */ | |||||
| 621 | xmmsc_result_ref (res); | |||||
| 622 | ||||||
| 623 | /* Add it to the loop */ | |||||
| 624 | xmmsc_ipc_result_register (c->ipc, res); | |||||
| 625 | ||||||
| 626 | /* For the destroy func */ | |||||
| 627 | res->ipc = c->ipc; | |||||
| 628 | ||||||
| 629 | return res; | |||||
| 630 | } | |||||
| 631 | ||||||
| 632 | void | |||||
| 633 | xmmsc_result_clear_weakrefs (xmmsc_result_t *result) | |||||
| 634 | { | |||||
| 635 | result->c = NULL((void*)0); | |||||
| 636 | result->ipc = NULL((void*)0); | |||||
| 637 | } | |||||
| 638 | ||||||
| 639 | /* Macro-magically define the xmmsc_result_callback_new_* functions. */ | |||||
| 640 | #define GEN_RESULT_CALLBACK_NEW_FUNC(name, cbtype)static xmmsc_result_callback_t * xmmsc_result_callback_new_name (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof (xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient" , XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 640); return ((void *)0); } cb->type = cbtype; cb->user_data = udata; cb-> free_func = free_f; cb->func = f; return cb; } \ | |||||
| 641 | static xmmsc_result_callback_t * \ | |||||
| 642 | xmmsc_result_callback_new_##name (xmmsc_result_notifier_t f, void *udata, \ | |||||
| 643 | xmmsc_user_data_free_func_t free_f) \ | |||||
| 644 | { \ | |||||
| 645 | xmmsc_result_callback_t *cb; \ | |||||
| 646 | \ | |||||
| 647 | cb = x_new0 (xmmsc_result_callback_t, 1)calloc (1, sizeof (xmmsc_result_callback_t) * (1)); \ | |||||
| 648 | if (!cb) { \ | |||||
| 649 | x_oom()xmmsc_log ("xmmsclient", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d" , __FUNCTION__, "../src/clients/lib/xmmsclient/result.c", 649 ); \ | |||||
| 650 | return NULL((void*)0); \ | |||||
| 651 | } \ | |||||
| 652 | \ | |||||
| 653 | cb->type = cbtype; \ | |||||
| 654 | cb->user_data = udata; \ | |||||
| 655 | cb->free_func = free_f; \ | |||||
| 656 | cb->func = f; \ | |||||
| 657 | \ | |||||
| 658 | return cb; \ | |||||
| 659 | } | |||||
| 660 | ||||||
| 661 | GEN_RESULT_CALLBACK_NEW_FUNC (default, XMMSC_RESULT_CALLBACK_DEFAULT)static xmmsc_result_callback_t * xmmsc_result_callback_new_default (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof (xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient" , XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 661); return ((void *)0); } cb->type = XMMSC_RESULT_CALLBACK_DEFAULT; cb->user_data = udata; cb->free_func = free_f; cb->func = f; return cb ; } | |||||
| 662 | GEN_RESULT_CALLBACK_NEW_FUNC (raw, XMMSC_RESULT_CALLBACK_RAW)static xmmsc_result_callback_t * xmmsc_result_callback_new_raw (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof (xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient" , XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 662); return ((void *)0); } cb->type = XMMSC_RESULT_CALLBACK_RAW; cb->user_data = udata; cb->free_func = free_f; cb->func = f; return cb ; } | |||||
| 663 | GEN_RESULT_CALLBACK_NEW_FUNC (c2c, XMMSC_RESULT_CALLBACK_C2C)static xmmsc_result_callback_t * xmmsc_result_callback_new_c2c (xmmsc_result_notifier_t f, void *udata, xmmsc_user_data_free_func_t free_f) { xmmsc_result_callback_t *cb; cb = calloc (1, sizeof (xmmsc_result_callback_t) * (1)); if (!cb) { xmmsc_log ("xmmsclient" , XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d", __FUNCTION__ , "../src/clients/lib/xmmsclient/result.c", 663); return ((void *)0); } cb->type = XMMSC_RESULT_CALLBACK_C2C; cb->user_data = udata; cb->free_func = free_f; cb->func = f; return cb ; } | |||||
| 664 | ||||||
| 665 | /* Add a new notifier to a result | |||||
| 666 | */ | |||||
| 667 | static void | |||||
| 668 | xmmsc_result_notifier_add (xmmsc_result_t *res, xmmsc_result_callback_t *cb) | |||||
| 669 | { | |||||
| 670 | /* The pending call takes one ref */ | |||||
| 671 | xmmsc_result_ref (res); | |||||
| 672 | res->notifiers = x_list_append (res->notifiers, cb); | |||||
| 673 | } | |||||
| 674 | ||||||
| 675 | ||||||
| 676 | /* Dereference a notifier from a result. | |||||
| 677 | * The #x_list_t node containing the notifier is passed. | |||||
| 678 | */ | |||||
| 679 | static void | |||||
| 680 | xmmsc_result_notifier_remove (xmmsc_result_t *res, x_list_t *node) | |||||
| 681 | { | |||||
| 682 | free (node->data); /* remove the callback struct, but not the udata */ | |||||
| 683 | res->notifiers = x_list_delete_link (res->notifiers, node); | |||||
| 684 | xmmsc_result_unref (res); /* each cb has a reference to res */ | |||||
| 685 | } | |||||
| 686 | ||||||
| 687 | /* Dereference a notifier from a result and delete its udata. | |||||
| 688 | * The #x_list_t node containing the notifier is passed. | |||||
| 689 | */ | |||||
| 690 | static void | |||||
| 691 | xmmsc_result_notifier_delete (xmmsc_result_t *res, x_list_t *node) | |||||
| 692 | { | |||||
| 693 | xmmsc_result_callback_t *cb = node->data; | |||||
| 694 | ||||||
| 695 | /* remove the udata */ | |||||
| 696 | if (cb->free_func) { | |||||
| 697 | cb->free_func (cb->user_data); | |||||
| 698 | } | |||||
| 699 | xmmsc_result_notifier_remove (res, node); | |||||
| 700 | } | |||||
| 701 | ||||||
| 702 | /* Dereference all notifiers from a result and delete their udata. */ | |||||
| 703 | static void | |||||
| 704 | xmmsc_result_notifier_delete_all (xmmsc_result_t *res) | |||||
| 705 | { | |||||
| 706 | x_list_t *n = res->notifiers; | |||||
| 707 | ||||||
| 708 | while (n) { | |||||
| 709 | x_list_t *next = x_list_next (n)((n) ? (((x_list_t *)(n))->next) : ((void*)0)); | |||||
| 710 | xmmsc_result_notifier_delete (res, n); | |||||
| 711 | n = next; | |||||
| 712 | } | |||||
| 713 | ||||||
| 714 | res->notifiers = NULL((void*)0); | |||||
| 715 | } |