Esempio n. 1
0
/**
 * Creates a cluster-dict fetch specification.
 *
 * @param cluster_by A list of attributes to cluster by
 * @param cluster_data The fetch specifcation to use when filling the list
 * @return A cluster-list fetch specification
 */
xmmsv_t *xmmsv_build_cluster_dict (xmmsv_t *cluster_by, xmmsv_t *cluster_field, xmmsv_t *cluster_data)
{
	xmmsv_t *res = xmmsv_new_dict ();
	if (res == NULL)
		return NULL;

	xmmsv_dict_set_string (res, "type", "cluster-dict");

	if (cluster_by != NULL) {
		xmmsv_dict_set (res, "cluster-by", cluster_by);
		xmmsv_unref (cluster_by);
	}


	if (cluster_field != NULL) {
		xmmsv_dict_set (res, "cluster-field", cluster_field);
		xmmsv_unref (cluster_field);
	}

	if (cluster_data != NULL) {
		xmmsv_dict_set (res, "data", cluster_data);
		xmmsv_unref (cluster_data);
	}

	return res;
}
Esempio n. 2
0
static void
filter_testcase (const gchar *path, xmmsv_t *list)
{
	gchar *content, *filename;
	xmmsv_t *dict, *data, *coll;

	g_assert (g_file_get_contents (path, &content, NULL, NULL));
	dict = xmmsv_from_json (content);
	if (dict == NULL) {
		g_error ("Could not parse '%s'!\n", path);
		g_assert_not_reached ();
	}
	g_free (content);

	g_assert (xmmsv_dict_has_key (dict, "medialib"));
	g_assert (xmmsv_dict_has_key (dict, "collection"));
	g_assert (xmmsv_dict_has_key (dict, "specification"));
	g_assert (xmmsv_dict_has_key (dict, "expected"));

	g_assert (xmmsv_dict_get (dict, "collection", &data));
	g_assert (xmmsv_is_type (data, XMMSV_TYPE_DICT));

	coll = xmmsv_coll_from_dict (data);

	xmmsv_dict_set (dict, "collection", coll);
	xmmsv_unref (coll);

	filename = g_path_get_basename (path);
	xmmsv_dict_set_string (dict, "name", filename);
	g_free (filename);

	xmmsv_list_append (list, dict);
	xmmsv_unref (dict);
}
static xmmsv_t *
convert_ghashtable_to_xmmsv (GHashTable *table, xmms_fetch_spec_t *spec)
{
	GHashTableIter iter;
	s4_resultset_t *value;
	const gchar *key;
	xmmsv_t *ret;

	g_hash_table_iter_init (&iter, table);

	ret = xmmsv_new_dict ();

	while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
		xmmsv_t *converted;

		if (value == NULL) {
			continue;
		}

		converted = xmms_medialib_query_to_xmmsv (value, spec);
		xmmsv_dict_set (ret, key, converted);
		xmmsv_unref (converted);
	}

	if (xmmsv_dict_get_size (ret) == 0) {
		xmmsv_unref (ret);
		ret = NULL;
	}

	return ret;
}
Esempio n. 4
0
static void
currently_playing_update_info (currently_playing_t *entry, xmmsv_t *value)
{
	const gchar *noinfo_fields[] = { "playback_status", "playtime", "position"};
	const gchar *time_fields[] = { "duration"};
	xmmsv_t *info;
	gint i;

	info = xmmsv_propdict_to_dict (value, NULL);

	enrich_mediainfo (info);

	/* copy over fields that are not from metadata */
	for (i = 0; i < G_N_ELEMENTS (noinfo_fields); i++) {
		xmmsv_t *copy;
		if (xmmsv_dict_get (entry->data, noinfo_fields[i], &copy)) {
			xmmsv_dict_set (info, noinfo_fields[i], copy);
		}
	}

	/* pretty format time fields */
	for (i = 0; i < G_N_ELEMENTS (time_fields); i++) {
		gint32 tim;
		if (xmmsv_dict_entry_get_int (info, time_fields[i], &tim)) {
			gchar *p = format_time (tim, FALSE);
			xmmsv_dict_set_string (info, time_fields[i], p);
			g_free (p);
		}
	}

	xmmsv_unref (entry->data);
	entry->data = info;
}
Esempio n. 5
0
/**
 * Create a new argument for a method.
 *
 * @param name The name of the argument. Must not be NULL.
 * @param docstring The docstring of the argument.
 * @param type The expected type of the argument. Use XMMSV_TYPE_NONE to
 * accept any type. XMMSV_TYPE_ERROR is reserved and should not be used.
 * @param default_value Value to set this argument to if it's missing in the
 * method call. Implies that the argument is optional. If NULL, the argument
 * is not optional.
 */
xmmsv_t *
xmmsv_sc_argument_new (const char *name, const char *docstring,
                       xmmsv_type_t type, xmmsv_t *default_value)
{
	xmmsv_t *arg;

	x_api_error_if (!name, "with NULL name.", NULL);
	x_api_error_if (type == XMMSV_TYPE_ERROR, "with ERROR type.", NULL);
	x_api_error_if (default_value && type != XMMSV_TYPE_NONE &&
	                xmmsv_get_type (default_value) != type,
	                "with wrong type for default value.", NULL);

	arg = xmmsv_new_dict ();
	if (!arg) {
		x_oom ();
		return NULL;
	}

	xmmsv_dict_set_string (arg, "name", name);
	xmmsv_dict_set_int (arg, "type", type);

	if (docstring) {
		xmmsv_dict_set_string (arg, "docstring", docstring);
	}

	if (default_value) {
		xmmsv_dict_set (arg, "default_value", default_value);
	}

	return arg;
}
Esempio n. 6
0
xmmsv_t *
xmmsv_build_dict_va (const char *firstkey, va_list ap)
{
	const char *key;
	xmmsv_t *val, *res;

	res = xmmsv_new_dict ();
	if (!res)
		return NULL;

	key = firstkey;
	do {
		val = va_arg (ap, xmmsv_t *);

		if (!xmmsv_dict_set (res, key, val)) {
			xmmsv_unref (res);
			res = NULL;
			break;
		}
		xmmsv_unref (val);
		key = va_arg (ap, const char *);
	} while (key);

	return res;
}
Esempio n. 7
0
static gboolean
create_xmmsv_dict_foreach (gpointer key, gpointer data, gpointer userdata)
{
	const char *k = (const char *) key;
	xmmsv_t *v = (xmmsv_t *) data;
	xmmsv_t *l = (xmmsv_t *) userdata;
	xmmsv_dict_set (l, k, v);
	return FALSE;
}
Esempio n. 8
0
void
xmms_xform_browse_add_entry_property (xmms_xform_t *xform, const gchar *key,
                                      xmmsv_t *val)
{
	g_return_if_fail (xform);
	g_return_if_fail (xform->browse_dict);
	g_return_if_fail (key);
	g_return_if_fail (val);

	xmmsv_dict_set (xform->browse_dict, key, val);
}
Esempio n. 9
0
static void
xmms_medialib_tree_add_tuple (xmmsv_t *dict, const char *key,
                              const char *source, xmmsv_t *value)
{
	xmmsv_t *entry;

	if (key == NULL || source == NULL || value == NULL) {
		return;
	}

	/* Find (or insert) subtree matching the prop key */
	if (!xmmsv_dict_get (dict, key, &entry)) {
		entry = xmmsv_new_dict ();
		xmmsv_dict_set (dict, key, entry);
		xmmsv_unref (entry);
	}

	/* Replace (or insert) value matching the prop source */
	xmmsv_dict_set (entry, source, value);
}
/* 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;
}
Esempio n. 11
0
/**
 * 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;
}
Esempio n. 12
0
static int
append (xmmsv_t *obj, const char *key, uint32_t key_len, xmmsv_t *value)
{
	if (xmmsv_is_type (obj, XMMSV_TYPE_LIST)) {
		xmmsv_list_append (obj, value);
	} else if (xmmsv_is_type (obj, XMMSV_TYPE_DICT) && key) {
		xmmsv_dict_set (obj, key, value);
	} else {
		/* Should never be reached */
		assert (0);
	}
	xmmsv_unref (value);
	return 0;
}
Esempio n. 13
0
/**
 * Creates an organize fetch specification that may be passed to xmmsc_coll_query.
 * It takes a dict with key-value pairs where the values are fetch specifications.
 *
 * @return An organize fetch specification
 */
xmmsv_t *
xmmsv_build_organize (xmmsv_t *data)
{
	xmmsv_t *res;

	x_return_val_if_fail (data != NULL, NULL);
	res = xmmsv_new_dict ();

	if (res != NULL) {
		xmmsv_dict_set_string (res, "type", "organize");
		xmmsv_dict_set (res, "data", data);
		xmmsv_unref (data);
	}

	return res;
}
Esempio n. 14
0
/**
 * Helper function to transform a key-source-value dict-of-dict
 * #xmmsv_t (formerly a propdict) to a regular key-value dict, given a
 * list of source preference.
 *
 * @param propdict A key-source-value dict-of-dict #xmmsv_t.
 * @param src_prefs A list of source names or patterns. Must be
 *                  NULL-terminated. If this argument is NULL, the
 *                  default source preferences is used.
 * @return An #xmmsv_t containing a simple key-value dict. Must be
 *         unreffed manually when done.
 */
xmmsv_t *
xmmsv_propdict_to_dict (xmmsv_t *propdict, const char **src_prefs)
{
	xmmsv_t *dict, *source_dict, *value, *best_value;
	xmmsv_dict_iter_t *key_it, *source_it;
	const char *key, *source;
	const char **local_prefs;
	int match_index, best_index;

	dict = xmmsv_new_dict ();

	local_prefs = src_prefs ? src_prefs : xmmsv_default_source_pref;

	xmmsv_get_dict_iter (propdict, &key_it);
	while (xmmsv_dict_iter_valid (key_it)) {
		xmmsv_dict_iter_pair (key_it, &key, &source_dict);

		best_value = NULL;
		best_index = -1;
		xmmsv_get_dict_iter (source_dict, &source_it);
		while (xmmsv_dict_iter_valid (source_it)) {
			xmmsv_dict_iter_pair (source_it, &source, &value);
			match_index = find_match_index (source, local_prefs);
			/* keep first match or better match */
			if (match_index >= 0 && (best_index < 0 ||
			                         match_index < best_index)) {
				best_value = value;
				best_index = match_index;
			}
			xmmsv_dict_iter_next (source_it);
		}

		/* Note: we do not insert a key-value pair if no source matches */
		if (best_value) {
			xmmsv_dict_set (dict, key, best_value);
		}

		xmmsv_dict_iter_next (key_it);
	}

	return dict;
}
Esempio n. 15
0
static int
xmmsc_deserialize_dict (xmmsv_t *bb, xmmsv_t **val)
{
	xmmsv_t *dict;
	int32_t len;
	unsigned int ignore;
	char *key;

	dict = xmmsv_new_dict ();

	if (!_internal_get_from_bb_int32_positive (bb, &len)) {
		goto err;
	}

	while (len--) {
		xmmsv_t *v;

		if (!_internal_get_from_bb_string_alloc (bb, &key, &ignore)) {
			goto err;
		}

		if (!xmmsv_bitbuffer_deserialize_value (bb, &v)) {
			free (key);
			goto err;
		}

		xmmsv_dict_set (dict, key, v);
		free (key);
		xmmsv_unref (v);
	}

	*val = dict;

	return true;

err:
	x_internal_error ("Message from server did not parse correctly!");
	xmmsv_unref (dict);
	return false;
}
Esempio n. 16
0
xmmsv_t *
duplicate_dict_value (xmmsv_t *val)
{
	xmmsv_t *dup_val;
	xmmsv_dict_iter_t *it;
	const char *key;
	xmmsv_t *v;
	xmmsv_t *new_elem;

	x_return_val_if_fail (xmmsv_get_dict_iter (val, &it), NULL);
	dup_val = xmmsv_new_dict ();
	while (xmmsv_dict_iter_pair (it, &key, &v)) {
		new_elem = xmmsv_copy (v);
		xmmsv_dict_set (dup_val, key, new_elem);
		xmmsv_unref (new_elem);
		xmmsv_dict_iter_next (it);
	}

	xmmsv_dict_iter_explicit_destroy (it);

	return dup_val;
}
Esempio n. 17
0
static xmmsv_t *
args_to_dict (gchar **argv, gint argc)
{
	xmmsv_t *dict;
	gint i;

	dict = xmmsv_new_dict ();
	if (!dict) {
		return NULL;
	}

	for (i = 0; i < argc; i++) {
		gchar **tuple;
		xmmsv_t *val;

		/* Split the string into arg and value. */
		tuple = g_strsplit (argv[i], "=", 2);
		if (tuple[0] && tuple[1]) {
			val = xmmsv_new_string (tuple[1]);
		} else if (tuple[0]) {
			val = xmmsv_new_none ();
		} else {
			g_strfreev (tuple);
			continue; /* Empty tuple, means empty string. */
		}
		if (!val) {
			xmmsv_unref (dict);
			return NULL;
		}

		xmmsv_dict_set (dict, tuple[0], val);

		g_strfreev (tuple);
		xmmsv_unref (val);
	}

	return dict;
}
Esempio n. 18
0
/**
 * Decodes a cluster fetch specification from a dictionary.
 * The 'cluster-by' must be one of 'id', 'position' or 'value'. If set
 * to 'value', then an additional 'cluster-field' will be used to specify
 * which meta data attribute to cluster on.
 */
static xmms_fetch_spec_t *
xmms_fetch_spec_new_cluster (xmmsv_t *fetch, xmms_fetch_info_t *info,
                             s4_sourcepref_t *prefs, xmms_error_t *err)
{
	xmmsv_t *cluster_by, *cluster_field, *cluster_data;
	xmms_fetch_spec_t *data, *spec = NULL;
	s4_sourcepref_t *sp;
	const gchar *value = NULL;
	const gchar *field = NULL;
	const gchar *fallback = NULL;
	gint cluster_type;

	if (!xmmsv_dict_get (fetch, "cluster-by", &cluster_by)) {
		cluster_by = xmmsv_new_string ("value");
		xmmsv_dict_set (fetch, "cluster-by", cluster_by);
		xmmsv_unref (cluster_by);
	}

	if (!xmmsv_dict_entry_get_string (fetch, "cluster-by", &value)) {
		const gchar *message = "'cluster-by' must be a string.";
		xmms_error_set (err, XMMS_ERROR_INVAL, message);
		return NULL;
	}

	xmmsv_get_string (cluster_by, &value);

	if (!cluster_by_from_string (value, &cluster_type)) {
		const gchar *message = "'cluster-by' must be 'id', 'position', or 'value'.";
		xmms_error_set (err, XMMS_ERROR_INVAL, message);
		return NULL;
	}

	if (cluster_type == CLUSTER_BY_VALUE) {
		if (!xmmsv_dict_entry_get_string (fetch, "cluster-field", &field)) {
			const gchar *message = "'cluster-field' must  if 'cluster-by' is 'value'.";
			xmms_error_set (err, XMMS_ERROR_INVAL, message);
			return NULL;
		}
	}

	if (!xmmsv_dict_get (fetch, "data", &cluster_data)) {
		const gchar *message = "Required field 'data' not set in cluster.";
		xmms_error_set (err, XMMS_ERROR_INVAL, message);
		return NULL;
	}

	if (xmmsv_dict_entry_get_type (fetch, "cluster-fallback") == XMMSV_TYPE_NONE) {
		fallback = NULL;
	} else if (!xmmsv_dict_entry_get_string (fetch, "cluster-fallback", &fallback)) {
		const gchar *message = "Optional field 'default' must be a string.";
		xmms_error_set (err, XMMS_ERROR_INVAL, message);
		return NULL;
	}

	sp = normalize_source_preferences (fetch, prefs, err);
	if (xmms_error_iserror (err)) {
		return NULL;
	}

	data = xmms_fetch_spec_new (cluster_data, info, sp, err);
	if (xmms_error_iserror (err)) {
		s4_sourcepref_unref (sp);
		return NULL;
	}

	spec = g_new0 (xmms_fetch_spec_t, 1);
	spec->data.cluster.data = data;
	spec->data.cluster.type = cluster_type;
	spec->data.cluster.fallback = fallback;

	switch (spec->data.cluster.type) {
		case CLUSTER_BY_ID:
			spec->data.cluster.column = xmms_fetch_info_add_song_id(info, cluster_field);
			break;
		case CLUSTER_BY_VALUE:
			xmmsv_dict_get (fetch, "cluster-field", &cluster_field);
			spec->data.cluster.column = xmms_fetch_info_add_key (info, cluster_field,
			                                                     field, sp);
			break;
		case CLUSTER_BY_POSITION:
			/* do nothing */
			break;
		default:
			g_assert_not_reached ();
	}

	s4_sourcepref_unref (sp);

	return spec;
}
Esempio n. 19
0
static bool
_internal_get_from_bb_collection_alloc (xmmsv_t *bb, xmmsv_coll_t **coll)
{
	int i;
	int32_t type;
	int32_t n_items;
	int id;
	int32_t *idlist = NULL;
	xmmsv_t *dict, *attrs;
	xmmsv_dict_iter_t *it;

	/* Get the type and create the collection */
	if (!_internal_get_from_bb_int32_positive (bb, &type)) {
		return false;
	}

	*coll = xmmsv_coll_new (type);

	/* Get the attributes */
	if (!_internal_get_from_bb_value_dict_alloc (bb, &dict)) {
		return false;
	}

	attrs = xmmsv_coll_attributes_get (*coll);

	xmmsv_get_dict_iter (dict, &it);
	while (xmmsv_dict_iter_valid (it)) {
		const char *key;
		xmmsv_t *value;
		xmmsv_dict_iter_pair (it, &key, &value);
		xmmsv_dict_set (attrs, key, value);
		xmmsv_dict_iter_next (it);
	}

	xmmsv_unref (dict);

	/* Get the idlist */
	if (!_internal_get_from_bb_int32_positive (bb, &n_items)) {
		goto err;
	}

	if (!(idlist = x_new (int32_t, n_items + 1))) {
		goto err;
	}

	for (i = 0; i < n_items; i++) {
		if (!_internal_get_from_bb_int32 (bb, &id)) {
			goto err;
		}

		idlist[i] = id;
	}

	idlist[i] = 0;
	xmmsv_coll_set_idlist (*coll, idlist);
	free (idlist);
	idlist = NULL;

	/* Get the operands */
	if (!_internal_get_from_bb_int32_positive (bb, &n_items)) {
		goto err;
	}

	for (i = 0; i < n_items; i++) {
		xmmsv_coll_t *operand;

		if (!_internal_get_from_bb_int32_positive (bb, &type) ||
		    type != XMMSV_TYPE_COLL ||
		    !_internal_get_from_bb_collection_alloc (bb, &operand)) {
			goto err;
		}

		xmmsv_coll_add_operand (*coll, operand);
		xmmsv_coll_unref (operand);
	}

	return true;

err:
	if (idlist != NULL) {
		free (idlist);
	}

	xmmsv_coll_unref (*coll);

	return false;
}
Esempio n. 20
0
/** 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 an S4 result (a column) into an xmmsv values */
static void *
result_to_xmmsv (xmmsv_t *ret, gint32 id, const s4_result_t *res,
                 xmms_fetch_spec_t *spec)
{
	static xmmsv_t * (*aggregate_functions[AGGREGATE_END])(xmmsv_t *c, gint i, const gchar *s) = {
		aggregate_first,
		aggregate_sum,
		aggregate_max,
		aggregate_min,
		aggregate_set,
		aggregate_list,
		aggregate_random,
		aggregate_average
	};
	const s4_val_t *val;
	xmmsv_t *dict, *current;
	const gchar *str_value, *key = NULL;
	gint32 i, int_value;
	xmmsv_t *newval;

	g_return_val_if_fail (spec->data.metadata.get_size > 0, ret);
	g_return_val_if_fail (spec->data.metadata.get_size <= METADATA_END, ret);
	g_return_val_if_fail (spec->data.metadata.aggr_func >= 0, ret);
	g_return_val_if_fail (spec->data.metadata.aggr_func < AGGREGATE_END, ret);

	/* Loop through all the values the column has */
	while (res != NULL) {
		dict = ret;
		current = ret;

		/* Loop through the list of what to get ("key", "source", ..) */
		for (i = 0; i < spec->data.metadata.get_size; i++) {
			str_value = NULL;
			int_value = 0;

			/* Fill str_value with the correct value if it is a string
			 * or int_value if it is an integer
			 */
			switch (spec->data.metadata.get[i]) {
				case METADATA_KEY:
					str_value = s4_result_get_key (res);
					break;
				case METADATA_SOURCE:
					str_value = s4_result_get_src (res);
					if (str_value == NULL)
						str_value = "server";
					break;
				case METADATA_ID:
					int_value = id;
					break;
				case METADATA_VALUE:
					val = s4_result_get_val (res);

					if (!s4_val_get_int (val, &int_value)) {
						s4_val_get_str (val, &str_value);
					}
					break;
				default:
					g_assert_not_reached ();
			}

			/* If this is not the last property to get we use this property
			 * as a key in a dict
			 */
			if (i < (spec->data.metadata.get_size - 1)) {
				/* Convert integers to strings */
				if (str_value == NULL) {
					/* Big enough to hold 2^32 with minus sign */
					gchar buf[12];
					g_sprintf (buf, "%i", int_value);
					key = buf;
				} else {
					key = str_value;
				}

				/* Make sure the root dict exists */
				if (dict == NULL) {
					ret = dict = xmmsv_new_dict ();
				}

				/* If this dict contains dicts we have to create a new
				 * dict if one does not exists for the key yet
				 */
				if (!xmmsv_dict_get (dict, key, &current))
					current = NULL;

				if (i < (spec->data.metadata.get_size - 2)) {
					if (current == NULL) {
						current = xmmsv_new_dict ();
						xmmsv_dict_set (dict, key, current);
						xmmsv_unref (current);
					}
					dict = current;
				}
			}
		}

		newval = aggregate_functions[spec->data.metadata.aggr_func](current, int_value, str_value);

		/* Update the previous dict (if there is one) */
		if (newval != current) {
			if (i > 1) {
				xmmsv_dict_set (dict, key, newval);
				xmmsv_unref (newval);
			} else {
				ret = newval;
				if (current != NULL) {
					xmmsv_unref (current);
				}
			}
		}

		res = s4_result_next (res);
	}

	return ret;
}
Esempio n. 22
0
/**
 * Set an attribute in the given collection.
 *
 * @param coll The collection in which to set the attribute.
 * @param key  The name of the attribute to set.
 * @param value The value of the attribute.
 */
void
xmmsv_coll_attribute_set_value (xmmsv_t *coll, const char *key, xmmsv_t *value)
{
	x_return_if_fail (xmmsv_is_type (coll, XMMSV_TYPE_COLL));
	xmmsv_dict_set (coll->value.coll->attributes, key, value);
}