Patchwork [08/14] qerror: add build_error_dict() and error_object_table[]

login
register
mail settings
Submitter Luiz Capitulino
Date July 25, 2012, 8:50 p.m.
Message ID <1343249431-9245-9-git-send-email-lcapitulino@redhat.com>
Download mbox | patch
Permalink /patch/173286/
State New
Headers show

Comments

Luiz Capitulino - July 25, 2012, 8:50 p.m.
In the near future, the QERR_ macros (which are json strings today) will
be turned into an enumeration. When we get there, build_error_dict()
will be used to (guess what) build an error dict by:

 1. Using the error class as an index to error_object_table[], which
    contains all QMP errors as json strings (with default values)

 2. Use the human error string to construct the error object data member.
    For example, an error message like:

     "Parameter name=brain has not been found"

     Will construct the following data member:

     'data': { 'name': 'brain' } }

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qerror.c               | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++
 qerror.h               |  1 +
 scripts/qapi-errors.py | 39 +++++++++++++++++++++++
 3 files changed, 126 insertions(+)
Markus Armbruster - July 26, 2012, 12:52 p.m.
Luiz Capitulino <lcapitulino@redhat.com> writes:

> In the near future, the QERR_ macros (which are json strings today) will
> be turned into an enumeration. When we get there, build_error_dict()
> will be used to (guess what) build an error dict by:
>
>  1. Using the error class as an index to error_object_table[], which
>     contains all QMP errors as json strings (with default values)
>
>  2. Use the human error string to construct the error object data member.
>     For example, an error message like:
>
>      "Parameter name=brain has not been found"
>
>      Will construct the following data member:
>
>      'data': { 'name': 'brain' } }
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
>  qerror.c               | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  qerror.h               |  1 +
>  scripts/qapi-errors.py | 39 +++++++++++++++++++++++
>  3 files changed, 126 insertions(+)
>
> diff --git a/qerror.c b/qerror.c
> index 42e8687..267545e 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -38,6 +38,92 @@ static QError *qerror_new(void)
>      return qerr;
>  }
>  
> +static bool iscchar(int c)
> +{
> +    return (isalpha(c) || isdigit(c) || c == '_');
> +}

Depends on locale, which may not be what you want.

Beware of passing negative arguments to ctype.h functions.

> +
> +static char *get_key(const char *str)
> +{
> +    char *p, *ret;
> +
> +    ret = p = g_strdup(str);
> +
> +    while (!iscchar(*p)) {
> +        p++;
> +    }
> +    memmove(ret, p, strlen(ret));
> +
> +    p = ret;
> +    while (iscchar(*p)) {
> +        p++;
> +    }
> +    *p = '\0';
> +
> +    return ret;
> +}

Suggest something like

static char *get_key(const char *str)
{
    char *beg, *end;

    for (beg = str; !iscchar(*beg); beg++) ;
    for (end = beg; iscchar(*end); end++) ;
    return g_strndup(beg, end - beg);
}

> +
> +static char *get_value(const char *str)
> +{
> +    char *p, *ret;
> +
> +    p = strchr(str, '=');
> +    while (!iscchar(*p)) {
> +        p++;
> +    }
> +    p = ret = g_strdup(p);
> +    while (iscchar(*p)) {
> +        p++;
> +    }
> +    *p = '\0';
> +
> +    return ret;
> +}

Likewise.

> +
> +static void set_dict_data(const char *msg, QDict *data_dict)
> +{
> +    char *str, *msg2, *saveptr = NULL;
> +
> +    msg2 = g_strdup(msg);
> +    str = strtok_r(msg2, " ", &saveptr);
> +    while (str) {
> +        if (strchr(str, '=')) {
> +            char *key = get_key(str);
> +            char *value = get_value(str);
> +
> +            /* FIXME: handle ints */
> +            if (qdict_haskey(data_dict, key)) {
> +                qdict_put(data_dict, key, qstring_from_str(value));
> +            }
> +
> +            g_free(key);
> +            g_free(value);
> +        }
> +        str = strtok_r(NULL, " ", &saveptr);
> +    }
> +
> +    g_free(msg2);
> +}
> +
> +QDict *build_error_dict(int err_class, const char *msg)
> +{
> +    QDict *err_dict;
> +    QObject *obj;
> +
> +    assert(msg[0] != '\0');
> +
> +    obj = qobject_from_json(error_object_table[err_class]);
> +    assert(obj);
> +    assert(qobject_type(obj) == QTYPE_QDICT);
> +
> +    err_dict = qobject_to_qdict(obj);
> +    assert(qdict_haskey(err_dict, "data"));
> +
> +    set_dict_data(msg, qdict_get_qdict(err_dict, "data"));
> +
> +    return err_dict;
> +}
> +
>  static QDict *error_object_from_fmt(const char *fmt, va_list *va)
>  {
>      QObject *obj;
> diff --git a/qerror.h b/qerror.h
> index 16401ff..c4f6053 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -36,5 +36,6 @@ void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
>  void qerror_report_err(Error *err);
>  void assert_no_error(Error *err);
>  char *qerror_format(const char *fmt, QDict *error);
> +QDict *build_error_dict(int err_class, const char *msg);
>  
>  #endif /* QERROR_H */
> diff --git a/scripts/qapi-errors.py b/scripts/qapi-errors.py
> index 59cf426..5f8723e 100644
> --- a/scripts/qapi-errors.py
> +++ b/scripts/qapi-errors.py
> @@ -85,6 +85,42 @@ static const QErrorStringTable qerror_table[] = {
>  
>      return ret
>  
> +def gen_error_data_obj(data):
> +    colon = ''
> +    data_str = ''
> +    for k, v in data.items():
> +        data_str += colon + "'%s': " % k
> +        if v == 'str':
> +            data_str += "'unknown'"
> +        elif v == 'int':
> +            data_str += '0'
> +        else:
> +            sys.exit("unknown data type '%s' for error '%s'" % (v, name))
> +        colon = ', '
> +    return data_str

colon is either empty or ', ', but never a colon.  What about calling it
sep, for separator?

> +
> +def gen_error_obj_table(exprs):
> +    ret = mcgen('''
> +static const char *error_object_table[] = {
> +''')
> +
> +    for err in exprs:
> +        data = gen_error_data_obj({})
> +        if err.has_key('data'):
> +            data = gen_error_data_obj(err['data'])
> +        ret += mcgen('''
> +    "{ 'class': '%(error_class)s', 'data': { %(error_data)s } }",
> +''',
> +                error_class=err['error'], error_data=data)
> +
> +    ret += mcgen('''
> +    NULL,
> +};
> +
> +''')
> +
> +    return ret;
> +
>  def gen_error_macro_data_str(data):
>      colon = ''
>      data_str = ''
> @@ -173,5 +209,8 @@ if __name__ == '__main__':
>      ret = gen_error_def_table(exprs)
>      fdef.write(ret)
>  
> +    ret = gen_error_obj_table(exprs)
> +    fdef.write(ret)
> +
>      fdef.flush()
>      fdef.close()

Patch

diff --git a/qerror.c b/qerror.c
index 42e8687..267545e 100644
--- a/qerror.c
+++ b/qerror.c
@@ -38,6 +38,92 @@  static QError *qerror_new(void)
     return qerr;
 }
 
+static bool iscchar(int c)
+{
+    return (isalpha(c) || isdigit(c) || c == '_');
+}
+
+static char *get_key(const char *str)
+{
+    char *p, *ret;
+
+    ret = p = g_strdup(str);
+
+    while (!iscchar(*p)) {
+        p++;
+    }
+    memmove(ret, p, strlen(ret));
+
+    p = ret;
+    while (iscchar(*p)) {
+        p++;
+    }
+    *p = '\0';
+
+    return ret;
+}
+
+static char *get_value(const char *str)
+{
+    char *p, *ret;
+
+    p = strchr(str, '=');
+    while (!iscchar(*p)) {
+        p++;
+    }
+    p = ret = g_strdup(p);
+    while (iscchar(*p)) {
+        p++;
+    }
+    *p = '\0';
+
+    return ret;
+}
+
+static void set_dict_data(const char *msg, QDict *data_dict)
+{
+    char *str, *msg2, *saveptr = NULL;
+
+    msg2 = g_strdup(msg);
+    str = strtok_r(msg2, " ", &saveptr);
+    while (str) {
+        if (strchr(str, '=')) {
+            char *key = get_key(str);
+            char *value = get_value(str);
+
+            /* FIXME: handle ints */
+            if (qdict_haskey(data_dict, key)) {
+                qdict_put(data_dict, key, qstring_from_str(value));
+            }
+
+            g_free(key);
+            g_free(value);
+        }
+        str = strtok_r(NULL, " ", &saveptr);
+    }
+
+    g_free(msg2);
+}
+
+QDict *build_error_dict(int err_class, const char *msg)
+{
+    QDict *err_dict;
+    QObject *obj;
+
+    assert(msg[0] != '\0');
+
+    obj = qobject_from_json(error_object_table[err_class]);
+    assert(obj);
+    assert(qobject_type(obj) == QTYPE_QDICT);
+
+    err_dict = qobject_to_qdict(obj);
+    assert(qdict_haskey(err_dict, "data"));
+
+    set_dict_data(msg, qdict_get_qdict(err_dict, "data"));
+
+    return err_dict;
+}
+
 static QDict *error_object_from_fmt(const char *fmt, va_list *va)
 {
     QObject *obj;
diff --git a/qerror.h b/qerror.h
index 16401ff..c4f6053 100644
--- a/qerror.h
+++ b/qerror.h
@@ -36,5 +36,6 @@  void qerror_report(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
 void qerror_report_err(Error *err);
 void assert_no_error(Error *err);
 char *qerror_format(const char *fmt, QDict *error);
+QDict *build_error_dict(int err_class, const char *msg);
 
 #endif /* QERROR_H */
diff --git a/scripts/qapi-errors.py b/scripts/qapi-errors.py
index 59cf426..5f8723e 100644
--- a/scripts/qapi-errors.py
+++ b/scripts/qapi-errors.py
@@ -85,6 +85,42 @@  static const QErrorStringTable qerror_table[] = {
 
     return ret
 
+def gen_error_data_obj(data):
+    colon = ''
+    data_str = ''
+    for k, v in data.items():
+        data_str += colon + "'%s': " % k
+        if v == 'str':
+            data_str += "'unknown'"
+        elif v == 'int':
+            data_str += '0'
+        else:
+            sys.exit("unknown data type '%s' for error '%s'" % (v, name))
+        colon = ', '
+    return data_str
+
+def gen_error_obj_table(exprs):
+    ret = mcgen('''
+static const char *error_object_table[] = {
+''')
+
+    for err in exprs:
+        data = gen_error_data_obj({})
+        if err.has_key('data'):
+            data = gen_error_data_obj(err['data'])
+        ret += mcgen('''
+    "{ 'class': '%(error_class)s', 'data': { %(error_data)s } }",
+''',
+                error_class=err['error'], error_data=data)
+
+    ret += mcgen('''
+    NULL,
+};
+
+''')
+
+    return ret;
+
 def gen_error_macro_data_str(data):
     colon = ''
     data_str = ''
@@ -173,5 +209,8 @@  if __name__ == '__main__':
     ret = gen_error_def_table(exprs)
     fdef.write(ret)
 
+    ret = gen_error_obj_table(exprs)
+    fdef.write(ret)
+
     fdef.flush()
     fdef.close()