2016-12-18 22:56:58 +00:00
|
|
|
/*
|
|
|
|
glib_compat.h replacement functionality for glib code used in qemu
|
|
|
|
Copyright (C) 2016 Chris Eagle cseagle at gmail dot com
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2018-02-26 04:12:20 +00:00
|
|
|
#ifndef QEMU_GLIB_COMPAT_H
|
|
|
|
#define QEMU_GLIB_COMPAT_H
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2017-01-20 13:13:21 +00:00
|
|
|
#include "unicorn/platform.h"
|
2016-12-18 22:56:58 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#ifndef TRUE
|
|
|
|
#define TRUE 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef FALSE
|
2016-12-26 14:02:34 +00:00
|
|
|
#define FALSE 0
|
2016-12-18 22:56:58 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define g_assert(expr) assert(expr)
|
|
|
|
#define g_assert_not_reached() assert(0)
|
|
|
|
|
|
|
|
/* typedefs for glib related types that may still be referenced */
|
|
|
|
typedef void* gpointer;
|
|
|
|
typedef const void *gconstpointer;
|
2016-12-19 20:32:06 +00:00
|
|
|
typedef int gint;
|
2021-03-04 02:22:02 +00:00
|
|
|
typedef int32_t gint32;
|
|
|
|
typedef int64_t gint64;
|
2016-12-26 12:12:01 +00:00
|
|
|
typedef uint32_t guint32;
|
2017-01-01 17:24:54 +00:00
|
|
|
typedef uint64_t guint64;
|
2016-12-19 20:32:06 +00:00
|
|
|
typedef unsigned int guint;
|
2016-12-18 22:56:58 +00:00
|
|
|
typedef char gchar;
|
2018-02-14 14:08:13 +00:00
|
|
|
typedef unsigned char guchar;
|
2016-12-18 22:56:58 +00:00
|
|
|
typedef int gboolean;
|
2016-12-26 12:12:01 +00:00
|
|
|
typedef unsigned long gulong;
|
2016-12-26 14:36:47 +00:00
|
|
|
typedef unsigned long gsize;
|
qapi: Improve qobject input visitor error reporting
Error messages refer to nodes of the QObject being visited by name.
Trouble is the names are sometimes less than helpful:
* The name of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "null". We commonly pass
NULL. Not good.
Avoiding errors "at the root" mitigates. For instance,
visit_start_struct() can only fail when the visited object is not a
dictionary, and we commonly ensure it is beforehand.
* The name of a QDict's member is the member key. Good enough only
when this happens to be unique.
* The name of a QList's member is "null". Not good.
Improve error messages by referring to nodes by path instead, as
follows:
* The path of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "<anonymous>".
* The path of a root QDict's member is the member key.
* The path of a root QList's member is "[%u]", where %u is the list
index, starting at zero.
* The path of a non-root QDict's member is the path of the QDict
concatenated with "." and the member key.
* The path of a non-root QList's member is the path of the QList
concatenated with "[%u]", where %u is the list index.
For example, the incorrect QMP command
{ "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "raw", "file": {"driver": "file" } } }
now fails with
{"error": {"class": "GenericError", "desc": "Parameter 'file.filename' is missing"}}
instead of
{"error": {"class": "GenericError", "desc": "Parameter 'filename' is missing"}}
and
{ "execute": "input-send-event", "arguments": { "device": "bar", "events": [ [] ] } }
now fails with
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'events[0]', expected: object"}}
instead of
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'null', expected: QDict"}}
Aside: calling the thing "parameter" is suboptimal for QMP, because
the root object is "arguments" there.
The qobject output visitor doesn't have this problem because it should
not fail. Same for dealloc and clone visitors.
The string visitors don't have this problem because they visit just
one value, whose name needs to be passed to the visitor as @name. The
string output visitor shouldn't fail anyway.
The options visitor uses QemuOpts names. Their name space is flat, so
the use of QDict member keys as names is fine. NULL names used with
roots and lists could conceivably result in bad error messages. Left
for another day.
Backports commit a9fc37f6bc3f2ab90585cb16493da9f6dcfbfbcf from qemu
2018-03-02 16:37:04 +00:00
|
|
|
typedef signed long gssize;
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2016-12-26 10:32:02 +00:00
|
|
|
typedef gint (*GCompareDataFunc)(gconstpointer a,
|
|
|
|
gconstpointer b,
|
|
|
|
gpointer user_data);
|
2016-12-25 17:35:42 +00:00
|
|
|
typedef void (*GFunc)(gpointer data, gpointer user_data);
|
|
|
|
typedef gint (*GCompareFunc)(gconstpointer v1, gconstpointer v2);
|
|
|
|
typedef void (*GDestroyNotify)(gpointer data);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2018-03-12 01:48:48 +00:00
|
|
|
guint g_direct_hash(gconstpointer v);
|
|
|
|
gboolean g_direct_equal(gconstpointer v1, gconstpointer v2);
|
|
|
|
|
2016-12-25 17:35:42 +00:00
|
|
|
guint g_str_hash(gconstpointer v);
|
|
|
|
gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
|
2018-03-11 18:29:19 +00:00
|
|
|
gboolean g_str_has_suffix(const gchar *str, const gchar *prefix);
|
|
|
|
gboolean g_str_has_prefix(const gchar *str, const gchar *prefix);
|
2016-12-25 17:35:42 +00:00
|
|
|
|
2018-03-11 18:29:19 +00:00
|
|
|
guint g_int_hash(gconstpointer v);
|
2016-12-25 17:35:42 +00:00
|
|
|
gboolean g_int_equal(gconstpointer v1, gconstpointer v2);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2021-03-04 02:22:02 +00:00
|
|
|
guint g_int64_hash(gconstpointer v);
|
|
|
|
gboolean g_int64_equal(gconstpointer v1, gconstpointer v2);
|
|
|
|
|
2016-12-18 22:56:58 +00:00
|
|
|
typedef struct _GList {
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer data;
|
2016-12-18 22:56:58 +00:00
|
|
|
struct _GList *next;
|
|
|
|
struct _GList *prev;
|
|
|
|
} GList;
|
|
|
|
|
2018-03-20 17:47:38 +00:00
|
|
|
GList* g_list_append(GList *list, gpointer data);
|
2016-12-18 22:56:58 +00:00
|
|
|
GList *g_list_first(GList *list);
|
2018-03-20 17:47:38 +00:00
|
|
|
GList* g_list_last(GList *list);
|
2016-12-25 17:35:42 +00:00
|
|
|
void g_list_foreach(GList *list, GFunc func, gpointer user_data);
|
2016-12-18 22:56:58 +00:00
|
|
|
void g_list_free(GList *list);
|
2018-03-20 17:47:38 +00:00
|
|
|
void g_list_free_full(GList *list, GDestroyNotify free_func);
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Backports commit db486cc334aafd3dbdaf107388e37fc3d6d3e171 from qemu
2018-02-25 05:05:52 +00:00
|
|
|
GList* g_list_insert_before(GList *list, GList *sibling, gpointer data);
|
2016-12-25 17:35:42 +00:00
|
|
|
GList *g_list_insert_sorted(GList *list, gpointer data, GCompareFunc compare);
|
2016-12-18 22:56:58 +00:00
|
|
|
#define g_list_next(list) (list->next)
|
2016-12-25 17:35:42 +00:00
|
|
|
GList *g_list_prepend(GList *list, gpointer data);
|
2016-12-18 22:56:58 +00:00
|
|
|
GList *g_list_remove_link(GList *list, GList *llink);
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Backports commit db486cc334aafd3dbdaf107388e37fc3d6d3e171 from qemu
2018-02-25 05:05:52 +00:00
|
|
|
GList *g_list_delete_link (GList *list, GList *link_);
|
2016-12-19 20:32:06 +00:00
|
|
|
GList *g_list_sort(GList *list, GCompareFunc compare);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
typedef struct _GSList {
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer data;
|
2016-12-18 22:56:58 +00:00
|
|
|
struct _GSList *next;
|
|
|
|
} GSList;
|
|
|
|
|
2016-12-25 17:35:42 +00:00
|
|
|
GSList *g_slist_append(GSList *list, gpointer data);
|
|
|
|
void g_slist_foreach(GSList *list, GFunc func, gpointer user_data);
|
2016-12-18 22:56:58 +00:00
|
|
|
void g_slist_free(GSList *list);
|
2016-12-25 17:35:42 +00:00
|
|
|
GSList *g_slist_prepend(GSList *list, gpointer data);
|
2016-12-19 20:32:06 +00:00
|
|
|
GSList *g_slist_sort(GSList *list, GCompareFunc compare);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
qapi: Improve qobject input visitor error reporting
Error messages refer to nodes of the QObject being visited by name.
Trouble is the names are sometimes less than helpful:
* The name of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "null". We commonly pass
NULL. Not good.
Avoiding errors "at the root" mitigates. For instance,
visit_start_struct() can only fail when the visited object is not a
dictionary, and we commonly ensure it is beforehand.
* The name of a QDict's member is the member key. Good enough only
when this happens to be unique.
* The name of a QList's member is "null". Not good.
Improve error messages by referring to nodes by path instead, as
follows:
* The path of the root QObject is whatever @name argument got passed
to the visitor, except NULL gets mapped to "<anonymous>".
* The path of a root QDict's member is the member key.
* The path of a root QList's member is "[%u]", where %u is the list
index, starting at zero.
* The path of a non-root QDict's member is the path of the QDict
concatenated with "." and the member key.
* The path of a non-root QList's member is the path of the QList
concatenated with "[%u]", where %u is the list index.
For example, the incorrect QMP command
{ "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "raw", "file": {"driver": "file" } } }
now fails with
{"error": {"class": "GenericError", "desc": "Parameter 'file.filename' is missing"}}
instead of
{"error": {"class": "GenericError", "desc": "Parameter 'filename' is missing"}}
and
{ "execute": "input-send-event", "arguments": { "device": "bar", "events": [ [] ] } }
now fails with
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'events[0]', expected: object"}}
instead of
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'null', expected: QDict"}}
Aside: calling the thing "parameter" is suboptimal for QMP, because
the root object is "arguments" there.
The qobject output visitor doesn't have this problem because it should
not fail. Same for dealloc and clone visitors.
The string visitors don't have this problem because they visit just
one value, whose name needs to be passed to the visitor as @name. The
string output visitor shouldn't fail anyway.
The options visitor uses QemuOpts names. Their name space is flat, so
the use of QDict member keys as names is fine. NULL names used with
roots and lists could conceivably result in bad error messages. Left
for another day.
Backports commit a9fc37f6bc3f2ab90585cb16493da9f6dcfbfbcf from qemu
2018-03-02 16:37:04 +00:00
|
|
|
typedef struct _GString GString;
|
|
|
|
|
|
|
|
struct _GString
|
|
|
|
{
|
|
|
|
gchar *str;
|
|
|
|
gsize len;
|
|
|
|
gsize allocated_len;
|
|
|
|
};
|
|
|
|
|
|
|
|
GString* g_string_new(const gchar *init);
|
|
|
|
GString* g_string_sized_new(gsize dfl_size);
|
|
|
|
gchar* g_string_free(GString *string, gboolean free_segment);
|
|
|
|
GString* g_string_erase(GString *string, gssize pos, gssize len);
|
|
|
|
GString* g_string_append_len(GString *string, const gchar *val, gssize len);
|
|
|
|
GString* g_string_insert_c(GString *string, gssize pos, gchar c);
|
|
|
|
GString* g_string_insert_len(GString *string, gssize pos, const gchar *val, gssize len);
|
|
|
|
GString* g_string_prepend(GString *string, const gchar *val);
|
|
|
|
GString* g_string_prepend_c(GString *string, gchar c);
|
|
|
|
GString* g_string_truncate(GString *string, gsize len);
|
|
|
|
GString* g_string_set_size(GString *string, gsize len);
|
|
|
|
|
2016-12-25 17:35:42 +00:00
|
|
|
typedef guint (*GHashFunc)(gconstpointer key);
|
|
|
|
typedef gboolean (*GEqualFunc)(gconstpointer a, gconstpointer b);
|
|
|
|
typedef void (*GHFunc)(gpointer key, gpointer value, gpointer user_data);
|
|
|
|
typedef gboolean (*GHRFunc)(gpointer key, gpointer value, gpointer user_data);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
typedef struct _GHashTable GHashTable;
|
2018-02-21 18:04:14 +00:00
|
|
|
typedef struct _GHashTableIter GHashTableIter;
|
|
|
|
|
|
|
|
struct _GHashTableIter
|
|
|
|
{
|
|
|
|
/*< private >*/
|
|
|
|
gpointer dummy1;
|
|
|
|
gpointer dummy2;
|
|
|
|
gpointer dummy3;
|
|
|
|
int dummy4;
|
|
|
|
gboolean dummy5;
|
|
|
|
gpointer dummy6;
|
|
|
|
};
|
2016-12-18 22:56:58 +00:00
|
|
|
|
|
|
|
void g_hash_table_destroy(GHashTable *hash_table);
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, gpointer user_data);
|
|
|
|
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data);
|
2019-04-26 23:31:04 +00:00
|
|
|
GList *g_hash_table_get_keys(GHashTable *hash_table);
|
2020-03-21 19:42:02 +00:00
|
|
|
gboolean g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value);
|
2018-03-12 01:48:48 +00:00
|
|
|
void g_hash_table_replace(GHashTable *hash_table, gpointer key, gpointer value);
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key);
|
2016-12-18 22:56:58 +00:00
|
|
|
GHashTable *g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func);
|
2018-03-12 01:48:48 +00:00
|
|
|
GHashTable *g_hash_table_new_full(GHashFunc hash_func, GEqualFunc key_equal_func,
|
2016-12-18 22:56:58 +00:00
|
|
|
GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func);
|
|
|
|
void g_hash_table_remove_all(GHashTable *hash_table);
|
2016-12-25 17:35:42 +00:00
|
|
|
gboolean g_hash_table_remove(GHashTable *hash_table, gconstpointer key);
|
2016-12-18 22:56:58 +00:00
|
|
|
void g_hash_table_unref(GHashTable *hash_table);
|
|
|
|
GHashTable *g_hash_table_ref(GHashTable *hash_table);
|
2016-12-19 20:32:06 +00:00
|
|
|
guint g_hash_table_size(GHashTable *hash_table);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2018-02-21 18:04:14 +00:00
|
|
|
void g_hash_table_iter_init(GHashTableIter *iter, GHashTable *hash_table);
|
|
|
|
gboolean g_hash_table_iter_next(GHashTableIter *iter, gpointer *key, gpointer *value);
|
|
|
|
GHashTable *g_hash_table_iter_get_hash_table(GHashTableIter *iter);
|
|
|
|
void g_hash_table_iter_remove(GHashTableIter *iter);
|
|
|
|
void g_hash_table_iter_steal(GHashTableIter *iter);
|
|
|
|
|
2016-12-18 22:56:58 +00:00
|
|
|
/* replacement for g_malloc dependency */
|
2016-12-25 17:35:42 +00:00
|
|
|
void g_free(gpointer ptr);
|
|
|
|
gpointer g_malloc(size_t size);
|
|
|
|
gpointer g_malloc0(size_t size);
|
|
|
|
gpointer g_try_malloc0(size_t size);
|
|
|
|
gpointer g_realloc(gpointer ptr, size_t size);
|
2016-12-18 22:56:58 +00:00
|
|
|
char *g_strdup(const char *str);
|
|
|
|
char *g_strdup_printf(const char *format, ...);
|
|
|
|
char *g_strdup_vprintf(const char *format, va_list ap);
|
|
|
|
char *g_strndup(const char *str, size_t n);
|
|
|
|
void g_strfreev(char **v);
|
2016-12-25 17:35:42 +00:00
|
|
|
gpointer g_memdup(gconstpointer mem, size_t byte_size);
|
|
|
|
gpointer g_new_(size_t sz, size_t n_structs);
|
|
|
|
gpointer g_new0_(size_t sz, size_t n_structs);
|
|
|
|
gpointer g_renew_(size_t sz, gpointer mem, size_t n_structs);
|
2016-12-26 14:36:47 +00:00
|
|
|
gchar* g_strconcat (const gchar *string1, ...);
|
|
|
|
gchar** g_strsplit (const gchar *string,
|
|
|
|
const gchar *delimiter,
|
|
|
|
gint max_tokens);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2018-02-14 14:08:13 +00:00
|
|
|
/* replacement for base64 dependency */
|
|
|
|
gsize g_base64_encode_close(gboolean break_lines, gchar *out,
|
|
|
|
gint *state, gint *save);
|
|
|
|
gchar *g_base64_encode(const guchar *data, gsize len);
|
|
|
|
guchar *g_base64_decode(const gchar *text, gsize *out_len);
|
|
|
|
guchar *g_base64_decode_inplace(gchar *text, gsize *out_len);
|
2016-12-18 22:56:58 +00:00
|
|
|
|
2019-02-15 22:41:32 +00:00
|
|
|
extern const gchar * const g_utf8_skip;
|
|
|
|
#define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(const guchar *)(p)])
|
|
|
|
char* g_utf8_strreverse (const char *str, long long len);
|
|
|
|
|
|
|
|
typedef struct _GPatternSpec GPatternSpec;
|
|
|
|
|
|
|
|
GPatternSpec* g_pattern_spec_new(const char *pattern);
|
|
|
|
void g_pattern_spec_free(GPatternSpec *pspec);
|
|
|
|
int g_pattern_spec_equal(GPatternSpec *pspec1, GPatternSpec *pspec2);
|
|
|
|
int g_pattern_match(GPatternSpec *pspec, unsigned int string_length, const char *string, const char *string_reversed);
|
|
|
|
int g_pattern_match_string(GPatternSpec *pspec, const char *string);
|
|
|
|
int g_pattern_match_simple(const char *pattern, const char *string);
|
|
|
|
|
2016-12-18 22:56:58 +00:00
|
|
|
#define g_new(struct_type, n_structs) ((struct_type*)g_new_(sizeof(struct_type), n_structs))
|
|
|
|
#define g_new0(struct_type, n_structs) ((struct_type*)g_new0_(sizeof(struct_type), n_structs))
|
|
|
|
#define g_renew(struct_type, mem, n_structs) ((struct_type*)g_renew_(sizeof(struct_type), mem, n_structs))
|
|
|
|
|
|
|
|
#endif
|