diff options
-rw-r--r-- | ChangeLog | 42 | ||||
-rw-r--r-- | doc/dbus-specification.xml | 41 | ||||
-rw-r--r-- | doc/introspect.dtd | 23 | ||||
-rw-r--r-- | glib/dbus-binding-tool-glib.c | 10 | ||||
-rw-r--r-- | glib/dbus-binding-tool-glib.h | 2 | ||||
-rw-r--r-- | glib/dbus-gidl.c | 60 | ||||
-rw-r--r-- | glib/dbus-gidl.h | 24 | ||||
-rw-r--r-- | glib/dbus-glib-tool.c | 30 | ||||
-rw-r--r-- | glib/dbus-gparser.c | 88 | ||||
-rw-r--r-- | test/glib/test-service-glib.xml | 18 |
10 files changed, 239 insertions, 99 deletions
@@ -1,5 +1,47 @@ 2005-02-17 Colin Walters <walters@verbum.org> + + * glib/dbus-gparser.c (struct Parser): Add in_annotation boolean. + (parse_node, parse_interface, parse_method, parse_signal) + (parse_property, parse_annotation): Lose if we're currently in an + annotation. + (parse_annotation): New function. + (parser_start_element, parser_end_element): Handle annotation. + (parse_method, parse_interface): Remove support for c_name attribute, + switch to annotations. + + * glib/dbus-gidl.h (interface_info_get_binding_names) + (method_info_get_binding_names) + (interface_info_get_binding_name, method_info_get_binding_name) + (interface_info_set_binding_name, method_info_set_binding_name): + Remove. + (interface_info_get_annotations, method_info_get_annotations) + (interface_info_get_annotation, method_info_get_annotation) + (interface_info_add_annotation, method_info_add_annotation): + Prototype. + + * glib/dbus-gidl.c (struct InterfaceInfo): Substitute "annotations" + for "bindings". + (struct MethodInfo): Ditto. + Straightfoward conversion of binding methods into annotation methods + as prototyped. + + * glib/dbus-glib-tool.c (pretty_print): Print annotations. + + * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_C_SYMBOL): Define. + + * glib/dbus-binding-tool-glib.c (gather_marshallers, generate_glue): + Use new annotation API. + + * doc/introspect.dtd: Fix a number of DTD syntax errors. Add + annotation element. + * doc/dbus-specification.xml: Discuss introspection annotations, + include list of well-known annotations. + + * test/glib/test-service-glib.xml: Make validate against new DTD. + +2005-02-17 Colin Walters <walters@verbum.org> + This patch is based on initial work from Paul Kuliniewicz <kuliniew@purdue.edu>. diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index 3d6a207f..ad21af62 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -2296,6 +2296,7 @@ <method name="Frobate"> <arg name="foo" type="int32" direction="in"/> <arg name="bar" type="string" direction="out"/> + <annotation name="org.freedesktop.DBus.Deprecated" value="true"/> </method> <signal name="Changed"> <arg name="new_value" type="boolean"/> @@ -2367,23 +2368,41 @@ </listitem> <listitem> <para> - The method, interface, property, and signal elements may have - an attribute deprecated="yes|no". If the attribute is not - present, the default value for an interface is "no", and - the default value for methods, properties, and signals is - the deprecation status of the interface. - </para> - </listitem> - <listitem> - <para> The "name" attribute on arguments is optional. </para> </listitem> </itemizedlist> </para> - + <para> + Method, interface, property, and signal elements may have + "annotations", which are generic key/value pairs of metadata. + They are similar conceptually to Java's annotations and C# attributes. + Well-known annotations: + </para> + <informaltable> + <tgroup cols="3"> + <thead> + <row> + <entry>Name</entry> + <entry>Values (separated by ,)</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>org.freedesktop.DBus.Deprecated</entry> + <entry>true,false</entry> + <entry>Whether or not the entity is deprecated; defaults to false</entry> + </row> + <row> + <entry>org.freedesktop.DBus.GLib.CSymbol</entry> + <entry>(string)</entry> + <entry>The C symbol; may be used for methods and interfaces</entry> + </row> + </tbody> + </tgroup> + </informaltable> </sect1> - <sect1 id="message-bus"> <title>Message Bus Specification</title> <sect2 id="message-bus-overview"> diff --git a/doc/introspect.dtd b/doc/introspect.dtd index 5e1c96df..fd6aa472 100644 --- a/doc/introspect.dtd +++ b/doc/introspect.dtd @@ -4,32 +4,33 @@ <!-- see D-BUS specification for documentation --> -<!ELEMENT node (interface,node)> +<!ELEMENT node (interface*,node*)> <!ATTLIST node name CDATA #REQUIRED> -<!ELEMENT interface (method,signal,property)> +<!ELEMENT interface (annotation*,method*,signal*,property*)> <!ATTLIST interface name CDATA #REQUIRED> -<!ATTLIST interface deprecated CDATA "no"> +<!ELEMENT method (annotation*,arg*)> <!ATTLIST method name CDATA #REQUIRED> -<!ATTLIST method deprecated #IMPLIED> <!ELEMENT arg EMPTY> -<!ATTLIST arg name CDATA #REQUIRED> +<!ATTLIST arg name CDATA #IMPLIED> <!ATTLIST arg type CDATA #REQUIRED> <!-- Method arguments SHOULD include "direction", while signal and error arguments SHOULD not (since there's no point). The DTD format can't express that subtlety. --> -<!ATTLIST arg direction "in|out" #IMPLIED> +<!ATTLIST arg direction (in|out) "in"> -<!ELEMENT signal (arg)> +<!ELEMENT signal (arg,annotation)> <!ATTLIST signal name CDATA #REQUIRED> -<!ATTLIST signal deprecated #IMPLIED> -<!ELEMENT property> <!-- AKA "attribute" --> +<!ELEMENT property (annotation)> <!-- AKA "attribute" --> <!ATTLIST property name CDATA #REQUIRED> <!ATTLIST property type CDATA #REQUIRED> -<!ATTLIST property access "read|write|readwrite" #REQUIRED> -<!ATTLIST property deprecated #IMPLIED> +<!ATTLIST property access (read|write|readwrite) #REQUIRED> + +<!ELEMENT annotation EMPTY> <!-- Generic metadata --> +<!ATTLIST annotation name CDATA #REQUIRED> +<!ATTLIST annotation value CDATA #REQUIRED> diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c index 98c13341..4ead51a3 100644 --- a/glib/dbus-binding-tool-glib.c +++ b/glib/dbus-binding-tool-glib.c @@ -201,7 +201,7 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error) const char *interface_c_name; interface = (InterfaceInfo *) base; - interface_c_name = interface_info_get_binding_name (interface, "C"); + interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL); if (interface_c_name == NULL) { return TRUE; @@ -217,7 +217,7 @@ gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error) char *marshaller_name; method = (MethodInfo *) tmp->data; - if (method_info_get_binding_name (method, "C") == NULL) + if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL) == NULL) { continue; } @@ -306,7 +306,7 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) channel = data->channel; interface = (InterfaceInfo *) base; - interface_c_name = interface_info_get_binding_name (interface, "C"); + interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL); if (interface_c_name == NULL) { return TRUE; @@ -319,7 +319,7 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) /* Table of marshalled methods. */ - if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_binding_name (interface, "C"))) + if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL))) goto io_lose; for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) { @@ -329,7 +329,7 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) GSList *args; method = (MethodInfo *) tmp->data; - method_c_name = method_info_get_binding_name (method, "C"); + method_c_name = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL); if (method_c_name == NULL) { continue; diff --git a/glib/dbus-binding-tool-glib.h b/glib/dbus-binding-tool-glib.h index d4589bc9..6667438a 100644 --- a/glib/dbus-binding-tool-glib.h +++ b/glib/dbus-binding-tool-glib.h @@ -25,6 +25,8 @@ G_BEGIN_DECLS +#define DBUS_GLIB_ANNOTATION_C_SYMBOL "org.freedesktop.DBus.GLib.CSymbol" + gboolean dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error); gboolean dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error); diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index 554e18c3..fb9573e5 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -43,7 +43,7 @@ struct NodeInfo struct InterfaceInfo { BaseInfo base; - GHashTable *bindings; + GHashTable *annotations; /* Since we have BaseInfo now these could be one list */ GSList *methods; GSList *signals; @@ -53,7 +53,7 @@ struct InterfaceInfo struct MethodInfo { BaseInfo base; - GHashTable *bindings; + GHashTable *annotations; GSList *args; }; @@ -345,9 +345,9 @@ interface_info_new (const char *name) info->base.refcount = 1; info->base.name = g_strdup (name); info->base.type = INFO_TYPE_INTERFACE; - info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_free); + info->annotations = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_free); return info; } @@ -366,7 +366,7 @@ interface_info_unref (InterfaceInfo *info) info->base.refcount -= 1; if (info->base.refcount == 0) { - g_hash_table_destroy (info->bindings); + g_hash_table_destroy (info->annotations); free_method_list (&info->methods); free_signal_list (&info->signals); free_property_list (&info->properties); @@ -381,16 +381,16 @@ interface_info_get_name (InterfaceInfo *info) } GSList * -interface_info_get_binding_names (InterfaceInfo *info) +interface_info_get_annotations (InterfaceInfo *info) { - return get_hash_keys (info->bindings); + return get_hash_keys (info->annotations); } const char* -interface_info_get_binding_name (InterfaceInfo *info, - const char *binding_type) +interface_info_get_annotation (InterfaceInfo *info, + const char *name) { - return g_hash_table_lookup (info->bindings, binding_type); + return g_hash_table_lookup (info->annotations, name); } GSList* @@ -412,13 +412,13 @@ interface_info_get_properties (InterfaceInfo *info) } void -interface_info_set_binding_name (InterfaceInfo *info, - const char *binding_type, - const char *bound_name) +interface_info_add_annotation (InterfaceInfo *info, + const char *name, + const char *value) { - g_hash_table_insert (info->bindings, - g_strdup (binding_type), - g_strdup (bound_name)); + g_hash_table_insert (info->annotations, + g_strdup (name), + g_strdup (value)); } void @@ -470,7 +470,7 @@ method_info_new (const char *name) info->base.refcount = 1; info->base.name = g_strdup (name); info->base.type = INFO_TYPE_METHOD; - info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal, + info->annotations = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); @@ -491,7 +491,7 @@ method_info_unref (MethodInfo *info) info->base.refcount -= 1; if (info->base.refcount == 0) { - g_hash_table_destroy (info->bindings); + g_hash_table_destroy (info->annotations); free_arg_list (&info->args); base_info_free (info); } @@ -504,16 +504,16 @@ method_info_get_name (MethodInfo *info) } GSList * -method_info_get_binding_names (MethodInfo *info) +method_info_get_annotations (MethodInfo *info) { - return get_hash_keys (info->bindings); + return get_hash_keys (info->annotations); } const char* -method_info_get_binding_name (MethodInfo *info, - const char *binding_type) +method_info_get_annotation (MethodInfo *info, + const char *name) { - return g_hash_table_lookup (info->bindings, binding_type); + return g_hash_table_lookup (info->annotations, name); } GSList* @@ -544,13 +544,13 @@ args_sort_by_direction (const void *a, } void -method_info_set_binding_name (MethodInfo *info, - const char *binding_type, - const char *bound_name) +method_info_add_annotation (MethodInfo *info, + const char *name, + const char *value) { - g_hash_table_insert (info->bindings, - g_strdup (binding_type), - g_strdup (bound_name)); + g_hash_table_insert (info->annotations, + g_strdup (name), + g_strdup (value)); } void diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 917432ee..539c731f 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -90,15 +90,15 @@ InterfaceInfo* interface_info_new (const char *name); InterfaceInfo* interface_info_ref (InterfaceInfo *info); void interface_info_unref (InterfaceInfo *info); const char* interface_info_get_name (InterfaceInfo *info); -GSList* interface_info_get_binding_names(InterfaceInfo *info); -const char* interface_info_get_binding_name(InterfaceInfo*info, - const char *binding_type); +GSList* interface_info_get_annotations(InterfaceInfo *info); +const char* interface_info_get_annotation (InterfaceInfo*info, + const char *annotation); GSList* interface_info_get_methods (InterfaceInfo *info); GSList* interface_info_get_signals (InterfaceInfo *info); GSList* interface_info_get_properties (InterfaceInfo *info); -void interface_info_set_binding_name(InterfaceInfo *info, - const char *name, - const char *value); +void interface_info_add_annotation (InterfaceInfo *info, + const char *name, + const char *value); void interface_info_add_method (InterfaceInfo *info, MethodInfo *method); void interface_info_add_signal (InterfaceInfo *info, @@ -109,12 +109,12 @@ MethodInfo* method_info_new (const char *name); MethodInfo* method_info_ref (MethodInfo *info); void method_info_unref (MethodInfo *info); const char* method_info_get_name (MethodInfo *info); -GSList* method_info_get_binding_names (MethodInfo *info); -const char* method_info_get_binding_name (MethodInfo *info, - const char *binding_type); -void method_info_set_binding_name (MethodInfo *info, - const char *binding_type, - const char *bound_name); +GSList* method_info_get_annotations (MethodInfo *info); +const char* method_info_get_annotation (MethodInfo *info, + const char *annotation); +void method_info_add_annotation (MethodInfo *info, + const char *name, + const char *value); GSList* method_info_get_args (MethodInfo *info); void method_info_add_arg (MethodInfo *info, ArgInfo *arg); diff --git a/glib/dbus-glib-tool.c b/glib/dbus-glib-tool.c index 022055e6..1359ba53 100644 --- a/glib/dbus-glib-tool.c +++ b/glib/dbus-glib-tool.c @@ -107,22 +107,22 @@ pretty_print (BaseInfo *base, case INFO_TYPE_INTERFACE: { InterfaceInfo *i = (InterfaceInfo*) base; - GSList *binding_types, *elt; + GSList *annotations, *elt; g_assert (name != NULL); printf (_("interface \"%s\" {\n"), name); - binding_types = interface_info_get_binding_names (i); - for (elt = binding_types; elt; elt = elt->next) + annotations = interface_info_get_annotations (i); + for (elt = annotations; elt; elt = elt->next) { - const char *binding_type = elt->data; - const char *binding_name = interface_info_get_binding_name (i, binding_type); + const char *name = elt->data; + const char *value = interface_info_get_annotation (i, name); printf (_(" (binding \"%s\": \"%s\") "), - binding_type, binding_name); + name, value); } - g_slist_free (binding_types); + g_slist_free (annotations); pretty_print_list (interface_info_get_methods (i), depth + 1); pretty_print_list (interface_info_get_signals (i), depth + 1); @@ -135,21 +135,21 @@ pretty_print (BaseInfo *base, case INFO_TYPE_METHOD: { MethodInfo *m = (MethodInfo*) base; - GSList *binding_types, *elt; + GSList *annotations, *elt; g_assert (name != NULL); - binding_types = method_info_get_binding_names (m); + annotations = method_info_get_annotations (m); printf (_("method \"%s\""), name); - for (elt = binding_types; elt; elt = elt->next) + for (elt = annotations; elt; elt = elt->next) { - const char *binding_type = elt->data; - const char *binding_name = method_info_get_binding_name (m, binding_type); + const char *name = elt->data; + const char *value = method_info_get_annotation (m, name); - printf (_(" (binding \"%s\": \"%s\") "), - binding_type, binding_name); + printf (_(" (annotation \"%s\": \"%s\") "), + name, value); } - g_slist_free (binding_types); + g_slist_free (annotations); pretty_print_list (method_info_get_args (m), depth + 1); diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c index 05136aa8..3adfe32e 100644 --- a/glib/dbus-gparser.c +++ b/glib/dbus-gparser.c @@ -171,6 +171,7 @@ struct Parser SignalInfo *signal; PropertyInfo *property; ArgInfo *arg; + gboolean in_annotation; }; Parser* @@ -240,7 +241,8 @@ parse_node (Parser *parser, parser->method || parser->signal || parser->property || - parser->arg) + parser->arg || + parser->in_annotation) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, @@ -308,7 +310,6 @@ parse_interface (Parser *parser, GError **error) { const char *name; - const char *c_name; InterfaceInfo *iface; NodeInfo *top; @@ -317,6 +318,7 @@ parse_interface (Parser *parser, parser->signal || parser->property || parser->arg || + parser->in_annotation || (parser->node_stack == NULL)) { g_set_error (error, G_MARKUP_ERROR, @@ -330,7 +332,6 @@ parse_interface (Parser *parser, if (!locate_attributes (element_name, attribute_names, attribute_values, error, "name", &name, - "c_name", &c_name, NULL)) return FALSE; @@ -346,8 +347,6 @@ parse_interface (Parser *parser, top = parser->node_stack->data; iface = interface_info_new (name); - if (c_name) - interface_info_set_binding_name (iface, "C", c_name); node_info_add_interface (top, iface); interface_info_unref (iface); @@ -364,7 +363,6 @@ parse_method (Parser *parser, GError **error) { const char *name; - const char *c_name; MethodInfo *method; NodeInfo *top; @@ -373,6 +371,7 @@ parse_method (Parser *parser, parser->method || parser->signal || parser->property || + parser->in_annotation || parser->arg) { g_set_error (error, G_MARKUP_ERROR, @@ -386,7 +385,6 @@ parse_method (Parser *parser, if (!locate_attributes (element_name, attribute_names, attribute_values, error, "name", &name, - "c_name", &c_name, NULL)) return FALSE; @@ -402,8 +400,6 @@ parse_method (Parser *parser, top = parser->node_stack->data; method = method_info_new (name); - if (c_name) - method_info_set_binding_name (method, "C", c_name); interface_info_add_method (parser->interface, method); method_info_unref (method); @@ -428,6 +424,7 @@ parse_signal (Parser *parser, parser->signal || parser->method || parser->property || + parser->in_annotation || parser->arg) { g_set_error (error, G_MARKUP_ERROR, @@ -539,6 +536,7 @@ parse_property (Parser *parser, parser->signal || parser->method || parser->property || + parser->in_annotation || parser->arg) { g_set_error (error, G_MARKUP_ERROR, @@ -633,6 +631,7 @@ parse_arg (Parser *parser, if (!(parser->method || parser->signal) || parser->node_stack == NULL || parser->property || + parser->in_annotation || parser->arg) { g_set_error (error, G_MARKUP_ERROR, @@ -724,6 +723,67 @@ parse_arg (Parser *parser, return TRUE; } +static gboolean +parse_annotation (Parser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + GError **error) +{ + const char *name; + const char *value; + + if (!(parser->method || parser->interface || parser->arg) || + parser->node_stack == NULL || + parser->signal || + parser->in_annotation) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("Can't put <%s> element here"), + element_name); + return FALSE; + } + + name = NULL; + if (!locate_attributes (element_name, attribute_names, + attribute_values, error, + "name", &name, + "value", &value, + NULL)) + return FALSE; + + /* name can be null for args */ + + if (name == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "name", element_name); + return FALSE; + } + if (value == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_PARSE, + _("\"%s\" attribute required on <%s> element "), + "value", element_name); + return FALSE; + } + + if (parser->method) + method_info_add_annotation (parser->method, name, value); + else if (parser->interface) + interface_info_add_annotation (parser->interface, name, value); + else + g_assert_not_reached (); + + parser->in_annotation = TRUE; + + return TRUE; +} + gboolean parser_start_element (Parser *parser, const char *element_name, @@ -769,6 +829,12 @@ parser_start_element (Parser *parser, attribute_values, error)) return FALSE; } + else if (ELEMENT_IS ("annotation")) + { + if (!parse_annotation (parser, element_name, attribute_names, + attribute_values, error)) + return FALSE; + } else { g_set_error (error, G_MARKUP_ERROR, @@ -807,6 +873,10 @@ parser_end_element (Parser *parser, { parser->arg = NULL; } + else if (ELEMENT_IS ("annotation")) + { + parser->in_annotation = FALSE; + } else if (ELEMENT_IS ("node")) { NodeInfo *top; diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml index 223bf67f..298e2ddb 100644 --- a/test/glib/test-service-glib.xml +++ b/test/glib/test-service-glib.xml @@ -2,25 +2,31 @@ <node name="/org/freedesktop/DBus/Tests/MyTestObject"> - <interface name="org.freedesktop.DBus.Tests.MyObject" c_name="my_object"> + <interface name="org.freedesktop.DBus.Tests.MyObject"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/> - <method name="DoNothing" c_name="my_object_do_nothing"> + <method name="DoNothing"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_do_nothing"/> </method> - <method name="Increment" c_name="my_object_increment"> + <method name="Increment"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_increment"/> <arg type="uint32" name="x" /> <arg type="uint32" direction="out" /> </method> - <method name="ThrowError" c_name="my_object_throw_error"> + <method name="ThrowError"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_throw_error"/> </method> - <method name="Uppercase" c_name="my_object_uppercase"> + <method name="Uppercase"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_uppercase"/> <arg type="string" direction="in" /> <arg type="string" direction="out" /> </method> - <method name="ManyArgs" c_name="my_object_many_args"> + <method name="ManyArgs"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/> <arg type="uint32" name="x" direction="in" /> <arg type="string" name="str" direction="in" /> <arg type="double" name="trouble" direction="in" /> |