From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: Luiz Capitulino <lcapitulino@redhat.com>
Subject: [Qemu-devel] [PATCH 4/7] add mutable qstring functions
Date: Sat, 17 Oct 2009 09:55:33 +0200 [thread overview]
Message-ID: <1255766136-3028-5-git-send-email-pbonzini@redhat.com> (raw)
In-Reply-To: <1255766136-3028-1-git-send-email-pbonzini@redhat.com>
qemu does not have a string buffer object, so I added this capability
to QString.
Cc: Luiz Capitulino <lcapitulino@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
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
next prev parent reply other threads:[~2009-10-17 7:55 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-10-17 7:55 [Qemu-devel] [PATCH 0/7] Add JSON enconding and formatted printing to QObject Paolo Bonzini
2009-10-17 7:55 ` [Qemu-devel] [PATCH 1/7] add qemu_memdup Paolo Bonzini
2009-10-17 7:55 ` [Qemu-devel] [PATCH 2/7] allow passing NULL to qobject_type Paolo Bonzini
2009-10-17 7:55 ` [Qemu-devel] [PATCH 3/7] forward declare all QObject subclasses in qobject.h Paolo Bonzini
2009-10-17 13:02 ` Anthony Liguori
2009-10-17 7:55 ` Paolo Bonzini [this message]
2009-10-17 13:03 ` [Qemu-devel] [PATCH 4/7] add mutable qstring functions Anthony Liguori
2009-10-17 7:55 ` [Qemu-devel] [PATCH 5/7] add json encoder for qobjects Paolo Bonzini
2009-10-17 13:03 ` Anthony Liguori
2009-10-17 13:44 ` Paolo Bonzini
2009-10-17 16:20 ` Anthony Liguori
2009-10-17 7:55 ` [Qemu-devel] [PATCH 6/7] add testsuite for qobject json encoder Paolo Bonzini
2009-10-17 7:55 ` [Qemu-devel] [PATCH 7/7] add formatted printing of QObjects Paolo Bonzini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1255766136-3028-5-git-send-email-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=lcapitulino@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).