2012-02-09 12:36:37 +04:00
|
|
|
/*
|
|
|
|
* String parsing visitor
|
|
|
|
*
|
2016-01-29 16:48:59 +03:00
|
|
|
* Copyright Red Hat, Inc. 2012-2016
|
2012-02-09 12:36:37 +04:00
|
|
|
*
|
|
|
|
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
2018-11-21 19:44:18 +03:00
|
|
|
* David Hildenbrand <david@redhat.com>
|
2012-02-09 12:36:37 +04:00
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
|
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
|
|
*/
|
|
|
|
|
2016-01-29 20:49:57 +03:00
|
|
|
#include "qemu/osdep.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
|
|
|
#include "qapi/error.h"
|
2012-12-17 21:19:43 +04:00
|
|
|
#include "qapi/string-input-visitor.h"
|
|
|
|
#include "qapi/visitor-impl.h"
|
|
|
|
#include "qapi/qmp/qerror.h"
|
2017-11-14 21:01:23 +03:00
|
|
|
#include "qapi/qmp/qnull.h"
|
2014-02-08 14:01:44 +04:00
|
|
|
#include "qemu/option.h"
|
2018-11-21 19:44:15 +03:00
|
|
|
#include "qemu/cutils.h"
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
typedef enum ListMode {
|
|
|
|
/* no list parsing active / no list expected */
|
|
|
|
LM_NONE,
|
|
|
|
/* we have an unparsed string remaining */
|
|
|
|
LM_UNPARSED,
|
|
|
|
/* we have an unfinished int64 range */
|
|
|
|
LM_INT64_RANGE,
|
|
|
|
/* we have an unfinished uint64 range */
|
|
|
|
LM_UINT64_RANGE,
|
|
|
|
/* we have parsed the string completely and no range is remaining */
|
|
|
|
LM_END,
|
|
|
|
} ListMode;
|
|
|
|
|
|
|
|
/* protect against DOS attacks, limit the amount of elements per range */
|
|
|
|
#define RANGE_MAX_ELEMENTS 65536
|
|
|
|
|
|
|
|
typedef union RangeElement {
|
|
|
|
int64_t i64;
|
|
|
|
uint64_t u64;
|
|
|
|
} RangeElement;
|
2012-02-09 12:36:37 +04:00
|
|
|
|
|
|
|
struct StringInputVisitor
|
|
|
|
{
|
|
|
|
Visitor visitor;
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
/* List parsing state */
|
|
|
|
ListMode lm;
|
|
|
|
RangeElement rangeNext;
|
|
|
|
RangeElement rangeEnd;
|
|
|
|
const char *unparsed_string;
|
|
|
|
void *list;
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
/* The original string to parse */
|
2012-02-09 12:36:37 +04:00
|
|
|
const char *string;
|
|
|
|
};
|
|
|
|
|
2016-01-29 16:48:38 +03:00
|
|
|
static StringInputVisitor *to_siv(Visitor *v)
|
|
|
|
{
|
|
|
|
return container_of(v, StringInputVisitor, visitor);
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool start_list(Visitor *v, const char *name, GenericList **list,
|
2018-11-21 19:44:18 +03:00
|
|
|
size_t size, Error **errp)
|
2014-06-10 15:15:27 +04:00
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm == LM_NONE);
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:34 +03:00
|
|
|
siv->list = list;
|
2018-11-21 19:44:18 +03:00
|
|
|
siv->unparsed_string = siv->string;
|
qapi: Simplify semantics of visit_next_list()
The semantics of the list visit are somewhat baroque, with the
following pseudocode when FooList is used:
start()
for (prev = head; cur = next(prev); prev = &cur) {
visit(&cur->value)
}
Note that these semantics (advance before visit) requires that
the first call to next() return the list head, while all other
calls return the next element of the list; that is, every visitor
implementation is required to track extra state to decide whether
to return the input as-is, or to advance. It also requires an
argument of 'GenericList **' to next(), solely because the first
iteration might need to modify the caller's GenericList head, so
that all other calls have to do a layer of dereferencing.
Thankfully, we only have two uses of list visits in the entire
code base: one in spapr_drc (which completely avoids
visit_next_list(), feeding in integers from a different source
than uint8List), and one in qapi-visit.py. That is, all other
list visitors are generated in qapi-visit.c, and share the same
paradigm based on a qapi FooList type, so we can refactor how
lists are laid out with minimal churn among clients.
We can greatly simplify things by hoisting the special case
into the start() routine, and flipping the order in the loop
to visit before advance:
start(head)
for (tail = *head; tail; tail = next(tail)) {
visit(&tail->value)
}
With the simpler semantics, visitors have less state to track,
the argument to next() is reduced to 'GenericList *', and it
also becomes obvious whether an input visitor is allocating a
FooList during visit_start_list() (rather than the old way of
not knowing if an allocation happened until the first
visit_next_list()). As a minor drawback, we now allocate in
two functions instead of one, and have to pass the size to
both functions (unless we were to tweak the input visitors to
cache the size to start_list for reuse during next_list, but
that defeats the goal of less visitor state).
The signature of visit_start_list() is chosen to match
visit_start_struct(), with the new parameters after 'name'.
The spapr_drc case is a virtual visit, done by passing NULL for
list, similarly to how NULL is passed to visit_start_struct()
when a qapi type is not used in those visits. It was easy to
provide these semantics for qmp-output and dealloc visitors,
and a bit harder for qmp-input (several prerequisite patches
refactored things to make this patch straightforward). But it
turned out that the string and opts visitors munge enough other
state during visit_next_list() to make it easier to just
document and require a GenericList visit for now; an assertion
will remind us to adjust things if we need the semantics in the
future.
Several pre-requisite cleanup patches made the reshuffling of
the various visitors easier; particularly the qmp input visitor.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-24-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:31 +03:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
if (!siv->string[0]) {
|
|
|
|
if (list) {
|
|
|
|
*list = NULL;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
2018-11-21 19:44:18 +03:00
|
|
|
siv->lm = LM_END;
|
qapi: Simplify semantics of visit_next_list()
The semantics of the list visit are somewhat baroque, with the
following pseudocode when FooList is used:
start()
for (prev = head; cur = next(prev); prev = &cur) {
visit(&cur->value)
}
Note that these semantics (advance before visit) requires that
the first call to next() return the list head, while all other
calls return the next element of the list; that is, every visitor
implementation is required to track extra state to decide whether
to return the input as-is, or to advance. It also requires an
argument of 'GenericList **' to next(), solely because the first
iteration might need to modify the caller's GenericList head, so
that all other calls have to do a layer of dereferencing.
Thankfully, we only have two uses of list visits in the entire
code base: one in spapr_drc (which completely avoids
visit_next_list(), feeding in integers from a different source
than uint8List), and one in qapi-visit.py. That is, all other
list visitors are generated in qapi-visit.c, and share the same
paradigm based on a qapi FooList type, so we can refactor how
lists are laid out with minimal churn among clients.
We can greatly simplify things by hoisting the special case
into the start() routine, and flipping the order in the loop
to visit before advance:
start(head)
for (tail = *head; tail; tail = next(tail)) {
visit(&tail->value)
}
With the simpler semantics, visitors have less state to track,
the argument to next() is reduced to 'GenericList *', and it
also becomes obvious whether an input visitor is allocating a
FooList during visit_start_list() (rather than the old way of
not knowing if an allocation happened until the first
visit_next_list()). As a minor drawback, we now allocate in
two functions instead of one, and have to pass the size to
both functions (unless we were to tweak the input visitors to
cache the size to start_list for reuse during next_list, but
that defeats the goal of less visitor state).
The signature of visit_start_list() is chosen to match
visit_start_struct(), with the new parameters after 'name'.
The spapr_drc case is a virtual visit, done by passing NULL for
list, similarly to how NULL is passed to visit_start_struct()
when a qapi type is not used in those visits. It was easy to
provide these semantics for qmp-output and dealloc visitors,
and a bit harder for qmp-input (several prerequisite patches
refactored things to make this patch straightforward). But it
turned out that the string and opts visitors munge enough other
state during visit_next_list() to make it easier to just
document and require a GenericList visit for now; an assertion
will remind us to adjust things if we need the semantics in the
future.
Several pre-requisite cleanup patches made the reshuffling of
the various visitors easier; particularly the qmp input visitor.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-24-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:31 +03:00
|
|
|
} else {
|
2018-11-21 19:44:18 +03:00
|
|
|
if (list) {
|
|
|
|
*list = g_malloc0(size);
|
|
|
|
}
|
|
|
|
siv->lm = LM_UNPARSED;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
|
|
|
|
qapi: Simplify semantics of visit_next_list()
The semantics of the list visit are somewhat baroque, with the
following pseudocode when FooList is used:
start()
for (prev = head; cur = next(prev); prev = &cur) {
visit(&cur->value)
}
Note that these semantics (advance before visit) requires that
the first call to next() return the list head, while all other
calls return the next element of the list; that is, every visitor
implementation is required to track extra state to decide whether
to return the input as-is, or to advance. It also requires an
argument of 'GenericList **' to next(), solely because the first
iteration might need to modify the caller's GenericList head, so
that all other calls have to do a layer of dereferencing.
Thankfully, we only have two uses of list visits in the entire
code base: one in spapr_drc (which completely avoids
visit_next_list(), feeding in integers from a different source
than uint8List), and one in qapi-visit.py. That is, all other
list visitors are generated in qapi-visit.c, and share the same
paradigm based on a qapi FooList type, so we can refactor how
lists are laid out with minimal churn among clients.
We can greatly simplify things by hoisting the special case
into the start() routine, and flipping the order in the loop
to visit before advance:
start(head)
for (tail = *head; tail; tail = next(tail)) {
visit(&tail->value)
}
With the simpler semantics, visitors have less state to track,
the argument to next() is reduced to 'GenericList *', and it
also becomes obvious whether an input visitor is allocating a
FooList during visit_start_list() (rather than the old way of
not knowing if an allocation happened until the first
visit_next_list()). As a minor drawback, we now allocate in
two functions instead of one, and have to pass the size to
both functions (unless we were to tweak the input visitors to
cache the size to start_list for reuse during next_list, but
that defeats the goal of less visitor state).
The signature of visit_start_list() is chosen to match
visit_start_struct(), with the new parameters after 'name'.
The spapr_drc case is a virtual visit, done by passing NULL for
list, similarly to how NULL is passed to visit_start_struct()
when a qapi type is not used in those visits. It was easy to
provide these semantics for qmp-output and dealloc visitors,
and a bit harder for qmp-input (several prerequisite patches
refactored things to make this patch straightforward). But it
turned out that the string and opts visitors munge enough other
state during visit_next_list() to make it easier to just
document and require a GenericList visit for now; an assertion
will remind us to adjust things if we need the semantics in the
future.
Several pre-requisite cleanup patches made the reshuffling of
the various visitors easier; particularly the qmp input visitor.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-24-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:31 +03:00
|
|
|
static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
|
2014-06-10 15:15:27 +04:00
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
switch (siv->lm) {
|
|
|
|
case LM_END:
|
2014-06-10 15:15:27 +04:00
|
|
|
return NULL;
|
2018-11-21 19:44:18 +03:00
|
|
|
case LM_INT64_RANGE:
|
|
|
|
case LM_UINT64_RANGE:
|
|
|
|
case LM_UNPARSED:
|
|
|
|
/* we have an unparsed string or something left in a range */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort();
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
|
|
|
|
qapi: Simplify semantics of visit_next_list()
The semantics of the list visit are somewhat baroque, with the
following pseudocode when FooList is used:
start()
for (prev = head; cur = next(prev); prev = &cur) {
visit(&cur->value)
}
Note that these semantics (advance before visit) requires that
the first call to next() return the list head, while all other
calls return the next element of the list; that is, every visitor
implementation is required to track extra state to decide whether
to return the input as-is, or to advance. It also requires an
argument of 'GenericList **' to next(), solely because the first
iteration might need to modify the caller's GenericList head, so
that all other calls have to do a layer of dereferencing.
Thankfully, we only have two uses of list visits in the entire
code base: one in spapr_drc (which completely avoids
visit_next_list(), feeding in integers from a different source
than uint8List), and one in qapi-visit.py. That is, all other
list visitors are generated in qapi-visit.c, and share the same
paradigm based on a qapi FooList type, so we can refactor how
lists are laid out with minimal churn among clients.
We can greatly simplify things by hoisting the special case
into the start() routine, and flipping the order in the loop
to visit before advance:
start(head)
for (tail = *head; tail; tail = next(tail)) {
visit(&tail->value)
}
With the simpler semantics, visitors have less state to track,
the argument to next() is reduced to 'GenericList *', and it
also becomes obvious whether an input visitor is allocating a
FooList during visit_start_list() (rather than the old way of
not knowing if an allocation happened until the first
visit_next_list()). As a minor drawback, we now allocate in
two functions instead of one, and have to pass the size to
both functions (unless we were to tweak the input visitors to
cache the size to start_list for reuse during next_list, but
that defeats the goal of less visitor state).
The signature of visit_start_list() is chosen to match
visit_start_struct(), with the new parameters after 'name'.
The spapr_drc case is a virtual visit, done by passing NULL for
list, similarly to how NULL is passed to visit_start_struct()
when a qapi type is not used in those visits. It was easy to
provide these semantics for qmp-output and dealloc visitors,
and a bit harder for qmp-input (several prerequisite patches
refactored things to make this patch straightforward). But it
turned out that the string and opts visitors munge enough other
state during visit_next_list() to make it easier to just
document and require a GenericList visit for now; an assertion
will remind us to adjust things if we need the semantics in the
future.
Several pre-requisite cleanup patches made the reshuffling of
the various visitors easier; particularly the qmp input visitor.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-24-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:31 +03:00
|
|
|
tail->next = g_malloc0(size);
|
|
|
|
return tail->next;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool check_list(Visitor *v, Error **errp)
|
2017-03-03 15:32:45 +03:00
|
|
|
{
|
|
|
|
const StringInputVisitor *siv = to_siv(v);
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
switch (siv->lm) {
|
|
|
|
case LM_INT64_RANGE:
|
|
|
|
case LM_UINT64_RANGE:
|
|
|
|
case LM_UNPARSED:
|
|
|
|
error_setg(errp, "Fewer list elements expected");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
case LM_END:
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2018-11-21 19:44:18 +03:00
|
|
|
default:
|
|
|
|
abort();
|
2017-03-03 15:32:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:34 +03:00
|
|
|
static void end_list(Visitor *v, void **obj)
|
2014-06-10 15:15:27 +04:00
|
|
|
{
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:34 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm != LM_NONE);
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:34 +03:00
|
|
|
assert(siv->list == obj);
|
2018-11-21 19:44:18 +03:00
|
|
|
siv->list = NULL;
|
|
|
|
siv->unparsed_string = NULL;
|
|
|
|
siv->lm = LM_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int try_parse_int64_list_entry(StringInputVisitor *siv, int64_t *obj)
|
|
|
|
{
|
|
|
|
const char *endptr;
|
|
|
|
int64_t start, end;
|
|
|
|
|
|
|
|
/* parse a simple int64 or range */
|
|
|
|
if (qemu_strtoi64(siv->unparsed_string, &endptr, 0, &start)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
end = start;
|
|
|
|
|
|
|
|
switch (endptr[0]) {
|
|
|
|
case '\0':
|
|
|
|
siv->unparsed_string = endptr;
|
|
|
|
break;
|
|
|
|
case ',':
|
|
|
|
siv->unparsed_string = endptr + 1;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
/* parse the end of the range */
|
|
|
|
if (qemu_strtoi64(endptr + 1, &endptr, 0, &end)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
switch (endptr[0]) {
|
|
|
|
case '\0':
|
|
|
|
siv->unparsed_string = endptr;
|
|
|
|
break;
|
|
|
|
case ',':
|
|
|
|
siv->unparsed_string = endptr + 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have a proper range (with maybe only one element) */
|
|
|
|
siv->lm = LM_INT64_RANGE;
|
|
|
|
siv->rangeNext.i64 = start;
|
|
|
|
siv->rangeEnd.i64 = end;
|
|
|
|
return 0;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_int64(Visitor *v, const char *name, int64_t *obj,
|
qapi: Prefer type_int64 over type_int in visitors
The qapi builtin type 'int' is basically shorthand for the type
'int64'. In fact, since no visitor was providing the optional
type_int64() callback, visit_type_int64() was just always falling
back to type_int(), cementing the equivalence between the types.
However, some visitors are providing a type_uint64() callback.
For purposes of code consistency, it is nicer if all visitors
use the paired type_int64/type_uint64 names rather than the
mismatched type_int/type_uint64. So this patch just renames
the signed int callbacks in place, dropping the type_int()
callback as redundant, and a later patch will focus on the
unsigned int callbacks.
Add some FIXMEs to questionable reuse of errp in code touched
by the rename, while at it (the reuse works as long as the
callbacks don't modify value when setting an error, but it's not
a good example to set) - a later patch will then fix those.
No change in functionality here, although further cleanups are
in the pipeline.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1454075341-13658-14-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:49 +03:00
|
|
|
Error **errp)
|
2012-02-09 12:36:37 +04:00
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2018-11-21 19:44:18 +03:00
|
|
|
int64_t val;
|
|
|
|
|
|
|
|
switch (siv->lm) {
|
|
|
|
case LM_NONE:
|
|
|
|
/* just parse a simple int64, bail out if not completely consumed */
|
|
|
|
if (qemu_strtoi64(siv->string, NULL, 0, &val)) {
|
2020-07-07 19:05:45 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
|
|
|
|
name ? name : "null", "int64");
|
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
}
|
|
|
|
*obj = val;
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2018-11-21 19:44:18 +03:00
|
|
|
case LM_UNPARSED:
|
|
|
|
if (try_parse_int64_list_entry(siv, obj)) {
|
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
|
|
|
|
"list of int64 values or ranges");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
}
|
|
|
|
assert(siv->lm == LM_INT64_RANGE);
|
|
|
|
/* fall through */
|
|
|
|
case LM_INT64_RANGE:
|
|
|
|
/* return the next element in the range */
|
|
|
|
assert(siv->rangeNext.i64 <= siv->rangeEnd.i64);
|
|
|
|
*obj = siv->rangeNext.i64++;
|
|
|
|
|
|
|
|
if (siv->rangeNext.i64 > siv->rangeEnd.i64 || *obj == INT64_MAX) {
|
|
|
|
/* end of range, check if there is more to parse */
|
|
|
|
siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
|
|
|
|
}
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2018-11-21 19:44:18 +03:00
|
|
|
case LM_END:
|
|
|
|
error_setg(errp, "Fewer list elements expected");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
default:
|
|
|
|
abort();
|
2016-04-29 00:45:30 +03:00
|
|
|
}
|
2018-11-21 19:44:18 +03:00
|
|
|
}
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
static int try_parse_uint64_list_entry(StringInputVisitor *siv, uint64_t *obj)
|
|
|
|
{
|
|
|
|
const char *endptr;
|
|
|
|
uint64_t start, end;
|
2014-06-10 15:15:27 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
/* parse a simple uint64 or range */
|
|
|
|
if (qemu_strtou64(siv->unparsed_string, &endptr, 0, &start)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
end = start;
|
|
|
|
|
|
|
|
switch (endptr[0]) {
|
|
|
|
case '\0':
|
|
|
|
siv->unparsed_string = endptr;
|
|
|
|
break;
|
|
|
|
case ',':
|
|
|
|
siv->unparsed_string = endptr + 1;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
/* parse the end of the range */
|
|
|
|
if (qemu_strtou64(endptr + 1, &endptr, 0, &end)) {
|
|
|
|
return -EINVAL;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
2018-11-21 19:44:18 +03:00
|
|
|
if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
|
|
|
|
return -EINVAL;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
2018-11-21 19:44:18 +03:00
|
|
|
switch (endptr[0]) {
|
|
|
|
case '\0':
|
|
|
|
siv->unparsed_string = endptr;
|
|
|
|
break;
|
|
|
|
case ',':
|
|
|
|
siv->unparsed_string = endptr + 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2014-06-10 15:15:27 +04:00
|
|
|
}
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
/* we have a proper range (with maybe only one element) */
|
|
|
|
siv->lm = LM_UINT64_RANGE;
|
|
|
|
siv->rangeNext.u64 = start;
|
|
|
|
siv->rangeEnd.u64 = end;
|
|
|
|
return 0;
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
|
qapi: Make all visitors supply uint64 callbacks
Our qapi visitor contract supports multiple integer visitors,
but left the type_uint64 visitor as optional (falling back on
type_int64); which in turn can lead to awkward behavior with
numbers larger than INT64_MAX (the user has to be aware of
twos complement, and deal with negatives).
This patch does not address the disparity in handling large
values as negatives. It merely moves the fallback from uint64
to int64 from the visitor core to the visitors, where the issue
can actually be fixed, by implementing the missing type_uint64()
callbacks on top of the respective type_int64() callbacks, and
with a FIXME comment explaining why that's wrong.
With that done, we now have a type_uint64() callback in every
driver, so we can make it mandatory from the core. And although
the type_int64() callback can cover the entire valid range of
type_uint{8,16,32} on valid user input, using type_uint64() to
avoid mixed signedness makes more sense.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1454075341-13658-15-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:50 +03:00
|
|
|
Error **errp)
|
|
|
|
{
|
2018-11-21 19:44:18 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
|
|
|
uint64_t val;
|
|
|
|
|
|
|
|
switch (siv->lm) {
|
|
|
|
case LM_NONE:
|
|
|
|
/* just parse a simple uint64, bail out if not completely consumed */
|
|
|
|
if (qemu_strtou64(siv->string, NULL, 0, &val)) {
|
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
|
|
|
|
"uint64");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
}
|
|
|
|
*obj = val;
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2018-11-21 19:44:18 +03:00
|
|
|
case LM_UNPARSED:
|
|
|
|
if (try_parse_uint64_list_entry(siv, obj)) {
|
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
|
|
|
|
"list of uint64 values or ranges");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
}
|
|
|
|
assert(siv->lm == LM_UINT64_RANGE);
|
|
|
|
/* fall through */
|
|
|
|
case LM_UINT64_RANGE:
|
|
|
|
/* return the next element in the range */
|
|
|
|
assert(siv->rangeNext.u64 <= siv->rangeEnd.u64);
|
|
|
|
*obj = siv->rangeNext.u64++;
|
|
|
|
|
|
|
|
if (siv->rangeNext.u64 > siv->rangeEnd.u64 || *obj == UINT64_MAX) {
|
|
|
|
/* end of range, check if there is more to parse */
|
|
|
|
siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
|
|
|
|
}
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2018-11-21 19:44:18 +03:00
|
|
|
case LM_END:
|
|
|
|
error_setg(errp, "Fewer list elements expected");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2018-11-21 19:44:18 +03:00
|
|
|
default:
|
|
|
|
abort();
|
qapi: Make all visitors supply uint64 callbacks
Our qapi visitor contract supports multiple integer visitors,
but left the type_uint64 visitor as optional (falling back on
type_int64); which in turn can lead to awkward behavior with
numbers larger than INT64_MAX (the user has to be aware of
twos complement, and deal with negatives).
This patch does not address the disparity in handling large
values as negatives. It merely moves the fallback from uint64
to int64 from the visitor core to the visitors, where the issue
can actually be fixed, by implementing the missing type_uint64()
callbacks on top of the respective type_int64() callbacks, and
with a FIXME comment explaining why that's wrong.
With that done, we now have a type_uint64() callback in every
driver, so we can make it mandatory from the core. And although
the type_int64() callback can cover the entire valid range of
type_uint{8,16,32} on valid user input, using type_uint64() to
avoid mixed signedness makes more sense.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1454075341-13658-15-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_size(Visitor *v, const char *name, uint64_t *obj,
|
2014-02-08 14:01:44 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2014-02-08 14:01:44 +04:00
|
|
|
uint64_t val;
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm == LM_NONE);
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!parse_option_size(name, siv->string, &val, errp)) {
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2014-02-08 14:01:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
*obj = val;
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2014-02-08 14:01:44 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_bool(Visitor *v, const char *name, bool *obj,
|
2012-02-09 12:36:37 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2012-02-09 12:36:37 +04:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm == LM_NONE);
|
2020-11-03 19:13:39 +03:00
|
|
|
return qapi_bool_parse(name ? name : "null", siv->string, obj, errp);
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_str(Visitor *v, const char *name, char **obj,
|
2012-02-09 12:36:37 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2017-03-03 15:32:36 +03:00
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm == LM_NONE);
|
2017-03-03 15:32:36 +03:00
|
|
|
*obj = g_strdup(siv->string);
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_number(Visitor *v, const char *name, double *obj,
|
2012-02-09 12:36:37 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
2016-01-29 16:48:38 +03:00
|
|
|
StringInputVisitor *siv = to_siv(v);
|
2012-02-09 12:36:37 +04:00
|
|
|
double val;
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm == LM_NONE);
|
2018-11-21 19:44:15 +03:00
|
|
|
if (qemu_strtod_finite(siv->string, NULL, &val)) {
|
qapi: Inline QERR_INVALID_PARAMETER_TYPE definition (constant value)
Address the comment added in commit 4629ed1e98
("qerror: Finally unused, clean up"), from 2015:
/*
* These macros will go away, please don't use
* in new code, and do not add new ones!
*/
Mechanical transformation using the following
coccinelle semantic patch:
@match@
expression errp;
expression param;
constant value;
@@
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, param, value);
@script:python strformat depends on match@
value << match.value;
fixedfmt; // new var
@@
fixedfmt = f'"Invalid parameter type for \'%s\', expected: {value[1:-1]}"'
coccinelle.fixedfmt = cocci.make_ident(fixedfmt)
@replace@
expression match.errp;
expression match.param;
constant match.value;
identifier strformat.fixedfmt;
@@
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, param, value);
+ error_setg(errp, fixedfmt, param);
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20240312141343.3168265-7-armbru@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
2024-03-12 17:13:39 +03:00
|
|
|
error_setg(errp, "Invalid parameter type for '%s', expected: number",
|
|
|
|
name ? name : "null");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
*obj = val;
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:45 +03:00
|
|
|
static bool parse_type_null(Visitor *v, const char *name, QNull **obj,
|
2017-06-26 19:22:59 +03:00
|
|
|
Error **errp)
|
2016-12-16 18:26:09 +03:00
|
|
|
{
|
|
|
|
StringInputVisitor *siv = to_siv(v);
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
assert(siv->lm == LM_NONE);
|
2017-06-26 19:22:59 +03:00
|
|
|
*obj = NULL;
|
|
|
|
|
2018-11-21 19:44:18 +03:00
|
|
|
if (siv->string[0]) {
|
qapi: Inline QERR_INVALID_PARAMETER_TYPE definition (constant value)
Address the comment added in commit 4629ed1e98
("qerror: Finally unused, clean up"), from 2015:
/*
* These macros will go away, please don't use
* in new code, and do not add new ones!
*/
Mechanical transformation using the following
coccinelle semantic patch:
@match@
expression errp;
expression param;
constant value;
@@
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, param, value);
@script:python strformat depends on match@
value << match.value;
fixedfmt; // new var
@@
fixedfmt = f'"Invalid parameter type for \'%s\', expected: {value[1:-1]}"'
coccinelle.fixedfmt = cocci.make_ident(fixedfmt)
@replace@
expression match.errp;
expression match.param;
constant match.value;
identifier strformat.fixedfmt;
@@
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, param, value);
+ error_setg(errp, fixedfmt, param);
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20240312141343.3168265-7-armbru@redhat.com>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
2024-03-12 17:13:39 +03:00
|
|
|
error_setg(errp, "Invalid parameter type for '%s', expected: null",
|
|
|
|
name ? name : "null");
|
2020-07-07 19:05:45 +03:00
|
|
|
return false;
|
2016-12-16 18:26:09 +03:00
|
|
|
}
|
2017-06-26 19:22:59 +03:00
|
|
|
|
|
|
|
*obj = qnull();
|
2020-07-07 19:05:45 +03:00
|
|
|
return true;
|
2016-12-16 18:26:09 +03:00
|
|
|
}
|
|
|
|
|
qapi: Add new visit_free() function
Making each visitor provide its own (awkwardly-named) FOO_cleanup()
is unusual, when we can instead have a polymorphic visit_free()
interface. Over the next few patches, we can use the polymorphic
functions to eliminate the need for a FOO_get_visitor() function
for accessing specific visitor functionality, once everything can
be accessed directly through the Visitor* interfaces.
The dealloc visitor is the first one converted to completely use
the new entry point, since qapi_dealloc_visitor_cleanup() was the
only reason that qapi_dealloc_get_visitor() existed, and only
generated and testsuite code was even using it. With the new
visit_free() entry point in place, we no longer need to expose
the QapiDeallocVisitor subtype through qapi_dealloc_visitor_new(),
and can get by with less generated code, with diffs that look like:
| void qapi_free_ACPIOSTInfo(ACPIOSTInfo *obj)
| {
|- QapiDeallocVisitor *qdv;
| Visitor *v;
|
| if (!obj) {
| return;
| }
|
|- qdv = qapi_dealloc_visitor_new();
|- v = qapi_dealloc_get_visitor(qdv);
|+ v = qapi_dealloc_visitor_new();
| visit_type_ACPIOSTInfo(v, NULL, &obj, NULL);
|- qapi_dealloc_visitor_cleanup(qdv);
|+ visit_free(v);
|}
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-5-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:35 +03:00
|
|
|
static void string_input_free(Visitor *v)
|
|
|
|
{
|
|
|
|
StringInputVisitor *siv = to_siv(v);
|
|
|
|
|
2016-06-09 19:48:37 +03:00
|
|
|
g_free(siv);
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|
|
|
|
|
2016-06-09 19:48:37 +03:00
|
|
|
Visitor *string_input_visitor_new(const char *str)
|
2012-02-09 12:36:37 +04:00
|
|
|
{
|
|
|
|
StringInputVisitor *v;
|
|
|
|
|
2017-03-03 15:32:36 +03:00
|
|
|
assert(str);
|
2012-02-09 12:36:37 +04:00
|
|
|
v = g_malloc0(sizeof(*v));
|
|
|
|
|
2016-04-29 00:45:09 +03:00
|
|
|
v->visitor.type = VISITOR_INPUT;
|
qapi: Prefer type_int64 over type_int in visitors
The qapi builtin type 'int' is basically shorthand for the type
'int64'. In fact, since no visitor was providing the optional
type_int64() callback, visit_type_int64() was just always falling
back to type_int(), cementing the equivalence between the types.
However, some visitors are providing a type_uint64() callback.
For purposes of code consistency, it is nicer if all visitors
use the paired type_int64/type_uint64 names rather than the
mismatched type_int/type_uint64. So this patch just renames
the signed int callbacks in place, dropping the type_int()
callback as redundant, and a later patch will focus on the
unsigned int callbacks.
Add some FIXMEs to questionable reuse of errp in code touched
by the rename, while at it (the reuse works as long as the
callbacks don't modify value when setting an error, but it's not
a good example to set) - a later patch will then fix those.
No change in functionality here, although further cleanups are
in the pipeline.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1454075341-13658-14-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:49 +03:00
|
|
|
v->visitor.type_int64 = parse_type_int64;
|
qapi: Make all visitors supply uint64 callbacks
Our qapi visitor contract supports multiple integer visitors,
but left the type_uint64 visitor as optional (falling back on
type_int64); which in turn can lead to awkward behavior with
numbers larger than INT64_MAX (the user has to be aware of
twos complement, and deal with negatives).
This patch does not address the disparity in handling large
values as negatives. It merely moves the fallback from uint64
to int64 from the visitor core to the visitors, where the issue
can actually be fixed, by implementing the missing type_uint64()
callbacks on top of the respective type_int64() callbacks, and
with a FIXME comment explaining why that's wrong.
With that done, we now have a type_uint64() callback in every
driver, so we can make it mandatory from the core. And although
the type_int64() callback can cover the entire valid range of
type_uint{8,16,32} on valid user input, using type_uint64() to
avoid mixed signedness makes more sense.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1454075341-13658-15-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:50 +03:00
|
|
|
v->visitor.type_uint64 = parse_type_uint64;
|
2014-02-08 14:01:44 +04:00
|
|
|
v->visitor.type_size = parse_type_size;
|
2012-02-09 12:36:37 +04:00
|
|
|
v->visitor.type_bool = parse_type_bool;
|
|
|
|
v->visitor.type_str = parse_type_str;
|
|
|
|
v->visitor.type_number = parse_type_number;
|
2016-12-16 18:26:09 +03:00
|
|
|
v->visitor.type_null = parse_type_null;
|
2014-06-10 15:15:27 +04:00
|
|
|
v->visitor.start_list = start_list;
|
|
|
|
v->visitor.next_list = next_list;
|
2017-03-03 15:32:45 +03:00
|
|
|
v->visitor.check_list = check_list;
|
2014-06-10 15:15:27 +04:00
|
|
|
v->visitor.end_list = end_list;
|
qapi: Add new visit_free() function
Making each visitor provide its own (awkwardly-named) FOO_cleanup()
is unusual, when we can instead have a polymorphic visit_free()
interface. Over the next few patches, we can use the polymorphic
functions to eliminate the need for a FOO_get_visitor() function
for accessing specific visitor functionality, once everything can
be accessed directly through the Visitor* interfaces.
The dealloc visitor is the first one converted to completely use
the new entry point, since qapi_dealloc_visitor_cleanup() was the
only reason that qapi_dealloc_get_visitor() existed, and only
generated and testsuite code was even using it. With the new
visit_free() entry point in place, we no longer need to expose
the QapiDeallocVisitor subtype through qapi_dealloc_visitor_new(),
and can get by with less generated code, with diffs that look like:
| void qapi_free_ACPIOSTInfo(ACPIOSTInfo *obj)
| {
|- QapiDeallocVisitor *qdv;
| Visitor *v;
|
| if (!obj) {
| return;
| }
|
|- qdv = qapi_dealloc_visitor_new();
|- v = qapi_dealloc_get_visitor(qdv);
|+ v = qapi_dealloc_visitor_new();
| visit_type_ACPIOSTInfo(v, NULL, &obj, NULL);
|- qapi_dealloc_visitor_cleanup(qdv);
|+ visit_free(v);
|}
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-5-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:35 +03:00
|
|
|
v->visitor.free = string_input_free;
|
2012-02-09 12:36:37 +04:00
|
|
|
|
|
|
|
v->string = str;
|
2018-11-21 19:44:18 +03:00
|
|
|
v->lm = LM_NONE;
|
2016-06-09 19:48:37 +03:00
|
|
|
return &v->visitor;
|
2012-02-09 12:36:37 +04:00
|
|
|
}
|