/** * Allocate a new collection of the given type. * The pointer will have to be deallocated using #xmmsv_coll_unref. * * @param type the #xmmsv_coll_type_t specifying the type of collection to create. * @return a pointer to the newly created collection, or NULL if the type is invalid. */ static xmmsv_coll_internal_t* _xmmsv_coll_new (xmmsv_coll_type_t type) { xmmsv_coll_internal_t *coll; x_return_val_if_fail (type <= XMMS_COLLECTION_TYPE_LAST, NULL); coll = x_new0 (xmmsv_coll_internal_t, 1); if (!coll) { x_oom (); return NULL; } coll->type = type; coll->idlist = xmmsv_new_list (); xmmsv_list_restrict_type (coll->idlist, XMMSV_TYPE_INT64); coll->operands = xmmsv_new_list (); xmmsv_list_restrict_type (coll->operands, XMMSV_TYPE_COLL); coll->attributes = xmmsv_new_dict (); return coll; }
/** List a playlist */ static xmmsv_t * xmms_playlist_client_list_entries (xmms_playlist_t *playlist, const gchar *plname, xmms_error_t *err) { xmmsv_t *entries = NULL; xmmsv_coll_t *plcoll; xmms_medialib_entry_t entry; xmmsv_list_iter_t *it; g_return_val_if_fail (playlist, NULL); g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { g_mutex_unlock (playlist->mutex); return NULL; } entries = xmmsv_new_list (); xmmsv_get_list_iter (xmmsv_coll_idlist_get (plcoll), &it); for (xmmsv_list_iter_first (it); xmmsv_list_iter_valid (it); xmmsv_list_iter_next (it)) { xmmsv_list_iter_entry_int (it, &entry); xmmsv_list_append_int (entries, entry); } xmmsv_list_iter_explicit_destroy (it); g_mutex_unlock (playlist->mutex); return entries; }
static xmmsv_t * aggregate_set (xmmsv_t *current, gint int_value, const gchar *str_value) { set_data_t *data; xmmsv_t *value; gpointer key; guint length; if (current == NULL) { set_data_t init = { .ht = g_hash_table_new (NULL, NULL), .list = xmmsv_new_list () }; current = xmmsv_new_bin ((guchar *) &init, sizeof (set_data_t)); } xmmsv_get_bin (current, (const guchar **) &data, &length); if (str_value != NULL) { value = xmmsv_new_string (str_value); key = (gpointer) str_value; } else { value = xmmsv_new_int (int_value); key = GINT_TO_POINTER (int_value); } if (g_hash_table_lookup (data->ht, key) == NULL) { g_hash_table_insert (data->ht, key, value); xmmsv_list_append (data->list, value); } xmmsv_unref (value); return current; }
/** * Create a new #xmmsv_t list initialized with the argument. * @param list The list of values to initially fill the #xmmsv_t with. * @return a new #xmmsv_t list. */ static xmmsv_t * xmms_create_xmmsv_list (GList *list) { xmmsv_t *v = xmmsv_new_list (); g_list_foreach (list, create_xmmsv_list_foreach, (gpointer) v); return v; }
/** * List the ids of all media matched by the given collection. * A list of ordering properties can be specified, as well as offsets * to only retrieve part of the result set. * * @param conn The connection to the server. * @param coll The collection used to query. * @param order The list of properties to order by, passed as an #xmmsv_t list of strings. * @param limit_start The offset at which to start retrieving results (0 to disable). * @param limit_len The maximum number of entries to retrieve (0 to disable). */ xmmsc_result_t* xmmsc_coll_query_ids (xmmsc_connection_t *conn, xmmsv_coll_t *coll, xmmsv_t *order, int limit_start, int limit_len) { xmms_ipc_msg_t *msg; x_check_conn (conn, NULL); x_api_error_if (!coll, "with a NULL collection", NULL); /* default to empty ordering */ if (!order) { order = xmmsv_new_list (); } else { xmmsv_ref (order); } msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_COLLECTION, XMMS_IPC_CMD_QUERY_IDS); xmms_ipc_msg_put_collection (msg, coll); xmms_ipc_msg_put_int32 (msg, limit_start); xmms_ipc_msg_put_int32 (msg, limit_len); xmms_ipc_msg_put_value_list (msg, order); /* purposedly skip typing */ xmmsv_unref (order); return xmmsc_send_msg (conn, msg); }
static int xmmsc_deserialize_list (xmmsv_t *bb, xmmsv_t **val) { xmmsv_t *list; int32_t len; list = xmmsv_new_list (); if (!_internal_get_from_bb_int32_positive (bb, &len)) { goto err; } while (len--) { xmmsv_t *v; if (xmmsv_bitbuffer_deserialize_value (bb, &v)) { xmmsv_list_append (list, v); } else { goto err; } xmmsv_unref (v); } *val = list; return true; err: x_internal_error ("Message from server did not parse correctly!"); xmmsv_unref (list); return false; }
xmmsv_t * xmmsv_build_list_va (xmmsv_t *first_entry, va_list ap) { xmmsv_t *val, *res; res = xmmsv_new_list (); if (!res) return NULL; val = first_entry; while (val) { if (!xmmsv_list_append (res, val)) { xmmsv_unref (res); res = NULL; break; } xmmsv_unref (val); val = va_arg (ap, xmmsv_t *); } return res; }
static xmmsv_t * xmms_main_client_list_plugins (xmms_object_t *main, gint32 type, xmms_error_t *err) { xmmsv_t *list = xmmsv_new_list (); xmms_plugin_foreach (type, xmms_main_client_list_foreach, list); return list; }
void xmms_medialib_session_track_garbage (xmms_medialib_session_t *session, xmmsv_t *data) { if (session->vals == NULL) session->vals = xmmsv_new_list (); xmmsv_list_append (session->vals, data); }
static xmmsv_t * create_structure (int stack_offset, int is_object) { if (is_object) { return xmmsv_new_dict (); } else { return xmmsv_new_list (); } }
/* Converts an S4 resultset into an xmmsv_t, based on the fetch specification */ xmmsv_t * xmms_medialib_query_to_xmmsv (s4_resultset_t *set, xmms_fetch_spec_t *spec) { GHashTable *set_table; GList *sets; xmmsv_t *val, *ret = NULL; gint i; switch (spec->type) { case FETCH_COUNT: ret = xmmsv_new_int (s4_resultset_get_rowcount (set)); break; case FETCH_METADATA: ret = metadata_to_xmmsv (set, spec); break; case FETCH_ORGANIZE: ret = xmmsv_new_dict (); for (i = 0; i < spec->data.organize.count; i++) { val = xmms_medialib_query_to_xmmsv (set, spec->data.organize.data[i]); if (val != NULL) { xmmsv_dict_set (ret, spec->data.organize.keys[i], val); xmmsv_unref (val); } } break; case FETCH_CLUSTER_LIST: sets = cluster_list (set, spec); ret = xmmsv_new_list (); for (; sets != NULL; sets = g_list_delete_link (sets, sets)) { set = sets->data; val = xmms_medialib_query_to_xmmsv (set, spec->data.cluster.data); if (val != NULL) { xmmsv_list_append (ret, val); xmmsv_unref (val); } s4_resultset_free (set); } break; case FETCH_CLUSTER_DICT: set_table = cluster_dict (set, spec); ret = convert_ghashtable_to_xmmsv (set_table, spec->data.cluster.data); g_hash_table_destroy (set_table); break; default: g_assert_not_reached (); } return ret; }
/** * Creates a metadata fetch specification. * * @param fields A list of fields to fetch, or NULL to fetch everything * @param get A list of what to get ("id", "key", "value", "source") * @param aggregate The aggregation function to use * @param sourcepref A list of sources, first one has the highest priority * @return A metadata fetch specification */ xmmsv_t *xmmsv_build_metadata (xmmsv_t *fields, xmmsv_t *get, const char *aggregate, xmmsv_t *sourcepref) { xmmsv_t *res = xmmsv_new_dict (); if (res == NULL) return NULL; xmmsv_dict_set_string (res, "type", "metadata"); if (fields != NULL) { if (xmmsv_get_type (fields) == XMMSV_TYPE_STRING) { xmmsv_t *list = xmmsv_new_list (); xmmsv_list_append (list, fields); xmmsv_unref (fields); fields = list; } xmmsv_dict_set (res, "fields", fields); xmmsv_unref (fields); } if (get != NULL) { if (xmmsv_get_type (get) == XMMSV_TYPE_STRING) { xmmsv_t *list = xmmsv_new_list (); xmmsv_list_append (list, get); xmmsv_unref (get); get = list; } xmmsv_dict_set (res, "get", get); xmmsv_unref (get); } if (sourcepref != NULL) { xmmsv_dict_set (res, "source-preference", sourcepref); xmmsv_unref (sourcepref); } if (aggregate != NULL) { xmmsv_dict_set_string (res, "aggregate", aggregate); } return res; }
/** * Sanitize the 'get' property of a 'metadata' fetch specification. */ static xmmsv_t * normalize_metadata_get (xmmsv_t *fetch, xmms_error_t *err) { xmmsv_list_iter_t *it; xmmsv_t *get, *list; guint32 values; if (!xmmsv_dict_get (fetch, "get", &get) || xmmsv_get_type (get) != XMMSV_TYPE_LIST || xmmsv_list_get_size (get) < 1) { const gchar *message = "'get' must be a non-empty list of strings."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } list = xmmsv_new_list (); values = 0; /* Scan for duplicates or invalid values */ xmmsv_get_list_iter (get, &it); while (xmmsv_list_iter_valid (it)) { const gchar *value = NULL; guint32 get_as_int, mask; xmmsv_list_iter_entry_string (it, &value); if (!metadata_value_from_string (value, &get_as_int)) { const gchar *message = "'get' entries must be 'id', 'field', 'value' or 'source'."; xmms_error_set (err, XMMS_ERROR_INVAL, message); xmmsv_unref (list); return NULL; } mask = 1 << (get_as_int + 1); if (values & mask) { const gchar *message = "'get' entries must be unique."; xmms_error_set (err, XMMS_ERROR_INVAL, message); xmmsv_unref (list); return NULL; } values |= mask; xmmsv_list_append_int (list, get_as_int); xmmsv_list_iter_next (it); } return list; }
static xmmsv_t * aggregate_list (xmmsv_t *current, gint int_value, const gchar *str_value) { if (current == NULL) { current = xmmsv_new_list (); } if (str_value != NULL) { xmmsv_list_append_string (current, str_value); } else { xmmsv_list_append_int (current, int_value); } return current; }
/** * Helper function to build a list #xmmsv_t containing the * strings from the input array. * * @param array An array of C strings. Must be NULL-terminated if num * is -1. * @param num The optional number of elements to read from the array. Set to * -1 if the array is NULL-terminated. * @return An #xmmsv_t containing the list of strings. Must be * unreffed manually when done. */ xmmsv_t * xmmsv_make_stringlist (char *array[], int num) { xmmsv_t *list, *elem; int i; list = xmmsv_new_list (); if (array) { for (i = 0; (num >= 0 && i < num) || array[i]; i++) { elem = xmmsv_new_string (array[i]); xmmsv_list_append (list, elem); xmmsv_unref (elem); } } return list; }
void xmms_xform_browse_add_entry (xmms_xform_t *xform, const gchar *filename, guint32 flags) { const gchar *url; gchar *efile, *eurl, *t; gint l, isdir; g_return_if_fail (filename); t = strchr (filename, '/'); g_return_if_fail (!t); /* filenames can't contain '/', can they? */ url = xmms_xform_get_url (xform); g_return_if_fail (url); xform->browse_dict = xmmsv_new_dict (); eurl = xmms_medialib_url_encode (url); efile = xmms_medialib_url_encode (filename); /* can't use g_build_filename as we need to preserve slashes stuff like file:/// */ l = strlen (url); if (l && url[l - 1] == '/') { t = g_strdup_printf ("%s%s", eurl, efile); } else { t = g_strdup_printf ("%s/%s", eurl, efile); } isdir = !!(flags & XMMS_XFORM_BROWSE_FLAG_DIR); xmms_xform_browse_add_entry_property_str (xform, "path", t); xmms_xform_browse_add_entry_property_int (xform, "isdir", isdir); if (xform->browse_list == NULL) { xform->browse_list = xmmsv_new_list (); } xmmsv_list_append (xform->browse_list, xform->browse_dict); xmmsv_unref (xform->browse_dict); g_free (t); g_free (efile); g_free (eurl); }
xmmsv_t * xmms_xform_browse_method (xmms_xform_t *xform, const gchar *url, xmms_error_t *error) { xmmsv_t *list = NULL; if (xmms_xform_plugin_can_browse (xform->plugin)) { xform->browse_list = xmmsv_new_list (); if (!xmms_xform_plugin_browse (xform->plugin, xform, url, error)) { return NULL; } list = xform->browse_list; xform->browse_list = NULL; xmmsv_list_sort (list, xmms_browse_list_sortfunc); } else { xmms_error_set (error, XMMS_ERROR_GENERIC, "Couldn't handle that URL"); } return list; }
/** Initialize the cache, must still be started to be filled. */ cli_cache_t * cli_cache_init () { cli_cache_t *cache; cache = g_new0 (cli_cache_t, 1); cache->currpos = -1; cache->currid = 0; cache->playback_status = 0; cache->active_playlist = xmmsv_new_list (); cache->active_playlist_name = NULL; /* Init the freshness state */ freshness_init (&cache->freshness_currpos); freshness_init (&cache->freshness_currid); freshness_init (&cache->freshness_playback_status); freshness_init (&cache->freshness_active_playlist); freshness_init (&cache->freshness_active_playlist_name); return cache; }
xmmsv_t * duplicate_list_value (xmmsv_t *val) { xmmsv_t *dup_val; xmmsv_list_iter_t *it; xmmsv_t *v; xmmsv_t *new_elem; x_return_val_if_fail (xmmsv_get_list_iter (val, &it), NULL); dup_val = xmmsv_new_list (); while (xmmsv_list_iter_entry (it, &v)) { new_elem = xmmsv_copy (v); xmmsv_list_append (dup_val, new_elem); xmmsv_unref (new_elem); xmmsv_list_iter_next (it); } xmmsv_list_iter_explicit_destroy (it); return dup_val; }
static xmmsv_t * scan_path (const gchar *path, xmms_path_predicate predicate) { const gchar *filename; xmmsv_t *list; GDir *dir; g_debug ("Scanning path: %s", path); list = xmmsv_new_list (); if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) { predicate (path, list); return list; } dir = g_dir_open (path, 0, NULL); if (dir == NULL) { g_print ("Could not open directory: %s\n", path); exit (EXIT_FAILURE); } while ((filename = g_dir_read_name (dir)) != NULL) { gchar *filepath; filepath = g_build_filename (path, filename, NULL); g_debug ("Found file: %s", filepath); predicate (filepath, list); g_free (filepath); } g_dir_close (dir); return list; }
/** * @internal Destroy the main object * @param[in] object The object to destroy */ static void xmms_main_destroy (xmms_object_t *object) { xmms_main_t *mainobj = (xmms_main_t *) object; xmms_object_cmd_arg_t arg; xmms_config_property_t *cv; cv = xmms_config_lookup ("core.shutdownpath"); do_scriptdir (xmms_config_property_get_string (cv), "stop"); /* stop output */ xmms_object_cmd_arg_init (&arg); arg.args = xmmsv_new_list (); xmms_object_cmd_call (XMMS_OBJECT (mainobj->output), XMMS_IPC_CMD_STOP, &arg); xmmsv_unref (arg.args); g_usleep (G_USEC_PER_SEC); /* wait for the output thread to end */ xmms_object_unref (mainobj->vis); xmms_object_unref (mainobj->output); xmms_object_unref (xform_obj); xmms_config_save (); xmms_config_shutdown (); xmms_plugin_shutdown (); xmms_main_unregister_ipc_commands (); xmms_ipc_shutdown (); xmms_log_shutdown (); }
/** Sorts the playlist by properties. * * This will sort the list. * @param playlist The playlist to sort. * @param properties Tells xmms_playlist_sort which properties it * should use when sorting. * @param err An #xmms_error_t - needed since xmms_playlist_sort is an ipc * method handler. */ static void xmms_playlist_client_sort (xmms_playlist_t *playlist, const gchar *plname, xmmsv_t *properties, xmms_error_t *err) { xmmsv_t *tmp, *idlist, *val, *spec, *metadata, *get; xmmsv_coll_t *plcoll, *ordered; gint currpos, pos; xmms_medialib_entry_t currid; g_return_if_fail (playlist); g_return_if_fail (properties); if (xmmsv_list_get_size (properties) < 1) { xmms_error_set (err, XMMS_ERROR_NOENT, "need at least one property to sort"); return; } g_mutex_lock (playlist->mutex); plcoll = xmms_playlist_get_coll (playlist, plname, err); if (plcoll == NULL) { xmms_error_set (err, XMMS_ERROR_NOENT, "no such playlist!"); g_mutex_unlock (playlist->mutex); return; } currpos = xmms_playlist_coll_get_currpos (plcoll); xmmsv_coll_idlist_get_index (plcoll, currpos, &currid); get = xmmsv_new_list (); xmmsv_list_append_string (get, "id"); metadata = xmmsv_new_dict (); xmmsv_dict_set_string (metadata, "type", "metadata"); xmmsv_dict_set_string (metadata, "aggregate", "first"); xmmsv_dict_set (metadata, "get", get); xmmsv_unref (get); spec = xmmsv_new_dict (); xmmsv_dict_set_string (spec, "type", "cluster-list"); xmmsv_dict_set_string (spec, "cluster-by", "position"); xmmsv_dict_set (spec, "data", metadata); xmmsv_unref (metadata); ordered = xmmsv_coll_add_order_operators (plcoll, properties); MEDIALIB_BEGIN (playlist->medialib); tmp = xmms_medialib_query (session, ordered, spec, err); MEDIALIB_COMMIT (); xmmsv_coll_unref (ordered); xmmsv_unref (spec); if (tmp == NULL) { g_mutex_unlock (playlist->mutex); return; } idlist = xmmsv_coll_idlist_get (plcoll); xmmsv_list_clear (idlist); for (pos = 0; xmmsv_list_get (tmp, pos, &val); pos++) { xmms_medialib_entry_t id; xmmsv_get_int (val, &id); xmmsv_list_append (idlist, val); if (id == currid) { xmms_collection_set_int_attr (plcoll, "position", pos); currpos = pos; } } xmmsv_unref (tmp); XMMS_PLAYLIST_CHANGED_MSG (XMMS_PLAYLIST_CHANGED_SORT, 0, plname); XMMS_PLAYLIST_CURRPOS_MSG (currpos, plname); g_mutex_unlock (playlist->mutex); }
/* Converts the temporary value returned by result_to_xmmsv into the real value */ static xmmsv_t * aggregate_data (xmmsv_t *value, aggregate_function_t aggr_func) { const random_data_t *random_data; const avg_data_t *avg_data; const set_data_t *set_data; gconstpointer data; xmmsv_t *ret; guint len; ret = NULL; data = NULL; if (value != NULL && xmmsv_is_type (value, XMMSV_TYPE_BIN)) xmmsv_get_bin (value, (const guchar **) &data, &len); switch (aggr_func) { case AGGREGATE_FIRST: case AGGREGATE_MIN: case AGGREGATE_MAX: case AGGREGATE_SUM: if (value != NULL) { ret = xmmsv_ref (value); } else { ret = xmmsv_new_none (); } break; case AGGREGATE_LIST: if (value != NULL) { ret = xmmsv_ref (value); } else { ret = xmmsv_new_list (); } break; case AGGREGATE_RANDOM: random_data = data; if (random_data != NULL) { ret = random_data->data; } else { ret = xmmsv_new_none (); } break; case AGGREGATE_SET: set_data = data; if (set_data != NULL) { g_hash_table_destroy (set_data->ht); ret = set_data->list; } else { ret = xmmsv_new_list (); } break; case AGGREGATE_AVG: avg_data = data; if (avg_data != NULL) { ret = xmmsv_new_float (avg_data->n ? avg_data->sum * 1.0 / avg_data->n : 0); } else { ret = xmmsv_new_none (); } break; default: g_assert_not_reached (); } if (value != NULL) { xmmsv_unref (value); } return ret; }