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; }
/** * 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; }
/** * 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; }
static xmmsv_t * xmmsv_coll_normalize_order_arguments (xmmsv_t *value) { xmmsv_t *order; const char *key; if (value == NULL) { return NULL; } if (xmmsv_is_type (value, XMMSV_TYPE_DICT)) { return xmmsv_ref (value); } x_api_error_if (!xmmsv_get_string (value, &key), "order entry must be string or dict", NULL); order = xmmsv_new_dict (); if (key[0] == '-') { xmmsv_dict_set_string (order, "direction", "DESC"); key++; } if (strcmp (key, "random") == 0) { xmmsv_dict_set_string (order, "type", "random"); } else if (strcmp (key, "id") == 0) { xmmsv_dict_set_string (order, "type", "id"); } else { xmmsv_dict_set_string (order, "type", "value"); xmmsv_dict_set_string (order, "field", key); } return order; }
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; }
/** * Creates a count fetch specification * * @return A new count fetch specification */ xmmsv_t *xmmsv_build_count () { xmmsv_t *res = xmmsv_new_dict (); xmmsv_dict_set_string (res, "type", "count"); return res; }
/** * 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; }
/* Applies an aggregation function to the leafs in an xmmsv dict tree */ static xmmsv_t * aggregate_result (xmmsv_t *val, gint depth, aggregate_function_t aggr_func) { xmmsv_dict_iter_t *it; if (depth == 0) { return aggregate_data (val, aggr_func); } if (val == NULL && depth > 0) { return xmmsv_new_dict(); } /* If it's a dict we call this function recursively on all its values */ xmmsv_get_dict_iter (val, &it); while (xmmsv_dict_iter_valid (it)) { xmmsv_t *entry; xmmsv_dict_iter_pair (it, NULL, &entry); xmmsv_ref (entry); entry = aggregate_result (entry, depth - 1, aggr_func); xmmsv_dict_iter_set (it, entry); xmmsv_unref (entry); xmmsv_dict_iter_next (it); } return val; }
static xmmsv_t * create_structure (int stack_offset, int is_object) { if (is_object) { return xmmsv_new_dict (); } else { return xmmsv_new_list (); } }
/** * Create a new #xmmsv_t dict initialized with the argument. * @param dict The dict of values to initially fill the #xmmsv_t with. * @return a new #xmmsv_t dict. */ static xmmsv_t * xmms_create_xmmsv_dict (GTree *dict) { xmmsv_t *v = NULL; if (dict) { v = xmmsv_new_dict (); g_tree_foreach (dict, create_xmmsv_dict_foreach, (gpointer) v); } return v; }
/* 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; }
static xmmsv_t * xmms_volume_map_to_dict (xmms_volume_map_t *vl) { xmmsv_t *ret; gint i; ret = xmmsv_new_dict (); for (i = 0; i < vl->num_channels; i++) { xmmsv_dict_set_int (ret, vl->names[i], vl->values[i]); } return ret; }
static xmmsv_t * xmms_medialib_entry_to_tree (xmms_medialib_session_t *session, xmms_medialib_entry_t entry) { s4_resultset_t *set; s4_val_t *song_id; xmmsv_t *ret, *id; gint i; song_id = s4_val_new_int (entry); set = xmms_medialib_filter (session, "song_id", song_id, S4_COND_PARENT, NULL, NULL, S4_FETCH_PARENT | S4_FETCH_DATA); s4_val_free (song_id); ret = xmmsv_new_dict (); for (i = 0; i < s4_resultset_get_rowcount (set); i++) { const s4_result_t *res; res = s4_resultset_get_result (set, 0, 0); while (res != NULL) { xmmsv_t *v_entry = NULL; const s4_val_t *val; const char *s; gint32 i; val = s4_result_get_val (res); if (s4_val_get_str (val, &s)) { v_entry = xmmsv_new_string (s); } else if (s4_val_get_int (val, &i)) { v_entry = xmmsv_new_int (i); } xmms_medialib_tree_add_tuple (ret, s4_result_get_key (res), s4_result_get_src (res), v_entry); xmmsv_unref (v_entry); res = s4_result_next (res); } } s4_resultset_free (set); id = xmmsv_new_int (entry); xmms_medialib_tree_add_tuple (ret, "id", "server", id); xmmsv_unref (id); return ret; }
/** * 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; }
status_entry_t * currently_playing_init (cli_context_t *ctx, const gchar *format, gint refresh) { currently_playing_t *entry; entry = g_new0 (currently_playing_t, 1); entry->data = xmmsv_new_dict (); entry->format = g_strdup (format); entry->ctx = ctx; return status_init (currently_playing_free, currently_playing_refresh, NULL, currently_playing_keymap, entry, refresh); }
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); }
/** * 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; }
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); }
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; }
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; }
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; }
/** * 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; }
/** 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); }
Dict::Dict() : value_( xmmsv_new_dict() ) { }
/* 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, ¤t)) 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; }