]> git.proxmox.com Git - qemu.git/blobdiff - qapi/qmp-input-visitor.c
qga: distinguish binary modes in "guest_file_open_modes" map
[qemu.git] / qapi / qmp-input-visitor.c
index 012cd0a0714611d8268ee5ddabb7372d650d037f..67fb127050ac6379d8ae2d605f5256263487e36d 100644 (file)
  *
  */
 
-#include "qmp-input-visitor.h"
-#include "qapi/qapi-visit-impl.h"
-#include "qemu-queue.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi/visitor-impl.h"
+#include "qemu/queue.h"
 #include "qemu-common.h"
-#include "qemu-objects.h"
-#include "qerror.h"
+#include "qapi/qmp/types.h"
+#include "qapi/qmp/qerror.h"
 
 #define QIV_STACK_SIZE 1024
 
 typedef struct StackObject
 {
-    const QObject *obj;
-    const  QListEntry *entry;
+    QObject *obj;
+    const QListEntry *entry;
+    GHashTable *h;
 } StackObject;
 
 struct QmpInputVisitor
 {
     Visitor visitor;
-    QObject *obj;
     StackObject stack[QIV_STACK_SIZE];
     int nb_stack;
+    bool strict;
 };
 
 static QmpInputVisitor *to_qiv(Visitor *v)
@@ -39,21 +40,18 @@ static QmpInputVisitor *to_qiv(Visitor *v)
     return container_of(v, QmpInputVisitor, visitor);
 }
 
-static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
-                                           const char *name)
+static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
+                                     const char *name)
 {
-    const QObject *qobj;
-
-    if (qiv->nb_stack == 0) {
-        qobj = qiv->obj;
-    } else {
-        qobj = qiv->stack[qiv->nb_stack - 1].obj;
-    }
+    QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
 
     if (qobj) {
         if (name && qobject_type(qobj) == QTYPE_QDICT) {
+            if (qiv->stack[qiv->nb_stack - 1].h) {
+                g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name);
+            }
             return qdict_get(qobject_to_qdict(qobj), name);
-        } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
+        } else if (qiv->stack[qiv->nb_stack - 1].entry) {
             return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
         }
     }
@@ -61,34 +59,66 @@ static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
     return qobj;
 }
 
-static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
+static void qdict_add_key(const char *key, QObject *obj, void *opaque)
 {
-    qiv->stack[qiv->nb_stack].obj = obj;
-    if (qobject_type(obj) == QTYPE_QLIST) {
-        qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
-    }
-    qiv->nb_stack++;
+    GHashTable *h = opaque;
+    g_hash_table_insert(h, (gpointer) key, NULL);
+}
+
+static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
+{
+    GHashTable *h;
 
     if (qiv->nb_stack >= QIV_STACK_SIZE) {
         error_set(errp, QERR_BUFFER_OVERRUN);
         return;
     }
+
+    qiv->stack[qiv->nb_stack].obj = obj;
+    qiv->stack[qiv->nb_stack].entry = NULL;
+    qiv->stack[qiv->nb_stack].h = NULL;
+
+    if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
+        h = g_hash_table_new(g_str_hash, g_str_equal);
+        qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
+        qiv->stack[qiv->nb_stack].h = h;
+    }
+
+    qiv->nb_stack++;
+}
+
+/** Only for qmp_input_pop. */
+static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
+{
+    *(const char **)user_pkey = (const char *)key;
+    return TRUE;
 }
 
 static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
 {
-    qiv->nb_stack--;
-    if (qiv->nb_stack < 0) {
-        error_set(errp, QERR_BUFFER_OVERRUN);
-        return;
+    assert(qiv->nb_stack > 0);
+
+    if (qiv->strict) {
+        GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
+        if (top_ht) {
+            if (g_hash_table_size(top_ht)) {
+                const char *key;
+                g_hash_table_find(top_ht, always_true, &key);
+                error_set(errp, QERR_QMP_EXTRA_MEMBER, key);
+            }
+            g_hash_table_unref(top_ht);
+        }
     }
+
+    qiv->nb_stack--;
 }
 
 static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
                                    const char *name, size_t size, Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
+    Error *err = NULL;
 
     if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -96,8 +126,9 @@ static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
         return;
     }
 
-    qmp_input_push(qiv, qobj, errp);
-    if (error_is_set(errp)) {
+    qmp_input_push(qiv, qobj, &err);
+    if (err) {
+        error_propagate(errp, err);
         return;
     }
 
@@ -116,7 +147,7 @@ static void qmp_input_end_struct(Visitor *v, Error **errp)
 static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
 
     if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -133,18 +164,24 @@ static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
     QmpInputVisitor *qiv = to_qiv(v);
     GenericList *entry;
     StackObject *so = &qiv->stack[qiv->nb_stack - 1];
+    bool first;
+
+    if (so->entry == NULL) {
+        so->entry = qlist_first(qobject_to_qlist(so->obj));
+        first = true;
+    } else {
+        so->entry = qlist_next(so->entry);
+        first = false;
+    }
 
     if (so->entry == NULL) {
         return NULL;
     }
 
     entry = g_malloc0(sizeof(*entry));
-    if (*list) {
-        so->entry = qlist_next(so->entry);
-        if (so->entry == NULL) {
-            g_free(entry);
-            return NULL;
-        }
+    if (first) {
+        *list = entry;
+    } else {
         (*list)->next = entry;
     }
 
@@ -162,7 +199,7 @@ static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
                                Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
 
     if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -177,7 +214,7 @@ static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
                                 Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
 
     if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -192,7 +229,7 @@ static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
                                Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
 
     if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@@ -207,22 +244,27 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
                                   Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
 
-    if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
+    if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT &&
+        qobject_type(qobj) != QTYPE_QINT)) {
         error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
-                  "double");
+                  "number");
         return;
     }
 
-    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+    if (qobject_type(qobj) == QTYPE_QINT) {
+        *obj = qint_get_int(qobject_to_qint(qobj));
+    } else {
+        *obj = qfloat_get_double(qobject_to_qfloat(qobj));
+    }
 }
 
 static void qmp_input_start_optional(Visitor *v, bool *present,
                                      const char *name, Error **errp)
 {
     QmpInputVisitor *qiv = to_qiv(v);
-    const QObject *qobj = qmp_input_get_object(qiv, name);
+    QObject *qobj = qmp_input_get_object(qiv, name);
 
     if (!qobj) {
         *present = false;
@@ -232,10 +274,6 @@ static void qmp_input_start_optional(Visitor *v, bool *present,
     *present = true;
 }
 
-static void qmp_input_end_optional(Visitor *v, Error **errp)
-{
-}
-
 Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
 {
     return &v->visitor;
@@ -243,7 +281,7 @@ Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
 
 void qmp_input_visitor_cleanup(QmpInputVisitor *v)
 {
-    qobject_decref(v->obj);
+    qobject_decref(v->stack[0].obj);
     g_free(v);
 }
 
@@ -264,10 +302,19 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
     v->visitor.type_str = qmp_input_type_str;
     v->visitor.type_number = qmp_input_type_number;
     v->visitor.start_optional = qmp_input_start_optional;
-    v->visitor.end_optional = qmp_input_end_optional;
 
-    v->obj = obj;
-    qobject_incref(v->obj);
+    qmp_input_push(v, obj, NULL);
+    qobject_incref(obj);
+
+    return v;
+}
+
+QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj)
+{
+    QmpInputVisitor *v;
+
+    v = qmp_input_visitor_new(obj);
+    v->strict = true;
 
     return v;
 }