XMMS2
src/lib/xmmstypes/coll.c
Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2011 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <ctype.h>
00021 
00022 #include "xmmsc/xmmsc_idnumbers.h"
00023 #include "xmmsc/xmmsv.h"
00024 #include "xmmsc/xmmsv_coll.h"
00025 #include "xmmsc/xmmsc_util.h"
00026 #include "xmmspriv/xmms_list.h"
00027 
00028 
00029 struct xmmsv_coll_St {
00030 
00031     /* refcounting */
00032     int ref;
00033 
00034     xmmsv_coll_type_t type;
00035     xmmsv_t *operands;
00036     xmmsv_t *attributes;
00037     xmmsv_t *idlist;
00038 
00039     int32_t *legacy_idlist;
00040 };
00041 
00042 
00043 static void xmmsv_coll_free (xmmsv_coll_t *coll);
00044 
00045 
00046 /**
00047  * @defgroup CollectionStructure CollectionStructure
00048  * @ingroup Collections
00049  * @brief The API to be used to work with collection structures.
00050  *
00051  * @{
00052  */
00053 
00054 /**
00055  * Increases the references for the #xmmsv_coll_t
00056  *
00057  * @param coll the collection to reference.
00058  * @return coll
00059  */
00060 xmmsv_coll_t *
00061 xmmsv_coll_ref (xmmsv_coll_t *coll)
00062 {
00063     x_return_val_if_fail (coll, NULL);
00064 
00065     coll->ref++;
00066 
00067     return coll;
00068 }
00069 
00070 /**
00071  * Allocate a new collection of the given type.
00072  * The pointer will have to be deallocated using #xmmsv_coll_unref.
00073  *
00074  * @param type the #xmmsv_coll_type_t specifying the type of collection to create.
00075  * @return a pointer to the newly created collection, or NULL if the type is invalid.
00076  */
00077 xmmsv_coll_t*
00078 xmmsv_coll_new (xmmsv_coll_type_t type)
00079 {
00080     xmmsv_coll_t *coll;
00081 
00082     x_return_val_if_fail (type <= XMMS_COLLECTION_TYPE_LAST, NULL);
00083 
00084     coll = x_new0 (xmmsv_coll_t, 1);
00085     if (!coll) {
00086         x_oom ();
00087         return NULL;
00088     }
00089 
00090     coll->ref  = 0;
00091     coll->type = type;
00092 
00093     coll->idlist = xmmsv_new_list ();
00094     xmmsv_list_restrict_type (coll->idlist, XMMSV_TYPE_INT32);
00095 
00096     coll->operands = xmmsv_new_list ();
00097     xmmsv_list_restrict_type (coll->operands, XMMSV_TYPE_COLL);
00098 
00099     coll->attributes = xmmsv_new_dict ();
00100 
00101     coll->legacy_idlist = NULL;
00102 
00103     /* user must give this back */
00104     xmmsv_coll_ref (coll);
00105 
00106     return coll;
00107 }
00108 
00109 /**
00110  * Free the memory owned by the collection.
00111  * You probably want to use #xmmsv_coll_unref instead, which handles
00112  * reference counting.
00113  *
00114  * @param coll the collection to free.
00115  */
00116 static void
00117 xmmsv_coll_free (xmmsv_coll_t *coll)
00118 {
00119     x_return_if_fail (coll);
00120 
00121     /* Unref all the operands and attributes */
00122     xmmsv_unref (coll->operands);
00123     xmmsv_unref (coll->attributes);
00124     xmmsv_unref (coll->idlist);
00125     if (coll->legacy_idlist) {
00126         free (coll->legacy_idlist);
00127     }
00128 
00129     free (coll);
00130 }
00131 
00132 /**
00133  * Decreases the references for the #xmmsv_coll_t
00134  * When the number of references reaches 0 it will
00135  * be freed and all its operands unreferenced as well.
00136  *
00137  * @param coll the collection to unref.
00138  */
00139 void
00140 xmmsv_coll_unref (xmmsv_coll_t *coll)
00141 {
00142     x_return_if_fail (coll);
00143     x_api_error_if (coll->ref < 1, "with a freed collection",);
00144 
00145     coll->ref--;
00146     if (coll->ref == 0) {
00147         xmmsv_coll_free (coll);
00148     }
00149 }
00150 
00151 
00152 /**
00153  * Set the list of ids in the given collection.
00154  * The list must be 0-terminated.
00155  * Note that the idlist is only relevant for idlist collections.
00156  *
00157  * @param coll the collection to modify.
00158  * @param ids  the 0-terminated list of ids to store in the collection.
00159  */
00160 void
00161 xmmsv_coll_set_idlist (xmmsv_coll_t *coll, int ids[])
00162 {
00163     unsigned int i;
00164 
00165     xmmsv_list_clear (coll->idlist);
00166     for (i = 0; ids[i]; i++) {
00167         xmmsv_list_append_int (coll->idlist, ids[i]);
00168     }
00169 }
00170 
00171 static int
00172 _xmmsv_coll_operand_find (xmmsv_list_iter_t *it, xmmsv_coll_t *op)
00173 {
00174     xmmsv_coll_t *c;
00175     xmmsv_t *v;
00176 
00177     while (xmmsv_list_iter_valid (it)) {
00178         xmmsv_list_iter_entry (it, &v);
00179         if (xmmsv_get_coll (v, &c)) {
00180             if (c == op) {
00181                 return 1;
00182             }
00183         }
00184         xmmsv_list_iter_next (it);
00185     }
00186     return 0;
00187 }
00188 
00189 /**
00190  * Add the operand to the given collection.
00191  * @param coll  The collection to add the operand to.
00192  * @param op    The operand to add.
00193  */
00194 void
00195 xmmsv_coll_add_operand (xmmsv_coll_t *coll, xmmsv_coll_t *op)
00196 {
00197     xmmsv_list_iter_t *it;
00198     xmmsv_t *v;
00199     x_return_if_fail (coll);
00200     x_return_if_fail (op);
00201 
00202     /* we used to check if it already existed here before */
00203     if (!xmmsv_get_list_iter (coll->operands, &it))
00204         return;
00205 
00206     if (_xmmsv_coll_operand_find (it, op)) {
00207         x_api_warning ("with an operand already in operand list");
00208         xmmsv_list_iter_explicit_destroy (it);
00209         return;
00210     }
00211 
00212     xmmsv_list_iter_explicit_destroy (it);
00213 
00214     v = xmmsv_new_coll (op);
00215     x_return_if_fail (v);
00216     xmmsv_list_append (coll->operands, v);
00217     xmmsv_unref (v);
00218 }
00219 
00220 /**
00221  * Remove all the occurences of the operand in the given collection.
00222  * @param coll  The collection to remove the operand from.
00223  * @param op    The operand to remove.
00224  */
00225 void
00226 xmmsv_coll_remove_operand (xmmsv_coll_t *coll, xmmsv_coll_t *op)
00227 {
00228     xmmsv_list_iter_t *it;
00229 
00230     x_return_if_fail (coll);
00231     x_return_if_fail (op);
00232 
00233     if (!xmmsv_get_list_iter (coll->operands, &it))
00234         return;
00235 
00236     if (_xmmsv_coll_operand_find (it, op)) {
00237         xmmsv_list_iter_remove (it);
00238     } else {
00239         x_api_warning ("with an operand not in operand list");
00240     }
00241     xmmsv_list_iter_explicit_destroy (it);
00242 }
00243 
00244 
00245 /**
00246  * Append a value to the idlist.
00247  * @param coll  The collection to update.
00248  * @param id    The id to append to the idlist.
00249  * @return  TRUE on success, false otherwise.
00250  */
00251 int
00252 xmmsv_coll_idlist_append (xmmsv_coll_t *coll, int id)
00253 {
00254     x_return_val_if_fail (coll, 0);
00255 
00256     return xmmsv_list_append_int (coll->idlist, id);
00257 }
00258 
00259 /**
00260  * Insert a value at a given position in the idlist.
00261  * @param coll  The collection to update.
00262  * @param id    The id to insert in the idlist.
00263  * @param index The position at which to insert the value.
00264  * @return  TRUE on success, false otherwise.
00265  */
00266 int
00267 xmmsv_coll_idlist_insert (xmmsv_coll_t *coll, int index, int id)
00268 {
00269     x_return_val_if_fail (coll, 0);
00270 
00271     return xmmsv_list_insert_int (coll->idlist, index, id);
00272 }
00273 
00274 /**
00275  * Move a value of the idlist to a new position.
00276  * @param coll  The collection to update.
00277  * @param index The index of the value to move.
00278  * @param newindex The newindex to which to move the value.
00279  * @return  TRUE on success, false otherwise.
00280  */
00281 int
00282 xmmsv_coll_idlist_move (xmmsv_coll_t *coll, int index, int newindex)
00283 {
00284     x_return_val_if_fail (coll, 0);
00285 
00286     return xmmsv_list_move (coll->idlist, index, newindex);
00287 }
00288 
00289 /**
00290  * Remove the value at a given index from the idlist.
00291  * @param coll  The collection to update.
00292  * @param index The index at which to remove the value.
00293  * @return  TRUE on success, false otherwise.
00294  */
00295 int
00296 xmmsv_coll_idlist_remove (xmmsv_coll_t *coll, int index)
00297 {
00298     x_return_val_if_fail (coll, 0);
00299 
00300     return xmmsv_list_remove (coll->idlist, index);
00301 }
00302 
00303 /**
00304  * Empties the idlist.
00305  * @param coll  The collection to update.
00306  * @return  TRUE on success, false otherwise.
00307  */
00308 int
00309 xmmsv_coll_idlist_clear (xmmsv_coll_t *coll)
00310 {
00311     x_return_val_if_fail (coll, 0);
00312 
00313     return xmmsv_list_clear (coll->idlist);
00314 }
00315 
00316 /**
00317  * Retrieves the value at the given position in the idlist.
00318  * @param coll  The collection to update.
00319  * @param index The position of the value to retrieve.
00320  * @param val   The pointer at which to store the found value.
00321  * @return  TRUE on success, false otherwise.
00322  */
00323 int
00324 xmmsv_coll_idlist_get_index (xmmsv_coll_t *coll, int index, int32_t *val)
00325 {
00326     x_return_val_if_fail (coll, 0);
00327 
00328     return xmmsv_list_get_int (coll->idlist, index, val);
00329 }
00330 
00331 /**
00332  * Sets the value at the given position in the idlist.
00333  * @param coll  The collection to update.
00334  * @param index The position of the value to set.
00335  * @param val   The new value.
00336  * @return  TRUE on success, false otherwise.
00337  */
00338 int
00339 xmmsv_coll_idlist_set_index (xmmsv_coll_t *coll, int index, int32_t val)
00340 {
00341     x_return_val_if_fail (coll, 0);
00342 
00343     return xmmsv_list_set_int (coll->idlist, index, val);
00344 }
00345 
00346 /**
00347  * Get the size of the idlist.
00348  * @param coll  The collection to update.
00349  * @return  The size of the idlist.
00350  */
00351 size_t
00352 xmmsv_coll_idlist_get_size (xmmsv_coll_t *coll)
00353 {
00354     x_return_val_if_fail (coll, 0);
00355 
00356     return xmmsv_list_get_size (coll->idlist);
00357 }
00358 
00359 
00360 
00361 /**
00362  * Return the type of the collection.
00363  * @param coll  The collection to consider.
00364  * @return The #xmmsv_coll_type_t of the collection, or -1 if invalid.
00365  */
00366 xmmsv_coll_type_t
00367 xmmsv_coll_get_type (xmmsv_coll_t *coll)
00368 {
00369     x_return_val_if_fail (coll, -1);
00370 
00371     return coll->type;
00372 }
00373 
00374 /**
00375  * Return the list of ids stored in the collection.
00376  * The list is owned by the collection.
00377  * Note that this must not be confused with the content of the
00378  * collection, which must be queried using xmmsc_coll_query_ids!
00379  *
00380  * Also note that this function is deprecated (use xmmsv_coll_idlist_get
00381  * instead) and that changes to the returned array will be ignored. The array
00382  * is also not updated when the idlist is changed using the supplied functions.
00383  * Additionally every call to this function allocates a new array, so calling
00384  * it repetitively will be a performance penalty.
00385  *
00386  * @param coll  The collection to consider.
00387  * @return The 0-terminated list of ids.
00388  */
00389 const int32_t*
00390 xmmsv_coll_get_idlist (xmmsv_coll_t *coll)
00391 {
00392     xmmsv_list_iter_t *it;
00393     unsigned int i;
00394     int32_t entry;
00395 
00396     x_return_null_if_fail (coll);
00397 
00398     /* free and allocate a new legacy list */
00399     if (coll->legacy_idlist) {
00400         free (coll->legacy_idlist);
00401     }
00402     coll->legacy_idlist = calloc (xmmsv_coll_idlist_get_size (coll) + 1,
00403                                   sizeof (int32_t));
00404 
00405     /* copy contents to legacy list */
00406     for (xmmsv_get_list_iter (coll->idlist, &it), i = 0;
00407          xmmsv_list_iter_valid (it);
00408          xmmsv_list_iter_next (it), i++) {
00409         xmmsv_list_iter_entry_int (it, &entry);
00410         coll->legacy_idlist[i] = entry;
00411     }
00412     coll->legacy_idlist[i] = 0;
00413 
00414     return coll->legacy_idlist;
00415 }
00416 
00417 /**
00418  * Return the list of ids stored in the collection.
00419  * This function does not increase the refcount of the list, the reference is
00420  * still owned by the collection.
00421  *
00422  * Note that this must not be confused with the content of the collection,
00423  * which must be queried using xmmsc_coll_query_ids!
00424  *
00425  * @param coll  The collection to consider.
00426  * @return The 0-terminated list of ids.
00427  */
00428 xmmsv_t *
00429 xmmsv_coll_idlist_get (xmmsv_coll_t *coll)
00430 {
00431     x_return_null_if_fail (coll);
00432 
00433     return coll->idlist;
00434 }
00435 
00436 xmmsv_t *
00437 xmmsv_coll_operands_get (xmmsv_coll_t *coll)
00438 {
00439     x_return_val_if_fail (coll, NULL);
00440 
00441     return coll->operands;
00442 }
00443 
00444 xmmsv_t *
00445 xmmsv_coll_attributes_get (xmmsv_coll_t *coll)
00446 {
00447     x_return_val_if_fail (coll, NULL);
00448 
00449     return coll->attributes;
00450 }
00451 
00452 /**
00453  * Set an attribute in the given collection.
00454  *
00455  * @param coll The collection in which to set the attribute.
00456  * @param key  The name of the attribute to set.
00457  * @param value The value of the attribute.
00458  */
00459 void
00460 xmmsv_coll_attribute_set (xmmsv_coll_t *coll, const char *key, const char *value)
00461 {
00462     xmmsv_t *v;
00463 
00464     v = xmmsv_new_string (value);
00465     x_return_if_fail (v);
00466 
00467     xmmsv_dict_set (coll->attributes, key, v);
00468     xmmsv_unref (v);
00469 }
00470 
00471 /**
00472  * Remove an attribute from the given collection.
00473  * The return value indicated whether the attribute was found (and
00474  * removed)
00475  *
00476  * @param coll The collection to remove the attribute from.
00477  * @param key  The name of the attribute to remove.
00478  * @return 1 upon success, 0 otherwise
00479  */
00480 int
00481 xmmsv_coll_attribute_remove (xmmsv_coll_t *coll, const char *key)
00482 {
00483     return xmmsv_dict_remove (coll->attributes, key);
00484 }
00485 
00486 /**
00487  * Retrieve the value of the attribute of the given collection.
00488  * The return value is 1 if the attribute was found and 0 otherwise.
00489  * The value of the attribute is owned by the collection and must not
00490  * be freed by the caller.
00491  *
00492  * @param coll The collection to retrieve the attribute from.
00493  * @param key  The name of the attribute.
00494  * @param value The value of the attribute if found (owned by the collection).
00495  * @return 1 if the attribute was found, 0 otherwise
00496  */
00497 int
00498 xmmsv_coll_attribute_get (xmmsv_coll_t *coll, const char *key, char **value)
00499 {
00500     if (xmmsv_dict_entry_get_string (coll->attributes, key, value)) {
00501         return 1;
00502     }
00503     *value = NULL;
00504     return 0;
00505 }
00506 
00507 
00508 
00509 struct attr_fe_data {
00510     xmmsv_coll_attribute_foreach_func func;
00511     void *userdata;
00512 };
00513 
00514 static void
00515 attr_fe_func (const char *key, xmmsv_t *val, void *user_data)
00516 {
00517     struct attr_fe_data *d = user_data;
00518     const char *v;
00519     int r;
00520 
00521     r = xmmsv_get_string (val, &v);
00522     x_return_if_fail (r)
00523 
00524     d->func (key, v, d->userdata);
00525 }
00526 /**
00527  * Iterate over all key/value-pair of the collection attributes.
00528  *
00529  * Calls specified function for each key/value-pair of the attribute list.
00530  *
00531  * void function (const char *key, const char *value, void *user_data);
00532  *
00533  * @param coll the #xmmsv_coll_t.
00534  * @param func function that is called for each key/value-pair
00535  * @param user_data extra data passed to func
00536  */
00537 void
00538 xmmsv_coll_attribute_foreach (xmmsv_coll_t *coll,
00539                               xmmsv_coll_attribute_foreach_func func,
00540                               void *user_data)
00541 {
00542     struct attr_fe_data d = {func, user_data};
00543     xmmsv_dict_foreach (coll->attributes, attr_fe_func, &d);
00544 }
00545 
00546 /**
00547  * Return a collection referencing the whole media library,
00548  * that is a reference to the "All Media" collection.
00549  * The returned structure must be unref'd using #xmmsv_coll_unref
00550  * after usage.
00551  *
00552  * @return a collection referring to the "All Media" collection.
00553  */
00554 xmmsv_coll_t*
00555 xmmsv_coll_universe ()
00556 {
00557     xmmsv_coll_t *univ = xmmsv_coll_new (XMMS_COLLECTION_TYPE_REFERENCE);
00558     xmmsv_coll_attribute_set (univ, "reference", "All Media");
00559     /* FIXME: namespace? */
00560 
00561     return univ;
00562 }
00563 
00564 /** @} */