blob: 1edd0cac57feba50edb8ec5e042d8a7ab751f982 [file] [log] [blame]
/* nih-dbus-tool
*
* annotation.c - annotation parsing and handling
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <nih/macros.h>
#include <nih/alloc.h>
#include <nih/list.h>
#include <nih/string.h>
#include <nih/logging.h>
#include "annotation.h"
#include "parse.h"
#include "errors.h"
/**
* annotation_start_tag:
* @xmlp: XML parser,
* @tag: name of XML tag being parsed,
* @attr: NULL-terminated array of attribute name and value pairs.
*
* This function is called by parse_start_tag() for an "annotation"
* start tag, this may be a child of the "interface", "method", "signal",
* "property" or (nih extension) "argument" tags and specifies a further
* property not defined by the Introspection specification.
*
* If the annotation does not appear within one of the permitted tags a
* warning is emitted and the tag will be ignored.
*
* Annotations must have a "name" attribute containing the well-known
* annotation name and a "value" attribute contianing the value.
*
* Any unknown attributes result in a warning and will be ignored.
*
* The appropriate *_annotation() function is called to handle
* identifying the annotation and applying it to the parent object. This
* may result in a warning being emitted if the annotation is unknown or
* an error if the value is not permitted.
*
* Returns: zero on success, negative value on raised error.
**/
int
annotation_start_tag (XML_Parser xmlp,
const char * tag,
char * const *attr)
{
ParseContext *context;
ParseStack * parent;
char * const *key;
char * const *value;
const char * name = NULL;
const char * val = NULL;
int ret;
nih_assert (xmlp != NULL);
nih_assert (tag != NULL);
nih_assert (attr != NULL);
context = XML_GetUserData (xmlp);
nih_assert (context != NULL);
/* Annotations apply to their parent tag */
parent = parse_stack_top (&context->stack);
if ((! parent) || ( (parent->type != PARSE_INTERFACE)
&& (parent->type != PARSE_METHOD)
&& (parent->type != PARSE_SIGNAL)
&& (parent->type != PARSE_PROPERTY)
&& (parent->type != PARSE_ARGUMENT)))
{
nih_warn ("%s:%zu:%zu: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unexpected <annotation> tag"));
if (! parse_stack_push (NULL, &context->stack,
PARSE_IGNORED, NULL))
nih_return_system_error (-1);
return 0;
}
/* Retrieve the name and value from the attributes */
for (key = attr; key && *key; key += 2) {
value = key + 1;
nih_assert (value && *value);
if (! strcmp (*key, "name")) {
name = *value;
} else if (! strcmp (*key, "value")) {
val = *value;
} else {
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown <annotation> attribute"),
*key);
}
}
/* Check we have a name and value */
if (! name)
nih_return_error (-1, ANNOTATION_MISSING_NAME,
_(ANNOTATION_MISSING_NAME_STR));
if (! val)
nih_return_error (-1, ANNOTATION_MISSING_VALUE,
_(ANNOTATION_MISSING_VALUE_STR));
/* Meaning of the annotation depends on the parent */
switch (parent->type) {
case PARSE_INTERFACE:
ret = interface_annotation (parent->interface, name, val);
break;
case PARSE_METHOD:
ret = method_annotation (parent->method, name, val);
break;
case PARSE_SIGNAL:
ret = signal_annotation (parent->signal, name, val);
break;
case PARSE_PROPERTY:
ret = property_annotation (parent->property, name, val);
break;
case PARSE_ARGUMENT:
ret = argument_annotation (parent->argument, name, val);
break;
default:
nih_assert_not_reached ();
}
if (ret < 0) {
NihError *err;
err = nih_error_get ();
switch (err->number) {
case INTERFACE_UNKNOWN_ANNOTATION:
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown interface annotation"),
name);
break;
case METHOD_UNKNOWN_ANNOTATION:
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown method annotation"),
name);
break;
case SIGNAL_UNKNOWN_ANNOTATION:
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown signal annotation"),
name);
break;
case PROPERTY_UNKNOWN_ANNOTATION:
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown property annotation"),
name);
break;
case ARGUMENT_UNKNOWN_ANNOTATION:
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown argument annotation"),
name);
break;
default:
return -1;
}
nih_free (err);
if (! parse_stack_push (NULL, &context->stack,
PARSE_IGNORED, NULL)) {
nih_error_raise_system ();
return -1;
}
} else {
if (! parse_stack_push (NULL, &context->stack,
PARSE_ANNOTATION, NULL)) {
nih_error_raise_system ();
return -1;
}
}
return 0;
}
/**
* annotation_end_tag:
* @xmlp: XML parser,
* @tag: name of XML tag being parsed.
*
* This function is called by parse_end_tag() for an "annotation" end
* tag, and matches a call to annotation_start_tag() made at the same
* parsing level.
*
* The object on the stack is always discarded.
*
* Returns: zero on success, negative value on raised error.
**/
int
annotation_end_tag (XML_Parser xmlp,
const char *tag)
{
ParseContext *context;
ParseStack * entry;
nih_assert (xmlp != NULL);
nih_assert (tag != NULL);
context = XML_GetUserData (xmlp);
nih_assert (context != NULL);
entry = parse_stack_top (&context->stack);
nih_assert (entry != NULL);
nih_assert (entry->type == PARSE_ANNOTATION);
nih_free (entry);
return 0;
}