[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 4/7] add mutable qstring functions
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PATCH 4/7] add mutable qstring functions |
Date: |
Sat, 17 Oct 2009 09:55:33 +0200 |
qemu does not have a string buffer object, so I added this capability
to QString.
Cc: Luiz Capitulino <address@hidden>
Signed-off-by: Paolo Bonzini <address@hidden>
---
check-qstring.c | 79 ++++++++++++++++++++++++++++++++++++++++-
qstring.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
qstring.h | 5 +++
3 files changed, 186 insertions(+), 3 deletions(-)
diff --git a/check-qstring.c b/check-qstring.c
index ea4dfd0..842cd7f 100644
--- a/check-qstring.c
+++ b/check-qstring.c
@@ -17,6 +17,23 @@
* (with some violations to access 'private' data)
*/
+START_TEST(qstring_new_test)
+{
+ QString *qstring;
+
+ qstring = qstring_new();
+ fail_unless(qstring != NULL);
+ fail_unless(qstring->base.refcnt == 1);
+ fail_unless(qstring->n == 0);
+ fail_unless(qstring->alloc < 1000);
+ fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
+
+ // destroy doesn't exit yet
+ qemu_free(qstring->string);
+ qemu_free(qstring);
+}
+END_TEST
+
START_TEST(qstring_from_str_test)
{
QString *qstring;
@@ -25,7 +42,9 @@ START_TEST(qstring_from_str_test)
qstring = qstring_from_str(str);
fail_unless(qstring != NULL);
fail_unless(qstring->base.refcnt == 1);
- fail_unless(strcmp(str, qstring->string) == 0);
+ fail_unless(qstring->n == 4);
+ fail_unless(qstring->alloc >= 4);
+ fail_unless(memcmp(str, qstring->string, 4) == 0);
fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
// destroy doesn't exit yet
@@ -55,6 +74,60 @@ START_TEST(qstring_get_str_test)
}
END_TEST
+START_TEST(qstring_append_test)
+{
+ QString *qstring;
+ const char *str = "QEM";
+ const char *longstr = "QEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMUQEMU";
+
+ qstring = qstring_from_str(str);
+ qstring_append(qstring, "U");
+ fail_unless(qstring->n == 4);
+ fail_unless(qstring->alloc >= 4);
+ fail_unless(memcmp(longstr, qstring->string, 4) == 0);
+
+ qstring_append(qstring, "Q");
+ fail_unless(qstring->n == 5);
+ fail_unless(qstring->alloc >= 5);
+ fail_unless(memcmp(longstr, qstring->string, 5) == 0);
+
+ qstring_append(qstring, longstr + 5);
+ fail_unless(qstring->n == strlen (longstr));
+ fail_unless(qstring->alloc >= qstring->n);
+ fail_unless(memcmp(longstr, qstring->string, qstring->n) == 0);
+ QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_append_ch_test)
+{
+ QString *qstring;
+ const char *str = "QEM";
+
+ qstring = qstring_from_str(str);
+ qstring_append_ch(qstring, 'U');
+ fail_unless(qstring->n == 4);
+ fail_unless(qstring->alloc >= 4);
+ fail_unless(memcmp("QEMU", qstring->string, 4) == 0);
+ QDECREF(qstring);
+}
+END_TEST
+
+START_TEST(qstring_append_escaped_test)
+{
+ QString *qstring;
+ const char *str = "\"Q\x0EMU\t";
+ const char *result = "\\\"Q\\u000eMU\\t";
+
+ qstring = qstring_new();
+ qstring_append_escaped(qstring, str);
+ fail_unless(qstring->n == strlen (result));
+ fail_unless(qstring->alloc >= qstring->n);
+ fail_unless(memcmp(result, qstring->string, strlen (result)) == 0);
+ QDECREF(qstring);
+}
+END_TEST
+
START_TEST(qobject_to_qstring_test)
{
QString *qstring;
@@ -75,9 +148,13 @@ static Suite *qstring_suite(void)
qstring_public_tcase = tcase_create("Public Interface");
suite_add_tcase(s, qstring_public_tcase);
+ tcase_add_test(qstring_public_tcase, qstring_new_test);
tcase_add_test(qstring_public_tcase, qstring_from_str_test);
tcase_add_test(qstring_public_tcase, qstring_destroy_test);
tcase_add_test(qstring_public_tcase, qstring_get_str_test);
+ tcase_add_test(qstring_public_tcase, qstring_append_test);
+ tcase_add_test(qstring_public_tcase, qstring_append_ch_test);
+ tcase_add_test(qstring_public_tcase, qstring_append_escaped_test);
tcase_add_test(qstring_public_tcase, qobject_to_qstring_test);
return s;
diff --git a/qstring.c b/qstring.c
index 6d411da..ab77fba 100644
--- a/qstring.c
+++ b/qstring.c
@@ -21,6 +21,29 @@ static const QType qstring_type = {
};
/**
+ * Invariant: all strings have an empty byte at the end so that
+ * it is easy to convert them to C strings.
+ */
+
+
+/**
+ * qstring_new(): Create a new empty QString
+ *
+ * Return strong reference.
+ */
+QString *qstring_new(void)
+{
+ QString *qstring;
+ qstring = qemu_malloc(sizeof(*qstring));
+ qstring->n = 0;
+ qstring->alloc = 16;
+ qstring->string = qemu_malloc(qstring->alloc);
+ QOBJECT_INIT(qstring, &qstring_type);
+
+ return qstring;
+}
+
+/**
* qstring_from_str(): Create a new QString from a regular C string
*
* Return strong reference.
@@ -28,15 +51,91 @@ static const QType qstring_type = {
QString *qstring_from_str(const char *str)
{
QString *qstring;
+ size_t n = strlen(str);
qstring = qemu_malloc(sizeof(*qstring));
- qstring->string = qemu_strdup(str);
+ qstring->n = n;
+ qstring->alloc = n + 1;
+ qstring->string = qemu_memdup(str, qstring->alloc);
QOBJECT_INIT(qstring, &qstring_type);
return qstring;
}
/**
+ * qstring_append(): Append a regular C string to a QString
+ */
+void qstring_append(QString *qstring, const char *str)
+{
+ size_t n = strlen(str);
+ size_t total = qstring->n + n + 1;
+
+ if (total > qstring->alloc) {
+ if (qstring->alloc * 2 < total) {
+ qstring->alloc = total;
+ } else {
+ qstring->alloc *= 2;
+ }
+ qstring->string = qemu_realloc (qstring->string, qstring->alloc);
+ }
+ memcpy (qstring->string + qstring->n, str, n + 1);
+ qstring->n += n;
+}
+
+/**
+ * qstring_append(): Append a regular C string to a QString, escaping it
+ * according to JSON syntax.
+ */
+void qstring_append_escaped(QString *qstring, const char *str)
+{
+ for (; *str; str++) {
+ unsigned char ch = *str;
+ switch (*str) {
+ case '\f': ch = 'f'; goto backslash;
+ case '\n': ch = 'n'; goto backslash;
+ case '\r': ch = 'r'; goto backslash;
+ case '\t': ch = 't'; goto backslash;
+ case '\b': ch = 'b'; goto backslash;
+
+ backslash:
+ case '\\':
+ case '\"':
+ qstring_append_ch (qstring, '\\');
+ break;
+
+ default:
+ if (ch < 0x20) {
+ qstring_append_ch (qstring, '\\');
+ qstring_append_ch (qstring, 'u');
+ qstring_append_ch (qstring, '0');
+ qstring_append_ch (qstring, '0');
+ qstring_append_ch (qstring, '0' + (ch >> 4));
+ ch = (ch & 15) + ((ch & 15) > 9 ? 'a' - 10 : '0');
+ }
+ break;
+ }
+
+ qstring_append_ch (qstring, ch);
+ }
+}
+
+/**
+ * qstring_append_ch(): Append a character to a QString
+ */
+void qstring_append_ch(QString *qstring, char c)
+{
+ if (qstring->n == qstring->alloc - 1) {
+ if (qstring->alloc < 10) {
+ qstring->alloc = 10;
+ } else {
+ qstring->alloc *= 2;
+ }
+ qstring->string = qemu_realloc (qstring->string, qstring->alloc);
+ }
+ qstring->string[qstring->n++] = c;
+}
+
+/**
* qobject_to_qstring(): Convert a QObject to a QString
*/
QString *qobject_to_qstring(const QObject *obj)
@@ -51,10 +150,12 @@ QString *qobject_to_qstring(const QObject *obj)
* qstring_get_str(): Return a pointer to the stored string
*
* NOTE: Should be used with caution, if the object is deallocated
- * this pointer becomes invalid.
+ * or modified this pointer becomes invalid.
*/
const char *qstring_get_str(const QString *qstring)
{
+ /* NULL-terminate it here. */
+ qstring->string[qstring->n] = 0;
return qstring->string;
}
diff --git a/qstring.h b/qstring.h
index e012cb7..6e16d58 100644
--- a/qstring.h
+++ b/qstring.h
@@ -5,11 +5,16 @@
typedef struct QString {
QObject_HEAD;
+ size_t n, alloc;
char *string;
} QString;
+QString *qstring_new(void);
QString *qstring_from_str(const char *str);
const char *qstring_get_str(const QString *qstring);
+void qstring_append(QString *qstring, const char *str);
+void qstring_append_escaped(QString *qstring, const char *str);
+void qstring_append_ch(QString *qstring, char c);
QString *qobject_to_qstring(const QObject *obj);
#endif /* QSTRING_H */
--
1.6.2.5
- [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject, Paolo Bonzini, 2009/10/17
- [Qemu-devel] [PATCH 1/7] add qemu_memdup, Paolo Bonzini, 2009/10/17
- [Qemu-devel] [PATCH 2/7] allow passing NULL to qobject_type, Paolo Bonzini, 2009/10/17
- [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h, Paolo Bonzini, 2009/10/17
- [Qemu-devel] [PATCH 4/7] add mutable qstring functions,
Paolo Bonzini <=
- [Qemu-devel] [PATCH 6/7] add testsuite for qobject json encoder, Paolo Bonzini, 2009/10/17
- [Qemu-devel] [PATCH 5/7] add json encoder for qobjects, Paolo Bonzini, 2009/10/17
- [Qemu-devel] [PATCH 7/7] add formatted printing of QObjects, Paolo Bonzini, 2009/10/17