/* dumps a recursive key-source-val dict */ void print_entry (const gchar *key, xmmsv_t *dict, void *udata) { xmmsv_t *v; const gchar *source; if (xmmsv_get_type (dict) == XMMSV_TYPE_DICT) { xmmsv_dict_iter_t *it; xmmsv_get_dict_iter (dict, &it); while (xmmsv_dict_iter_valid (it)) { xmmsv_dict_iter_pair (it, &source, &v); switch (xmmsv_get_type (v)) { case XMMSV_TYPE_STRING: print_entry_string (v, key, source); break; case XMMSV_TYPE_INT32: { gint i; xmmsv_get_int (v, &i); print_info ("[%s] %s = %d", source, key, i); break; } default: print_info ("[%s] %s = (unknown data)", source, key); break; } xmmsv_dict_iter_next (it); } } }
static void add_metadatum (gpointer _key, gpointer _value, gpointer user_data) { xmmsv_t *value = (xmmsv_t *) _value; gchar *key = (gchar *) _key; metadata_festate_t *st = (metadata_festate_t *) user_data; if (xmmsv_get_type (value) == XMMSV_TYPE_STRING) { const gchar *s; xmmsv_get_string (value, &s); xmms_medialib_entry_property_set_str_source (st->session, st->entry, key, s, st->source); } else if (xmmsv_get_type (value) == XMMSV_TYPE_INT32) { gint i; xmmsv_get_int (value, &i); xmms_medialib_entry_property_set_int_source (st->session, st->entry, key, i, st->source); } else { XMMS_DBG ("Unknown type?!?"); } }
static int32_t xmms_visualization_client_set_properties (xmms_visualization_t *vis, int32_t id, xmmsv_t* prop, xmms_error_t *err) { xmms_vis_client_t *c; xmmsv_dict_iter_t *it; const gchar *key, *valstr; xmmsv_t *value; x_fetch_client (id); if (!xmmsv_get_type (prop) == XMMSV_TYPE_DICT) { xmms_error_set (err, XMMS_ERROR_INVAL, "properties must be sent as a dict!"); } else { /* record every pair */ xmmsv_get_dict_iter (prop, &it); while (xmmsv_dict_iter_valid (it)) { if (!xmmsv_dict_iter_pair (it, &key, &value)) { xmms_error_set (err, XMMS_ERROR_INVAL, "key-value property pair could not be read!"); } else if (!xmmsv_get_string (value, &valstr)) { xmms_error_set (err, XMMS_ERROR_INVAL, "property value could not be read!"); } else if (!property_set (&c->prop, key, valstr)) { xmms_error_set (err, XMMS_ERROR_INVAL, "property could not be set!"); } xmmsv_dict_iter_next (it); } /* TODO: propagate new format to xform! */ } x_release_client (); return (++c->format); }
static xmms_fetch_spec_t * xmms_fetch_spec_new_organize (xmmsv_t *fetch, xmms_fetch_info_t *info, s4_sourcepref_t *prefs, xmms_error_t *err) { xmms_fetch_spec_t *spec; xmmsv_dict_iter_t *it; s4_sourcepref_t *sp; xmmsv_t *org_data; gint org_idx; if (!xmmsv_dict_get (fetch, "data", &org_data)) { xmms_error_set (err, XMMS_ERROR_INVAL, "Required field 'data' not set in organize."); return NULL; } if (xmmsv_get_type (org_data) != XMMSV_TYPE_DICT) { xmms_error_set (err, XMMS_ERROR_INVAL, "Field 'data' in organize must be a dict."); return NULL; } sp = normalize_source_preferences (fetch, prefs, err); if (xmms_error_iserror (err)) { return NULL; } spec = g_new0 (xmms_fetch_spec_t, 1); spec->type = FETCH_ORGANIZE; spec->data.organize.count = xmmsv_dict_get_size (org_data); spec->data.organize.keys = g_new0 (const char *, spec->data.organize.count); spec->data.organize.data = g_new0 (xmms_fetch_spec_t *, spec->data.organize.count); org_idx = 0; xmmsv_get_dict_iter (org_data, &it); while (xmmsv_dict_iter_valid (it)) { xmms_fetch_spec_t *orgee; const gchar *str; xmmsv_t *entry; xmmsv_dict_iter_pair (it, &str, &entry); orgee = xmms_fetch_spec_new (entry, info, sp, err); if (xmms_error_iserror (err)) { xmms_fetch_spec_free (spec); spec = NULL; break; } spec->data.organize.keys[org_idx] = str; spec->data.organize.data[org_idx] = orgee; org_idx++; xmmsv_dict_iter_next (it); } xmmsv_dict_iter_explicit_destroy (it); s4_sourcepref_unref (sp); return spec; }
static void print_config_entry (const gchar *confname, xmmsv_t *val, void *udata) { xmmsv_type_t type; type = xmmsv_get_type (val); switch (type) { case XMMSV_TYPE_STRING: { const gchar *confval; xmmsv_get_string (val, &confval); g_printf ("%s = %s\n", confname, confval); break; } case XMMSV_TYPE_INT32: { int confval; xmmsv_get_int (val, &confval); g_printf ("%s = %d\n", confname, confval); break; } default: break; } }
void print_hash (const gchar *key, xmmsv_t *value, void *udata) { xmmsv_type_t value_type; const char *string_val; unsigned int uint_val; int int_val; value_type = xmmsv_get_type (value); switch (value_type) { case XMMSV_TYPE_STRING: xmmsv_get_string (value, &string_val); print_info ("%s = %s", key, string_val); break; case XMMSV_TYPE_INT32: xmmsv_get_int (value, &int_val); print_info ("%s = %d", key, int_val); break; default: print_error ("unhandled hash value %i", value_type); } }
static gboolean type_and_msg_to_arg (xmmsv_type_t expected_type, xmmsv_t *argument_list, xmms_object_cmd_arg_t *arg, gint i) { xmmsv_t *arg_value; xmmsv_type_t actual_type; if (argument_list && xmmsv_list_get (argument_list, i, &arg_value)) { xmmsv_ref (arg_value); } else { arg_value = xmmsv_new_none (); } actual_type = xmmsv_get_type (arg_value); if (actual_type != expected_type) { XMMS_DBG ("Expected type %i, but got type %i", expected_type, actual_type); xmmsv_unref (arg_value); return FALSE; } else { arg->values[i] = arg_value; return TRUE; } }
/** * 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 VALUE extract_value (VALUE parent, xmmsv_t *val) { switch (xmmsv_get_type (val)) { case XMMSV_TYPE_INT32: return int_get (val); case XMMSV_TYPE_STRING: return string_get (val); case XMMSV_TYPE_BIN: return bin_get (val); case XMMSV_TYPE_COLL: return coll_get (val); case XMMSV_TYPE_LIST: return list_get (parent, val); case XMMSV_TYPE_DICT: // will be handled below break; default: return Qnil; } VALUE value; RbDict *dict = NULL; value = Data_Make_Struct (cRawDict, RbDict, c_dict_mark, c_dict_free, dict); dict->real = xmmsv_ref (val); dict->parent = parent; rb_obj_call_init (value, 0, NULL); return value; }
static void getValue( Dict::Variant& val, xmmsv_t *value ) { switch( xmmsv_get_type( value ) ) { case XMMSV_TYPE_INT32: { int32_t temp = 0; if( !xmmsv_get_int( value, &temp ) ) { // FIXME: handle error } val = temp; break; } case XMMSV_TYPE_STRING: { const char* temp = 0; if( !xmmsv_get_string( value, &temp ) ) { // FIXME: handle error } val = std::string( temp ); break; } case XMMSV_TYPE_NONE: { break; } default: { } } }
static xmmsv_t * normalize_metadata_fields (xmmsv_t *fetch, xmms_error_t *err) { gpointer SENTINEL = GINT_TO_POINTER (0x31337); GHashTable *table; xmmsv_list_iter_t *it; xmmsv_t *fields; if (!xmmsv_dict_get (fetch, "fields", &fields)) { /* No fields means that we should fetch all fields */ return NULL; } if (xmmsv_get_type (fields) != XMMSV_TYPE_LIST) { const gchar *message = "'fields' must be a list of strings."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } if (xmmsv_list_get_size (fields) < 1) { /* No fields means that we should fetch all fields */ return NULL; } table = g_hash_table_new (g_str_hash, g_str_equal); xmmsv_get_list_iter (fields, &it); while (xmmsv_list_iter_valid (it)) { const gchar *value = NULL; if (!xmmsv_list_iter_entry_string (it, &value)) { const gchar *message = "'fields' entries must be of string type."; xmms_error_set (err, XMMS_ERROR_INVAL, message); g_hash_table_unref (table); return NULL; } if (g_hash_table_lookup (table, (gpointer) value) == SENTINEL) { const gchar *message = "'fields' entries must be unique."; xmms_error_set (err, XMMS_ERROR_INVAL, message); g_hash_table_unref (table); return NULL; } g_hash_table_insert (table, (gpointer) value, SENTINEL); xmmsv_list_iter_next (it); } g_hash_table_unref (table); return fields; }
/* Dumps a propdict on stdout */ static void dict_dump (const gchar *source, xmmsv_t *val, void *udata) { xmmsv_type_t type; const gchar **keyfilter = (const gchar **) udata; const gchar *key = (const gchar *) keyfilter[0]; const gchar *filter = (const gchar *) keyfilter[1]; if (filter && strcmp (filter, source) != 0) { return; } type = xmmsv_get_type (val); switch (type) { case XMMSV_TYPE_INT32: { gint value; xmmsv_get_int (val, &value); g_printf (_("[%s] %s = %u\n"), source, key, value); break; } case XMMSV_TYPE_STRING: { const gchar *value; xmmsv_get_string (val, &value); /* FIXME: special handling for url, guess charset, see common.c:print_entry */ g_printf (_("[%s] %s = %s\n"), source, key, value); break; } case XMMSV_TYPE_LIST: g_printf (_("[%s] %s = <list>\n"), source, key); break; case XMMSV_TYPE_DICT: g_printf (_("[%s] %s = <dict>\n"), source, key); break; case XMMSV_TYPE_COLL: g_printf (_("[%s] %s = <coll>\n"), source, key); break; case XMMSV_TYPE_BIN: g_printf (_("[%s] %s = <bin>\n"), source, key); break; case XMMSV_TYPE_END: g_printf (_("[%s] %s = <end>\n"), source, key); break; case XMMSV_TYPE_NONE: g_printf (_("[%s] %s = <none>\n"), source, key); break; case XMMSV_TYPE_ERROR: g_printf (_("[%s] %s = <error>\n"), source, key); break; } }
Dict::Dict( xmmsv_t* val ) : value_( 0 ) { if( xmmsv_is_error( val ) ) { const char *buf; xmmsv_get_error( val, &buf ); throw value_error( buf ); } else if( xmmsv_get_type( val ) != XMMSV_TYPE_DICT ) { throw not_dict_error( "Value is not a dict" ); } setValue( val ); }
/** * Return a new value object which is a deep copy of the input value * * @param val #xmmsv_t to copy. * @return 1 the address to the new copy of the value. */ xmmsv_t * xmmsv_copy (xmmsv_t *val) { xmmsv_t *cur_val = NULL; xmmsv_type_t type; int64_t i; const char *s; float f; x_return_val_if_fail (val, 0); type = xmmsv_get_type (val); switch (type) { case XMMSV_TYPE_DICT: cur_val = duplicate_dict_value (val); break; case XMMSV_TYPE_LIST: cur_val = duplicate_list_value (val); break; case XMMSV_TYPE_INT64: xmmsv_get_int (val, &i); cur_val = xmmsv_new_int (i); break; case XMMSV_TYPE_FLOAT: xmmsv_get_float (val, &f); cur_val = xmmsv_new_float (f); break; case XMMSV_TYPE_STRING: xmmsv_get_string (val, &s); cur_val = xmmsv_new_string (s); break; case XMMSV_TYPE_ERROR: xmmsv_get_error (val, &s); cur_val = xmmsv_new_error (s); break; case XMMSV_TYPE_COLL: cur_val = duplicate_coll_value (val); break; case XMMSV_TYPE_BIN: cur_val = xmmsv_new_bin (val->value.bin.data, val->value.bin.len); break; case XMMSV_TYPE_BITBUFFER: cur_val = xmmsv_new_bitbuffer (); xmmsv_bitbuffer_put_data (cur_val, val->value.bit.buf, val->value.bit.len / 8); xmmsv_bitbuffer_goto (cur_val, xmmsv_bitbuffer_pos (val)); break; default: cur_val = xmmsv_new_none (); break; } assert (cur_val); return cur_val; }
gboolean xmms_xform_auxdata_get_int (xmms_xform_t *xform, const gchar *key, gint32 *val) { const xmmsv_t *obj; obj = xmms_xform_auxdata_get_val (xform, key); if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_INT32) { xmmsv_get_int (obj, val); return TRUE; } return FALSE; }
/** * 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; }
static gint xmms_browse_list_sortfunc (gconstpointer a, gconstpointer b) { int r1, r2; xmmsv_t *val1, *val2, *tmp1, *tmp2; const gchar *s1, *s2; val1 = (xmmsv_t *) a; val2 = (xmmsv_t *) b; g_return_val_if_fail (xmmsv_get_type (val1) == XMMSV_TYPE_DICT, 0); g_return_val_if_fail (xmmsv_get_type (val2) == XMMSV_TYPE_DICT, 0); r1 = xmmsv_dict_get (val1, "intsort", &tmp1); r2 = xmmsv_dict_get (val2, "intsort", &tmp2); if (r1 && r2) { gint i1, i2; if (!xmmsv_get_int (tmp1, &i1)) return 0; if (!xmmsv_get_int (tmp2, &i2)) return 0; return i1 > i2; } if (!xmmsv_dict_get (val1, "path", &tmp1)) return 0; if (!xmmsv_dict_get (val2, "path", &tmp2)) return 0; if (!xmmsv_get_string (tmp1, &s1)) return 0; if (!xmmsv_get_string (tmp2, &s2)) return 0; return xmms_natcmp (s1, s2); }
gboolean xmms_xform_auxdata_get_bin (xmms_xform_t *xform, const gchar *key, const guchar **data, gsize *datalen) { const xmmsv_t *obj; obj = xmms_xform_auxdata_get_val (xform, key); if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_BIN) { xmmsv_get_bin (obj, data, datalen); return TRUE; } return FALSE; }
gboolean xmms_xform_auxdata_get_str (xmms_xform_t *xform, const gchar *key, const gchar **val) { const xmmsv_t *obj; obj = xmms_xform_auxdata_get_val (xform, key); if (obj && xmmsv_get_type (obj) == XMMSV_TYPE_STRING) { xmmsv_get_string (obj, val); return TRUE; } return FALSE; }
/** * 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 void _sum_len_string_dict (const char *key, xmmsv_t *val, void *userdata) { const char *arg; int *extra = (int *) userdata; if (xmmsv_get_type (val) == XMMSV_TYPE_NONE) { *extra += strlen (key) + 1; /* Leave room for the ampersand. */ } else if (xmmsv_get_string (val, &arg)) { /* Leave room for the equals sign and ampersand. */ *extra += strlen (key) + strlen (arg) + 2; } else { x_api_warning ("with non-string argument"); } }
static s4_sourcepref_t * normalize_source_preferences (xmmsv_t *fetch, s4_sourcepref_t *prefs, xmms_error_t *err) { s4_sourcepref_t *sp; xmmsv_list_iter_t *it; const char **strv; const gchar *str; xmmsv_t *list; gint length, idx; if (!xmmsv_dict_get (fetch, "source-preference", &list)) { return s4_sourcepref_ref (prefs); } if (xmmsv_get_type (list) != XMMSV_TYPE_LIST) { const gchar *message = "'source-preference' must be a list of strings."; xmms_error_set (err, XMMS_ERROR_INVAL, message); return NULL; } length = xmmsv_list_get_size (list); if (length == 0) { return s4_sourcepref_ref (prefs); } strv = g_new0 (const char *, length + 1); idx = 0; xmmsv_get_list_iter (list, &it); while (xmmsv_list_iter_valid (it)) { if (!xmmsv_list_iter_entry_string (it, &str)) { const gchar *message = "'source-preference' must be a list of strings."; xmms_error_set (err, XMMS_ERROR_INVAL, message); g_free (strv); return NULL; } strv[idx++] = str; xmmsv_list_iter_next (it); } sp = s4_sourcepref_create (strv); g_free (strv); return sp; }
/** * Checks that the list only contains string values. */ gboolean check_string_list (xmmsv_t *list) { xmmsv_t *valstr; xmmsv_list_iter_t *it; for (xmmsv_get_list_iter (list, &it); xmmsv_list_iter_valid (it); xmmsv_list_iter_next (it)) { xmmsv_list_iter_entry (it, &valstr); if (xmmsv_get_type (valstr) != XMMSV_TYPE_STRING) { return FALSE; } } return TRUE; }
/** * Converts a fetch specification in xmmsv_t form into a * fetch_spec_t structure */ xmms_fetch_spec_t * xmms_fetch_spec_new (xmmsv_t *fetch, xmms_fetch_info_t *info, s4_sourcepref_t *prefs, xmms_error_t *err) { const char *type; if (xmmsv_get_type (fetch) != XMMSV_TYPE_DICT) { xmms_error_set (err, XMMS_ERROR_INVAL, "A fetch specification must be a dict."); return NULL; } if (xmmsv_dict_entry_get_type (fetch, "type") == XMMSV_TYPE_NONE) { xmmsv_dict_set_string (fetch, "type", "metadata"); } if (!xmmsv_dict_entry_get_string (fetch, "type", &type)) { xmms_error_set (err, XMMS_ERROR_INVAL, "A fetch specification must have a type."); return NULL; } if (strcmp (type, "metadata") == 0) { return xmms_fetch_spec_new_metadata (fetch, info, prefs, err); } else if (strcmp (type, "cluster-list") == 0) { return xmms_fetch_spec_new_cluster_list (fetch, info, prefs, err); } else if (strcmp (type, "cluster-dict") == 0) { return xmms_fetch_spec_new_cluster_dict (fetch, info, prefs, err); } else if (strcmp (type, "organize") == 0) { return xmms_fetch_spec_new_organize (fetch, info, prefs, err); } else if (strcmp (type, "count") == 0) { return xmms_fetch_spec_new_count (fetch, info, prefs, err); } xmms_error_set (err, XMMS_ERROR_INVAL, "Unknown fetch type."); return NULL; }
int xmmsv_bitbuffer_serialize_value (xmmsv_t *bb, xmmsv_t *v) { bool ret; int32_t i; const char *s; xmmsv_coll_t *c; const unsigned char *bc; unsigned int bl; xmmsv_type_t type; type = xmmsv_get_type (v); ret = _internal_put_on_bb_int32 (bb, type); if (!ret) return ret; switch (type) { case XMMSV_TYPE_ERROR: if (!xmmsv_get_error (v, &s)) { return false; } ret = _internal_put_on_bb_error (bb, s); break; case XMMSV_TYPE_INT32: if (!xmmsv_get_int (v, &i)) { return false; } ret = _internal_put_on_bb_int32 (bb, i); break; case XMMSV_TYPE_STRING: if (!xmmsv_get_string (v, &s)) { return false; } ret = _internal_put_on_bb_string (bb, s); break; case XMMSV_TYPE_COLL: if (!xmmsv_get_coll (v, &c)) { return false; } ret = _internal_put_on_bb_collection (bb, c); break; case XMMSV_TYPE_BIN: if (!xmmsv_get_bin (v, &bc, &bl)) { return false; } ret = _internal_put_on_bb_bin (bb, bc, bl); break; case XMMSV_TYPE_LIST: ret = _internal_put_on_bb_value_list (bb, v); break; case XMMSV_TYPE_DICT: ret = _internal_put_on_bb_value_dict (bb, v); break; case XMMSV_TYPE_NONE: break; default: x_internal_error ("Tried to serialize value of unsupported type"); return false; } return ret; }
/** * This function will make a pretty string about the information in * xmmsv dict. * * @param target A allocated char * * @param len Length of target * @param fmt A format string to use. You can insert items from the dict by * using specialformat "${field}". * @param val The #xmmsv_t that contains the dict. * * @returns The number of chars written to target */ int xmmsv_dict_format (char *target, int len, const char *fmt, xmmsv_t *val) { const char *pos; if (!target) { return 0; } if (!fmt) { return 0; } memset (target, 0, len); pos = fmt; while (strlen (target) + 1 < len) { char *next_key, *key, *end; int keylen; xmmsv_dict_iter_t *it; xmmsv_t *v; next_key = strstr (pos, "${"); if (!next_key) { strncat (target, pos, len - strlen (target) - 1); break; } strncat (target, pos, MIN (next_key - pos, len - strlen (target) - 1)); keylen = strcspn (next_key + 2, "}"); key = malloc (keylen + 1); if (!key) { fprintf (stderr, "Unable to allocate %u bytes of memory, OOM?", keylen); break; } memset (key, 0, keylen + 1); strncpy (key, next_key + 2, keylen); xmmsv_get_dict_iter (val, &it); if (strcmp (key, "seconds") == 0) { int64_t duration; if (xmmsv_dict_iter_find (it, "duration")) { xmmsv_dict_iter_pair (it, NULL, &v); xmmsv_get_int (v, &duration); } else { duration = 0; } if (!duration) { strncat (target, "00", len - strlen (target) - 1); } else { char seconds[21]; /* rounding */ duration += 500; snprintf (seconds, sizeof (seconds), "%02" PRId64, (duration/1000)%60); strncat (target, seconds, len - strlen (target) - 1); } } else if (strcmp (key, "minutes") == 0) { int64_t duration; if (xmmsv_dict_iter_find (it, "duration")) { xmmsv_dict_iter_pair (it, NULL, &v); xmmsv_get_int (v, &duration); } else { duration = 0; } if (!duration) { strncat (target, "00", len - strlen (target) - 1); } else { char minutes[21]; /* rounding */ duration += 500; snprintf (minutes, sizeof (minutes), "%02" PRId64, duration/60000); strncat (target, minutes, len - strlen (target) - 1); } } else { const char *result = NULL; char tmp[21]; if (xmmsv_dict_iter_find (it, key)) { xmmsv_dict_iter_pair (it, NULL, &v); xmmsv_type_t type = xmmsv_get_type (v); if (type == XMMSV_TYPE_STRING) { xmmsv_get_string (v, &result); } else if (type == XMMSV_TYPE_INT64) { int64_t i; xmmsv_get_int (v, &i); snprintf (tmp, 21, "%" PRId64, i); result = tmp; } else if (type == XMMSV_TYPE_FLOAT) { float f; xmmsv_get_float (v, &f); snprintf (tmp, 12, "%.6f", f); result = tmp; } } if (result) strncat (target, result, len - strlen (target) - 1); } free (key); end = strchr (next_key, '}'); if (!end) { break; } pos = end + 1; } return strlen (target); }