XMMS2

src/lib/xmmstypes/coll.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 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 
00038     /* List of ids, 0-terminated. */
00039     uint32_t *idlist;
00040     size_t idlist_size;
00041     size_t idlist_allocated;
00042 
00043 };
00044 
00045 
00046 static void xmmsv_coll_free (xmmsv_coll_t *coll);
00047 
00048 static int xmmsv_coll_idlist_resize (xmmsv_coll_t *coll, size_t newsize);
00049 
00050 
00051 /**
00052  * @defgroup CollectionStructure CollectionStructure
00053  * @ingroup Collections
00054  * @brief The API to be used to work with collection structures.
00055  *
00056  * @{
00057  */
00058 
00059 /**
00060  * Increases the references for the #xmmsv_coll_t
00061  *
00062  * @param coll the collection to reference.
00063  * @return coll
00064  */
00065 xmmsv_coll_t *
00066 xmmsv_coll_ref (xmmsv_coll_t *coll)
00067 {
00068     x_return_val_if_fail (coll, NULL);
00069 
00070     coll->ref++;
00071 
00072     return coll;
00073 }
00074 
00075 /**
00076  * Allocate a new collection of the given type.
00077  * The pointer will have to be deallocated using #xmmsv_coll_unref.
00078  *
00079  * @param type the #xmmsv_coll_type_t specifying the type of collection to create.
00080  * @return a pointer to the newly created collection, or NULL if the type is invalid.
00081  */
00082 xmmsv_coll_t*
00083 xmmsv_coll_new (xmmsv_coll_type_t type)
00084 {
00085     xmmsv_coll_t *coll;
00086 
00087     x_return_val_if_fail (type <= XMMS_COLLECTION_TYPE_LAST, NULL);
00088 
00089     coll = x_new0 (xmmsv_coll_t, 1);
00090     if (!coll) {
00091         x_oom ();
00092         return NULL;
00093     }
00094 
00095     if (!(coll->idlist = x_new0 (uint32_t, 1))) {
00096         x_oom ();
00097         free (coll);
00098         return NULL;
00099     }
00100     coll->idlist_size = 1;
00101     coll->idlist_allocated = 1;
00102 
00103     coll->ref  = 0;
00104     coll->type = type;
00105 
00106     coll->operands = xmmsv_new_list ();
00107     xmmsv_list_restrict_type (coll->operands, XMMSV_TYPE_COLL);
00108 
00109     coll->attributes = xmmsv_new_dict ();
00110 
00111     /* user must give this back */
00112     xmmsv_coll_ref (coll);
00113 
00114     return coll;
00115 }
00116 
00117 /**
00118  * Free the memory owned by the collection.
00119  * You probably want to use #xmmsv_coll_unref instead, which handles
00120  * reference counting.
00121  *
00122  * @param coll the collection to free.
00123  */
00124 static void
00125 xmmsv_coll_free (xmmsv_coll_t *coll)
00126 {
00127     x_return_if_fail (coll);
00128 
00129     /* Unref all the operands and attributes */
00130     xmmsv_unref (coll->operands);
00131 
00132     xmmsv_unref (coll->attributes);
00133 
00134     free (coll->idlist);
00135 
00136     free (coll);
00137 }
00138 
00139 /**
00140  * Decreases the references for the #xmmsv_coll_t
00141  * When the number of references reaches 0 it will
00142  * be freed and all its operands unreferenced as well.
00143  *
00144  * @param coll the collection to unref.
00145  */
00146 void
00147 xmmsv_coll_unref (xmmsv_coll_t *coll)
00148 {
00149     x_return_if_fail (coll);
00150     x_api_error_if (coll->ref < 1, "with a freed collection",);
00151 
00152     coll->ref--;
00153     if (coll->ref == 0) {
00154         xmmsv_coll_free (coll);
00155     }
00156 }
00157 
00158 
00159 /**
00160  * Set the list of ids in the given collection.
00161  * The list must be 0-terminated.
00162  * Note that the idlist is only relevant for idlist collections.
00163  *
00164  * @param coll the collection to modify.
00165  * @param ids  the 0-terminated list of ids to store in the collection.
00166  */
00167 void
00168 xmmsv_coll_set_idlist (xmmsv_coll_t *coll, unsigned int ids[])
00169 {
00170     unsigned int i;
00171     unsigned int size = 0;
00172 
00173     x_return_if_fail (coll);
00174 
00175     while (ids[size] != 0) {
00176         ++size;
00177     }
00178     ++size;
00179 
00180     free (coll->idlist);
00181     if (!(coll->idlist = x_new0 (uint32_t, size))) {
00182         x_oom ();
00183         return;
00184     }
00185 
00186     for (i = 0; i < size; ++i) {
00187         coll->idlist[i] = ids[i];
00188     }
00189 
00190     coll->idlist_size = size;
00191     coll->idlist_allocated = size;
00192 }
00193 
00194 static int
00195 _xmmsv_coll_operand_find (xmmsv_list_iter_t *it, xmmsv_coll_t *op)
00196 {
00197     xmmsv_coll_t *c;
00198     xmmsv_t *v;
00199 
00200     while (xmmsv_list_iter_valid (it)) {
00201         xmmsv_list_iter_entry (it, &v);
00202         if (xmmsv_get_coll (v, &c)) {
00203             if (c == op) {
00204                 return 1;
00205             }
00206         }
00207         xmmsv_list_iter_next (it);
00208     }
00209     return 0;
00210 }
00211 
00212 /**
00213  * Add the operand to the given collection.
00214  * @param coll  The collection to add the operand to.
00215  * @param op    The operand to add.
00216  */
00217 void
00218 xmmsv_coll_add_operand (xmmsv_coll_t *coll, xmmsv_coll_t *op)
00219 {
00220     xmmsv_list_iter_t *it;
00221     xmmsv_t *v;
00222     x_return_if_fail (coll);
00223     x_return_if_fail (op);
00224 
00225     /* we used to check if it already existed here before */
00226     if (!xmmsv_get_list_iter (coll->operands, &it))
00227         return;
00228 
00229     if (_xmmsv_coll_operand_find (it, op)) {
00230         x_api_warning ("with an operand already in operand list");
00231         xmmsv_list_iter_explicit_destroy (it);
00232         return;
00233     }
00234 
00235     xmmsv_list_iter_explicit_destroy (it);
00236 
00237     v = xmmsv_new_coll (op);
00238     x_return_if_fail (v);
00239     xmmsv_list_append (coll->operands, v);
00240     xmmsv_unref (v);
00241 }
00242 
00243 /**
00244  * Remove all the occurences of the operand in the given collection.
00245  * @param coll  The collection to remove the operand from.
00246  * @param op    The operand to remove.
00247  */
00248 void
00249 xmmsv_coll_remove_operand (xmmsv_coll_t *coll, xmmsv_coll_t *op)
00250 {
00251     xmmsv_list_iter_t *it;
00252 
00253     x_return_if_fail (coll);
00254     x_return_if_fail (op);
00255 
00256     if (!xmmsv_get_list_iter (coll->operands, &it))
00257         return;
00258 
00259     if (_xmmsv_coll_operand_find (it, op)) {
00260         xmmsv_list_iter_remove (it);
00261     } else {
00262         x_api_warning ("with an operand not in operand list");
00263     }
00264     xmmsv_list_iter_explicit_destroy (it);
00265 }
00266 
00267 
00268 /**
00269  * Append a value to the idlist.
00270  * @param coll  The collection to update.
00271  * @param id    The id to append to the idlist.
00272  * @return  TRUE on success, false otherwise.
00273  */
00274 int
00275 xmmsv_coll_idlist_append (xmmsv_coll_t *coll, unsigned int id)
00276 {
00277     x_return_val_if_fail (coll, 0);
00278 
00279     return xmmsv_coll_idlist_insert (coll, coll->idlist_size - 1, id);
00280 }
00281 
00282 /**
00283  * Insert a value at a given position in the idlist.
00284  * @param coll  The collection to update.
00285  * @param id    The id to insert in the idlist.
00286  * @param index The position at which to insert the value.
00287  * @return  TRUE on success, false otherwise.
00288  */
00289 int
00290 xmmsv_coll_idlist_insert (xmmsv_coll_t *coll, unsigned int index, unsigned int id)
00291 {
00292     int i;
00293     x_return_val_if_fail (coll, 0);
00294 
00295     if (index >= coll->idlist_size) {
00296         return 0;
00297     }
00298 
00299     /* We need more memory, reallocate */
00300     if (coll->idlist_size == coll->idlist_allocated) {
00301         int success;
00302         size_t double_size = coll->idlist_allocated * 2;
00303         success = xmmsv_coll_idlist_resize (coll, double_size);
00304         x_return_val_if_fail (success, 0);
00305     }
00306 
00307     for (i = coll->idlist_size; i > index; i--) {
00308         coll->idlist[i] = coll->idlist[i - 1];
00309     }
00310 
00311     coll->idlist[index] = id;
00312     coll->idlist_size++;
00313 
00314     return 1;
00315 }
00316 
00317 /**
00318  * Move a value of the idlist to a new position.
00319  * @param coll  The collection to update.
00320  * @param index The index of the value to move.
00321  * @param newindex The newindex to which to move the value.
00322  * @return  TRUE on success, false otherwise.
00323  */
00324 int
00325 xmmsv_coll_idlist_move (xmmsv_coll_t *coll, unsigned int index, unsigned int newindex)
00326 {
00327     int i;
00328     uint32_t tmp;
00329 
00330     x_return_val_if_fail (coll, 0);
00331 
00332     if ((index >= coll->idlist_size - 1) || (newindex >= coll->idlist_size - 1)) {
00333         return 0;
00334     }
00335 
00336     tmp = coll->idlist[index];
00337     if (index < newindex) {
00338         for (i = index; i < newindex; i++) {
00339             coll->idlist[i] = coll->idlist[i + 1];
00340         }
00341     }
00342     else if (index > newindex) {
00343         for (i = index; i > newindex; i--) {
00344             coll->idlist[i] = coll->idlist[i - 1];
00345         }
00346     }
00347     coll->idlist[newindex] = tmp;
00348 
00349     return 1;
00350 }
00351 
00352 /**
00353  * Remove the value at a given index from the idlist.
00354  * @param coll  The collection to update.
00355  * @param index The index at which to remove the value.
00356  * @return  TRUE on success, false otherwise.
00357  */
00358 int
00359 xmmsv_coll_idlist_remove (xmmsv_coll_t *coll, unsigned int index)
00360 {
00361     int i;
00362     size_t half_size;
00363 
00364     x_return_val_if_fail (coll, 0);
00365 
00366     if (index >= coll->idlist_size - 1) {
00367         return 0;
00368     }
00369 
00370     coll->idlist_size--;
00371     for (i = index; i < coll->idlist_size; i++) {
00372         coll->idlist[i] = coll->idlist[i + 1];
00373     }
00374 
00375     /* Reduce memory usage by two if possible */
00376     half_size = coll->idlist_allocated / 2;
00377     if (coll->idlist_size <= half_size) {
00378         xmmsv_coll_idlist_resize (coll, half_size);
00379     }
00380 
00381     return 1;
00382 }
00383 
00384 /**
00385  * Empties the idlist.
00386  * @param coll  The collection to update.
00387  * @return  TRUE on success, false otherwise.
00388  */
00389 int
00390 xmmsv_coll_idlist_clear (xmmsv_coll_t *coll)
00391 {
00392     unsigned int empty[] = { 0 };
00393 
00394     x_return_val_if_fail (coll, 0);
00395 
00396     xmmsv_coll_set_idlist (coll, empty);
00397 
00398     return 1;
00399 }
00400 
00401 /**
00402  * Retrieves the value at the given position in the idlist.
00403  * @param coll  The collection to update.
00404  * @param index The position of the value to retrieve.
00405  * @param val   The pointer at which to store the found value.
00406  * @return  TRUE on success, false otherwise.
00407  */
00408 int
00409 xmmsv_coll_idlist_get_index (xmmsv_coll_t *coll, unsigned int index, uint32_t *val)
00410 {
00411     x_return_val_if_fail (coll, 0);
00412 
00413     if (index >= (coll->idlist_size - 1)) {
00414         return 0;
00415     }
00416 
00417     *val = coll->idlist[index];
00418 
00419     return 1;
00420 }
00421 
00422 /**
00423  * Sets the value at the given position in the idlist.
00424  * @param coll  The collection to update.
00425  * @param index The position of the value to set.
00426  * @param val   The new value.
00427  * @return  TRUE on success, false otherwise.
00428  */
00429 int
00430 xmmsv_coll_idlist_set_index (xmmsv_coll_t *coll, unsigned int index, uint32_t val)
00431 {
00432     x_return_val_if_fail (coll, 0);
00433 
00434     if (index >= (coll->idlist_size - 1)) {
00435         return 0;
00436     }
00437 
00438     coll->idlist[index] = val;
00439 
00440     return 1;
00441 }
00442 
00443 /**
00444  * Get the size of the idlist.
00445  * @param coll  The collection to update.
00446  * @return  The size of the idlist.
00447  */
00448 size_t
00449 xmmsv_coll_idlist_get_size (xmmsv_coll_t *coll)
00450 {
00451     x_return_val_if_fail (coll, 0);
00452 
00453     return coll->idlist_size - 1;
00454 }
00455 
00456 
00457 
00458 /**
00459  * Return the type of the collection.
00460  * @param coll  The collection to consider.
00461  * @return The #xmmsv_coll_type_t of the collection, or -1 if invalid.
00462  */
00463 xmmsv_coll_type_t
00464 xmmsv_coll_get_type (xmmsv_coll_t *coll)
00465 {
00466     x_return_val_if_fail (coll, -1);
00467 
00468     return coll->type;
00469 }
00470 
00471 /**
00472  * Return the list of ids stored in the collection.
00473  * The list is owned by the collection.
00474  * Note that this must not be confused with the content of the
00475  * collection, which must be queried using xmmsc_coll_query_ids!
00476  *
00477  * @param coll  The collection to consider.
00478  * @return The 0-terminated list of ids.
00479  */
00480 uint32_t*
00481 xmmsv_coll_get_idlist (xmmsv_coll_t *coll)
00482 {
00483     x_return_null_if_fail (coll);
00484 
00485     return coll->idlist;
00486 }
00487 
00488 xmmsv_t *
00489 xmmsv_coll_operands_get (xmmsv_coll_t *coll)
00490 {
00491     x_return_val_if_fail (coll, NULL);
00492 
00493     return coll->operands;
00494 }
00495 
00496 xmmsv_t *
00497 xmmsv_coll_attributes_get (xmmsv_coll_t *coll)
00498 {
00499     x_return_val_if_fail (coll, NULL);
00500 
00501     return coll->attributes;
00502 }
00503 
00504 /**
00505  * Set an attribute in the given collection.
00506  *
00507  * @param coll The collection in which to set the attribute.
00508  * @param key  The name of the attribute to set.
00509  * @param value The value of the attribute.
00510  */
00511 void
00512 xmmsv_coll_attribute_set (xmmsv_coll_t *coll, const char *key, const char *value)
00513 {
00514     xmmsv_t *v;
00515 
00516     v = xmmsv_new_string (value);
00517     x_return_if_fail (v);
00518 
00519     xmmsv_dict_set (coll->attributes, key, v);
00520     xmmsv_unref (v);
00521 }
00522 
00523 /**
00524  * Remove an attribute from the given collection.
00525  * The return value indicated whether the attribute was found (and
00526  * removed)
00527  *
00528  * @param coll The collection to remove the attribute from.
00529  * @param key  The name of the attribute to remove.
00530  * @return 1 upon success, 0 otherwise
00531  */
00532 int
00533 xmmsv_coll_attribute_remove (xmmsv_coll_t *coll, const char *key)
00534 {
00535     return xmmsv_dict_remove (coll->attributes, key);
00536 }
00537 
00538 /**
00539  * Retrieve the value of the attribute of the given collection.
00540  * The return value is 1 if the attribute was found and 0 otherwise.
00541  * The value of the attribute is owned by the collection and must not
00542  * be freed by the caller.
00543  *
00544  * @param coll The collection to retrieve the attribute from.
00545  * @param key  The name of the attribute.
00546  * @param value The value of the attribute if found (owned by the collection).
00547  * @return 1 if the attribute was found, 0 otherwise
00548  */
00549 int
00550 xmmsv_coll_attribute_get (xmmsv_coll_t *coll, const char *key, char **value)
00551 {
00552     if (xmmsv_dict_entry_get_string (coll->attributes, key, value)) {
00553         return 1;
00554     }
00555     *value = NULL;
00556     return 0;
00557 }
00558 
00559 
00560 
00561 struct attr_fe_data {
00562     xmmsv_coll_attribute_foreach_func func;
00563     void *userdata;
00564 };
00565 
00566 static void
00567 attr_fe_func (const char *key, xmmsv_t *val, void *user_data)
00568 {
00569     struct attr_fe_data *d = user_data;
00570     const char *v;
00571     int r;
00572 
00573     r = xmmsv_get_string (val, &v);
00574     x_return_if_fail (r)
00575 
00576     d->func (key, v, d->userdata);
00577 }
00578 /**
00579  * Iterate over all key/value-pair of the collection attributes.
00580  *
00581  * Calls specified function for each key/value-pair of the attribute list.
00582  *
00583  * void function (const char *key, const char *value, void *user_data);
00584  *
00585  * @param coll the #xmmsv_coll_t.
00586  * @param func function that is called for each key/value-pair
00587  * @param user_data extra data passed to func
00588  */
00589 void
00590 xmmsv_coll_attribute_foreach (xmmsv_coll_t *coll,
00591                               xmmsv_coll_attribute_foreach_func func,
00592                               void *user_data)
00593 {
00594     struct attr_fe_data d = {func, user_data};
00595     xmmsv_dict_foreach (coll->attributes, attr_fe_func, &d);
00596 }
00597 
00598 /**
00599  * Return a collection referencing the whole media library,
00600  * that is a reference to the "All Media" collection.
00601  * The returned structure must be unref'd using #xmmsv_coll_unref
00602  * after usage.
00603  *
00604  * @return a collection referring to the "All Media" collection.
00605  */
00606 xmmsv_coll_t*
00607 xmmsv_coll_universe ()
00608 {
00609     xmmsv_coll_t *univ = xmmsv_coll_new (XMMS_COLLECTION_TYPE_REFERENCE);
00610     xmmsv_coll_attribute_set (univ, "reference", "All Media");
00611     /* FIXME: namespace? */
00612 
00613     return univ;
00614 }
00615 
00616 /** @} */
00617 
00618 
00619 
00620 /** @internal */
00621 
00622 
00623 static int
00624 xmmsv_coll_idlist_resize (xmmsv_coll_t *coll, size_t newsize)
00625 {
00626     uint32_t *newmem;
00627 
00628     newmem = realloc (coll->idlist, newsize * sizeof (uint32_t));
00629 
00630     if (newmem == NULL) {
00631         x_oom ();
00632         return 0;
00633     }
00634 
00635     coll->idlist = newmem;
00636     coll->idlist_allocated = newsize;
00637 
00638     return 1;
00639 }