mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-14 21:36:13 +01:00
159a9c215a
This introduces no functional changes. Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
1173 lines
40 KiB
XML
1173 lines
40 KiB
XML
<?xml version='1.0' encoding='utf-8'?>
|
|
|
|
<refentry id='gvariant-format-strings'>
|
|
<refmeta>
|
|
<refentrytitle>GVariant Format Strings</refentrytitle>
|
|
</refmeta>
|
|
<refnamediv>
|
|
<refname>GVariant Format Strings</refname>
|
|
<refpurpose>varargs conversion of GVariants</refpurpose>
|
|
</refnamediv>
|
|
|
|
<refsect1>
|
|
<title>Variable Argument Conversions</title>
|
|
|
|
<para>
|
|
This page attempts to document how to perform variable argument
|
|
conversions with GVariant.
|
|
</para>
|
|
<para>
|
|
Conversions occur according to format strings. A format string is a two-way mapping between a single
|
|
<link linkend='GVariant'>GVariant</link> value and one or more C values.
|
|
</para>
|
|
<para>
|
|
A conversion from C values into a <link linkend='GVariant'>GVariant</link> value is made using the
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> function. A conversion from a
|
|
<link linkend='GVariant'>GVariant</link> into C values is made using the
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link> function.
|
|
</para>
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>Syntax</title>
|
|
|
|
<para>
|
|
This section exhaustively describes all possibilities for GVariant format strings. There are no valid forms of
|
|
format strings other than those described here. Please note that the format string syntax is likely to expand in the
|
|
future.
|
|
</para>
|
|
<para>
|
|
Valid format strings have one of the following forms:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>any type string</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
a type string prefixed with a '<literal>@</literal>'
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
'<literal>&s</literal>' '<literal>&o</literal>', '<literal>&g</literal>', '<literal>^as</literal>',
|
|
'<literal>^a&s</literal>', '<literal>^ao</literal>', '<literal>^a&o</literal>','<literal>^ay</literal>',
|
|
'<literal>^&ay</literal>', '<literal>^aay</literal>' or '<literal>^a&ay</literal>'.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
any format string, prefixed with an '<literal>m</literal>'
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
a sequence of zero or more format strings, concatenated and enclosed in parentheses
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
an opening brace, followed by two format strings, followed by a closing brace (subject to the constraint that the
|
|
first format string correspond to a type valid for use as the key type of a dictionary)
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</refsect1>
|
|
<refsect1>
|
|
<title>Symbols</title>
|
|
|
|
<para>
|
|
The following table describes the rough meaning of symbols that may appear inside a GVariant format string. Each
|
|
symbol is described in detail in its own section, including usage examples.
|
|
</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols='2'>
|
|
<colspec colname='col_0'/>
|
|
<colspec colname='col_1'/>
|
|
<tbody>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>Symbol</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>Meaning</emphasis>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>b</literal>, <literal>y</literal>, <literal>n</literal>, <literal>q</literal>, <literal>i</literal>,
|
|
<literal>u</literal>, <literal>x</literal>, <literal>t</literal>, <literal>h</literal>, <literal>d</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing boolean, byte and numeric types. See
|
|
<link linkend='gvariant-format-strings-numeric-types'>Numeric Types</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>s</literal>, <literal>o</literal>, <literal>g</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing string types. See
|
|
<link linkend='gvariant-format-strings-strings'>Strings</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'><literal>v</literal></emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing variant types. See
|
|
<link linkend='gvariant-format-strings-variants'>Variants</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>a</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing arrays. See
|
|
<link linkend='gvariant-format-strings-arrays'>Arrays</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>m</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing maybe types. See
|
|
<link linkend='gvariant-format-strings-maybe-types'>Maybe Types</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>()</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing tuples. See
|
|
<link linkend='gvariant-format-strings-tuples'>Tuples</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>{}</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used for building or deconstructing dictionary entries. See
|
|
<link linkend='gvariant-format-strings-dictionaries'>Dictionaries</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>@</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used as a prefix for a GVariant type string (not a prefix for a format string, so <literal>@as</literal> is
|
|
a valid format string but <literal>@^as</literal> is not). Denotes that a pointer to a
|
|
<link linkend='GVariant'>GVariant</link> should be used in place of the normal C type or types. For
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> this means that you must pass a
|
|
non-<link linkend='NULL:CAPS'><literal>NULL</literal></link> <code>(<link linkend='GVariant'>GVariant</link>
|
|
*)</code>; if it is a floating reference, ownership will be taken, as
|
|
if by using <link linkend="g-variant-ref-sink"><function>g_variant_ref_sink()</function></link>.
|
|
For <link linkend='g-variant-get'><function>g_variant_get()</function></link> this means that you
|
|
must pass a pointer to a <code>(<link linkend='GVariant'>GVariant</link> *)</code> for the value to be returned
|
|
by reference or <link linkend='NULL:CAPS'><literal>NULL</literal></link> to ignore the value. See
|
|
<link linkend='gvariant-format-strings-gvariant'><code>GVariant *</code></link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>*</literal>, <literal>?</literal>, <literal>r</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Exactly equivalent to <literal>@*</literal>, <literal>@?</literal> and <literal>@r</literal>. Provided only for
|
|
completeness so that all GVariant type strings can be used also as format strings. See <link
|
|
linkend='gvariant-format-strings-gvariant'><code>GVariant *</code></link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'><literal>&</literal></emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used as a prefix for a GVariant type string (not a prefix for a format string, so <literal>&s</literal> is
|
|
a valid format string but <literal>&@s</literal> is not).
|
|
Denotes that a C pointer to serialised data
|
|
should be used in place of the normal C type. See
|
|
<link linkend='gvariant-format-strings-pointers'>Pointers</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'><literal>^</literal></emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
Used as a prefix on some specific types of format strings. See
|
|
<link linkend='gvariant-format-strings-convenience'>Convenience Conversions</link> below.
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
|
|
<refsect2 id='gvariant-format-strings-numeric-types'>
|
|
<title>Numeric Types</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>b</literal>, <literal>y</literal>, <literal>n</literal>, <literal>q</literal>,
|
|
<literal>i</literal>, <literal>u</literal>, <literal>x</literal>, <literal>t</literal>, <literal>h</literal>,
|
|
<literal>d</literal>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
Variable argument conversions from numeric types work in the most obvious way possible. Upon encountering one of
|
|
these characters, <link linkend='g-variant-new'><function>g_variant_new()</function></link> takes the equivalent C
|
|
type as an argument. <link linkend='g-variant-get'><function>g_variant_get()</function></link> takes a pointer to
|
|
the equivalent C type (or <link linkend='NULL:CAPS'><literal>NULL</literal></link> to ignore the value).
|
|
</para>
|
|
|
|
<para>
|
|
The equivalent C types are as follows:
|
|
</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols='2'>
|
|
<colspec colname='col_0'/><colspec colname='col_1'/>
|
|
<tbody>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>Character</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>Equivalent C type</emphasis>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>b</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='gboolean'><type>gboolean</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>y</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='guchar'><type>guchar</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>n</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='gint16'><type>gint16</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>q</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='guint16'><type>guint16</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>i</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='gint32'><type>gint32</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>u</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='guint32'><type>guint32</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>x</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='gint64'><type>gint64</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>t</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='guint64'><type>guint64</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>h</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='gint32'><type>gint32</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>d</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<link linkend='gdouble'><type>gdouble</type></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<anchor id='gvariant-varargs'/>
|
|
<para>
|
|
Note that in C, small integer types in variable argument lists are promoted up to <link
|
|
linkend='gint'><type>int</type></link> or <link linkend='guint'><type>unsigned int</type></link> as appropriate, and
|
|
read back accordingly. <link linkend='gint'><type>int</type></link> is 32 bits on every platform on which GLib is
|
|
currently supported. This means that you can use C expressions of type <link linkend='gint'><type>int</type></link>
|
|
with <link linkend='g-variant-new'><function>g_variant_new()</function></link> and format characters
|
|
'<literal>b</literal>', '<literal>y</literal>', '<literal>n</literal>', '<literal>q</literal>',
|
|
'<literal>i</literal>', '<literal>u</literal>' and '<literal>h</literal>'. Specifically, you can use integer
|
|
literals with these characters.
|
|
</para>
|
|
|
|
<para>
|
|
When using the '<literal>x</literal>' and '<literal>t</literal>' characters, you must ensure that the value that you
|
|
provide is 64 bit. This means that you should use a cast or make use of the
|
|
<link linkend='G-GINT64-CONSTANT:CAPS'><literal>G_GINT64_CONSTANT</literal></link> or
|
|
<link linkend='G-GUINT64-CONSTANT:CAPS'><literal>G_GUINT64_CONSTANT</literal></link> macros.
|
|
</para>
|
|
|
|
<para>
|
|
No type promotion occurs when using <link linkend='g-variant-get'><function>g_variant_get()</function></link> since
|
|
it operates with pointers. The pointers must always point to a memory region of exactly the correct size.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *value1, *value2, *value3, *value4;
|
|
|
|
value1 = g_variant_new ("y", 200);
|
|
value2 = g_variant_new ("b", TRUE);
|
|
value3 = g_variant_new ("d", 37.5):
|
|
value4 = g_variant_new ("x", G_GINT64_CONSTANT (998877665544332211));
|
|
|
|
{
|
|
gdouble floating;
|
|
gboolean truth;
|
|
gint64 bignum;
|
|
|
|
|
|
g_variant_get (value1, "y", NULL); /* ignore the value. */
|
|
g_variant_get (value2, "b", &truth);
|
|
g_variant_get (value3, "d", &floating);
|
|
g_variant_get (value4, "x", &bignum);
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-strings'>
|
|
<title>Strings</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>s</literal>, <literal>o</literal>, <literal>g</literal>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
String conversions occur to and from standard nul-terminated C strings. Upon encountering an
|
|
'<literal>s</literal>', '<literal>o</literal>' or '<literal>g</literal>' in a format string,
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> takes a <code>(const
|
|
<link linkend='gchar'>gchar</link> *)</code> and makes a copy of it.
|
|
<link linkend='NULL:CAPS'><literal>NULL</literal></link> is not a valid string; use
|
|
<link linkend='gvariant-format-strings-maybe-types'>maybe types</link> to encode that. If the '<literal>o</literal>' or
|
|
'<literal>g</literal>' characters are used, care must be taken to ensure that the passed string is a valid D-Bus
|
|
object path or D-Bus type signature, respectively.
|
|
</para>
|
|
<para>
|
|
Upon encounting '<literal>s</literal>', '<literal>o</literal>' or '<literal>g</literal>', <link
|
|
linkend='g-variant-get'><function>g_variant_get()</function></link> takes a pointer to a
|
|
<code>(<link linkend='gchar'>gchar</link> *)</code> (ie: <code>(<link linkend='gchar'>gchar</link> **)</code>) and
|
|
sets it to a newly-allocated copy of the string. It is appropriate to free this copy using
|
|
<link linkend='g-free'><function>g_free()</function></link>.
|
|
<link linkend='NULL:CAPS'><literal>NULL</literal></link> may also be passed to indicate that the value of the
|
|
string should be ignored (in which case no copy is made).
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *value1, *value2, *value3;
|
|
|
|
value1 = g_variant_new ("s", "hello world!");
|
|
value2 = g_variant_new ("o", "/must/be/a/valid/path");
|
|
value3 = g_variant_new ("g", "iias");
|
|
|
|
#if 0
|
|
g_variant_new ("s", NULL); /* not valid: NULL is not a string. */
|
|
#endif
|
|
|
|
{
|
|
gchar *result;
|
|
|
|
g_variant_get (value1, "s", &result);
|
|
g_print ("It was '%s'\n", result);
|
|
g_free (result);
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-variants'>
|
|
<title>Variants</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>v</literal>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
Upon encountering a '<literal>v</literal>',
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> takes a <code>(<link
|
|
linkend='GVariant'>GVariant</link> *)</code>. The value of the
|
|
<link linkend='GVariant'><type>GVariant</type></link> is used as the contents of the variant value.
|
|
</para>
|
|
<para>
|
|
Upon encountering a '<literal>v</literal>', <link
|
|
linkend='g-variant-get'><function>g_variant_get()</function></link> takes a pointer to a
|
|
<code>(<link linkend='GVariant'>GVariant</link> *)</code> (ie: <code>(<link linkend='GVariant'>GVariant</link> **)
|
|
</code>). It is set to a new reference to a <link linkend='GVariant'><type>GVariant</type></link> instance
|
|
containing the contents of the variant value. It is appropriate to free this reference using
|
|
<link linkend='g-variant-unref'><function>g_variant_unref()</function></link>.
|
|
<link linkend='NULL:CAPS'><literal>NULL</literal></link> may also be passed to indicate that the value should be
|
|
ignored (in which case no new reference is created).
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *x, *y;
|
|
|
|
/* the following two lines are equivalent: */
|
|
x = g_variant_new ("v", y);
|
|
x = g_variant_new_variant (y);
|
|
|
|
/* as are these: */
|
|
g_variant_get (x, "v", &y);
|
|
y = g_variant_get_variant (x);]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
|
|
<refsect2 id='gvariant-format-strings-arrays'>
|
|
<title>Arrays</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>a</literal>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
Upon encountering an '<literal>a</literal>' character followed by a type string,
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> will take a
|
|
<code>(<link linkend='GVariantBuilder'>GVariantBuilder</link> *)</code> that has been created as an array builder
|
|
for an array of the type given in the type string. The builder will have
|
|
<link linkend='g-variant-builder-end'><function>g_variant_builder_end()</function></link> called on it and the
|
|
result will be used as the value. As a special exception, if the given type string is a definite type, then
|
|
<link linkend='NULL:CAPS'><literal>NULL</literal></link> may be given to mean an empty array of that type.
|
|
</para>
|
|
|
|
<para>
|
|
Upon encountering an '<literal>a</literal>' character followed by a type string,
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link> will take a pointer to a
|
|
<code>(<link linkend='GVariantIter'>GVariantIter</link> *)</code> (ie:
|
|
<code>(<link linkend='GVariantIter'>GVariantIter</link> **)</code>).
|
|
A new heap-allocated iterator is created and returned, initialised for iterating over the elements of the array.
|
|
This iterator should be freed when you are done with it, using
|
|
<link linkend='g-variant-iter-free'><function>g_variant_iter_free()</function></link>.
|
|
<link linkend='NULL:CAPS'><literal>NULL</literal></link> may also be given to indicate that the value of the array
|
|
should be ignored.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariantBuilder *builder;
|
|
GVariant *value;
|
|
|
|
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
|
|
g_variant_builder_add (builder, "s", "when");
|
|
g_variant_builder_add (builder, "s", "in");
|
|
g_variant_builder_add (builder, "s", "the");
|
|
g_variant_builder_add (builder, "s", "course");
|
|
value = g_variant_new ("as", builder);
|
|
g_variant_builder_unref (builder);
|
|
|
|
{
|
|
GVariantIter *iter;
|
|
gchar *str;
|
|
|
|
g_variant_get (value, "as", &iter);
|
|
while (g_variant_iter_loop (iter, "s", &str))
|
|
g_print ("%s\n", str);
|
|
g_variant_iter_free (iter);
|
|
}
|
|
|
|
g_variant_unref (value);]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-maybe-types'>
|
|
<title>Maybe Types</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>m</literal>
|
|
</emphasis>
|
|
</para>
|
|
<para>
|
|
Maybe types are handled in two separate ways depending on the format string that follows the
|
|
'<literal>m</literal>'. The method that is used currently depends entirely on the character immediately following the
|
|
'<literal>m</literal>'.
|
|
</para>
|
|
|
|
<para>
|
|
The first way is used with format strings starting with '<literal>a</literal>', '<literal>s</literal>',
|
|
'<literal>o</literal>', '<literal>g</literal>', '<literal>v</literal>', '<literal>@</literal>',
|
|
'<literal>*</literal>', '<literal>?</literal>', '<literal>r</literal>', '<literal>&</literal>', or
|
|
'<literal>^</literal>'. In all of these cases, for non-maybe types,
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> takes a pointer to a
|
|
non-<link linkend='NULL:CAPS'><literal>NULL</literal></link> value and
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link> returns (by reference) a
|
|
non-<link linkend='NULL:CAPS'><literal>NULL</literal></link> pointer. When any of these format strings are
|
|
prefixed with an '<literal>m</literal>', the type of arguments that are collected does not change in any way, but
|
|
<link linkend='NULL:CAPS'><literal>NULL</literal></link> becomes a permissible value, to indicate the Nothing case.
|
|
</para>
|
|
<para>
|
|
Note that the "special exception" introduced in the array section for constructing empty arrays is ignored
|
|
here. Using a <literal>NULL</literal> pointer with the format string '<literal>mas</literal>' constructs
|
|
the Nothing value -- not an empty array.
|
|
</para>
|
|
<para>
|
|
The second way is used with all other format strings. For
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> an additional
|
|
<link linkend='gboolean'><type>gboolean</type></link> argument is collected and for
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link> an additional
|
|
<code>(<link linkend='gboolean'>gboolean</link> *)</code>. Following this argument, the arguments that are normally
|
|
collected for the equivalent non-maybe type will be collected.
|
|
</para>
|
|
<para>
|
|
If <link linkend='FALSE:CAPS'><literal>FALSE</literal></link> is given to
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> then the Nothing value is constructed and
|
|
the collected arguments are ignored. Otherwise (if <link linkend='TRUE:CAPS'><literal>TRUE</literal></link> was
|
|
given), the arguments are used in the normal way to create the Just value.
|
|
</para>
|
|
<para>
|
|
If <link linkend='NULL:CAPS'><literal>NULL</literal></link> is given to
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link> then the value is ignored. If a
|
|
non-<link linkend='NULL:CAPS'><literal>NULL</literal></link> pointer is given then it is used to return by reference
|
|
whether the value was Just. In the case that the value was Just, the
|
|
<link linkend='gboolean'><type>gboolean</type></link> will be set to
|
|
<link linkend='TRUE:CAPS'><literal>TRUE</literal></link> and the value will be stored in the arguments in the usual
|
|
way. In the case that the value was Nothing, the <link linkend='gboolean'><type>gboolean</type></link> will be set to
|
|
<link linkend='FALSE:CAPS'><literal>FALSE</literal></link> and the arguments will be collected in the normal way
|
|
but have their values set to binary zero.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *value1, *value2, *value3, *value4, *value5, *value6;
|
|
value1 = g_variant_new ("ms", "Hello world");
|
|
value2 = g_variant_new ("ms", NULL);
|
|
value3 = g_variant_new ("(m(ii)s)", TRUE, 123, 456, "Done");
|
|
value4 = g_variant_new ("(m(ii)s)", FALSE, -1, -1, "Done"); /* both '-1' are ignored. */
|
|
value5 = g_variant_new ("(m@(ii)s)", NULL, "Done");
|
|
|
|
{
|
|
GVariant *contents;
|
|
const gchar *cstr;
|
|
gboolean just;
|
|
gint32 x, y;
|
|
gchar *str;
|
|
|
|
g_variant_get (value1, "ms", &str);
|
|
if (str != NULL)
|
|
g_print ("str: %s\n", str);
|
|
else
|
|
g_print ("it was null\n");
|
|
g_free (str);
|
|
|
|
|
|
g_variant_get (value2, "m&s", &cstr);
|
|
if (cstr != NULL)
|
|
g_print ("str: %s\n", cstr);
|
|
else
|
|
g_print ("it was null\n");
|
|
/* don't free 'cstr' */
|
|
|
|
|
|
/* NULL passed for the gboolean *, but two 'gint32 *' still collected */
|
|
g_variant_get (value3, "(m(ii)s)", NULL, NULL, NULL, &str);
|
|
g_print ("string is %s\n", str);
|
|
g_free (str);
|
|
|
|
/* note: &s used, so g_free() not needed */
|
|
g_variant_get (value4, "(m(ii)&s)", &just, &x, &y, &cstr);
|
|
if (just)
|
|
g_print ("it was (%d, %d)\n", x, y);
|
|
else
|
|
g_print ("it was null\n");
|
|
g_print ("string is %s\n", cstr);
|
|
/* don't free 'cstr' */
|
|
|
|
|
|
g_variant_get (value5, "(m*s)", &contents, NULL); /* ignore the string. */
|
|
if (contents != NULL)
|
|
{
|
|
g_variant_get (contents, "(ii)", &x, &y);
|
|
g_print ("it was (%d, %d)\n", x, y);
|
|
g_variant_unref (contents);
|
|
}
|
|
else
|
|
g_print ("it was null\n");
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-tuples'>
|
|
<title>Tuples</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <code>()</code>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
Tuples are handled by handling each item in the tuple, in sequence. Each item is handled in the usual way.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *value1, *value2;
|
|
|
|
value1 = g_variant_new ("(s(ii))", "Hello", 55, 77);
|
|
value2 = g_variant_new ("()");
|
|
|
|
{
|
|
gchar *string;
|
|
gint x, y;
|
|
|
|
g_variant_get (value1, "(s(ii))", &string, &x, &y);
|
|
g_print ("%s, %d, %d\n", string, x, y);
|
|
g_free (string);
|
|
|
|
g_variant_get (value2, "()"); /* do nothing... */
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-gvariant'>
|
|
<title>GVariant *</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>@</literal>, <literal>*</literal>, <literal>?</literal>, <literal>r</literal>
|
|
</emphasis>
|
|
|
|
</para>
|
|
<para>
|
|
Upon encountering a '<literal>@</literal>' in front of a type string,
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> takes a
|
|
non-<link linkend='NULL:CAPS'><literal>NULL</literal></link> pointer to a
|
|
<link linkend='GVariant'><type>GVariant</type></link> and uses its value directly instead of collecting arguments to
|
|
create the value. The provided <link linkend='GVariant'><type>GVariant</type></link> must have a type that matches the
|
|
type string following the '<literal>@</literal>'. '<literal>*</literal>' is
|
|
the same as '<literal>@*</literal>' (ie: take a <link linkend='GVariant'><type>GVariant</type></link> of any type).
|
|
'<literal>?</literal>' is the same as '<literal>@?</literal>' (ie: take a
|
|
<link linkend='GVariant'><type>GVariant</type></link> of any basic type). '<literal>r</literal>' is the same as
|
|
'<literal>@r</literal>' (ie: take a <link linkend='GVariant'><type>GVariant</type></link> of any tuple type).
|
|
</para>
|
|
<para>
|
|
Upon encountering a '<literal>@</literal>' in front of a type string,
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link>
|
|
takes a pointer to a <code>(<link linkend='GVariant'>GVariant</link> *)</code> (ie: a
|
|
<code>(<link linkend='GVariant'>GVariant</link> **)</code>) and sets it to a new reference to a
|
|
<link linkend='GVariant'><type>GVariant</type></link> containing the value (instead of deconstructing the value into
|
|
C types in the usual way). <link linkend='NULL:CAPS'><literal>NULL</literal></link> can be given to ignore the
|
|
value. '<literal>*</literal>', '<literal>?</literal>' and '<literal>r</literal>' are handled in a way analogous to
|
|
what is stated above.
|
|
</para>
|
|
<para>
|
|
You can always use '<literal>*</literal>' as an alternative to '<literal>?</literal>', '<literal>r</literal>' or any
|
|
use of '<literal>@</literal>'. Using the other characters where possible is recommended, however, due to the
|
|
improvements in type safety and code self-documentation.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *value1, *value2;
|
|
|
|
value1 = g_variant_new ("(i@ii)", 44, g_variant_new_int32 (55), 66);
|
|
|
|
/* note: consumes floating reference count on 'value1' */
|
|
value2 = g_variant_new ("(@(iii)*)", value1, g_variant_new_string ("foo"));
|
|
|
|
{
|
|
const gchar *string;
|
|
GVariant *tmp;
|
|
gsize length;
|
|
gint x, y, z;
|
|
|
|
g_variant_get (value2, "((iii)*)", &x, &y, &z, &tmp);
|
|
string = g_variant_get_string (tmp, &length);
|
|
g_print ("it is %d %d %d %s (length=%d)\n", x, y, z, string, (int) length);
|
|
g_variant_unref (tmp);
|
|
|
|
/* quick way to skip all the values in a tuple */
|
|
g_variant_get (value2, "(rs)", NULL, &string); /* or "(@(iii)s)" */
|
|
g_print ("i only got the string: %s\n", string);
|
|
g_free (string);
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-dictionaries'>
|
|
<title>Dictionaries</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <code>{}</code>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
Dictionary entries are handled by handling first the key, then the value. Each is handled in the usual way.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariantBuilder *b;
|
|
GVariant *dict;
|
|
|
|
b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
|
g_variant_builder_add (b, "{sv}", "name", g_variant_new_string ("foo"));
|
|
g_variant_builder_add (b, "{sv}", "timeout", g_variant_new_int32 (10));
|
|
dict = g_variant_builder_end (b);]]></programlisting></informalexample>
|
|
</refsect3>
|
|
|
|
<para>
|
|
To extract data from nested dictionaries you can go through a vardict.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[GVariant *data;
|
|
gint value = 1;
|
|
gint max = 3;
|
|
|
|
/* type (oa{sa{sv}) */
|
|
data = g_variant_new_parsed ("(%o, {'brightness': {'value': <%i>, 'max': <%i>}})",
|
|
"/object/path", value, max);
|
|
{
|
|
GVariant *params;
|
|
GVariant *p_brightness;
|
|
gchar *obj
|
|
gint p_max;
|
|
|
|
g_variant_get (data, "(o@a{?*})", &obj, ¶ms);
|
|
g_print ("object_path: %s\n", obj);
|
|
|
|
p_brightness = g_variant_lookup_value (params, "brightness", G_VARIANT_TYPE_VARDICT);
|
|
g_variant_lookup (p_brightness, "max", "i", &p_max);
|
|
g_print ("max: %d\n", p_max);
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-pointers'>
|
|
<title>Pointers</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <code>&</code>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
The '<code>&</code>' character is used to indicate that serialised data should be directly exchanged via a
|
|
pointer.
|
|
</para>
|
|
<para>
|
|
Currently, the only use for this character is when it is applied to a string (ie: '<literal>&s</literal>',
|
|
'<literal>&o</literal>' or '<code>&g</code>'). For
|
|
<link linkend='g-variant-new'><function>g_variant_new()</function></link> this has absolutely no effect. The string
|
|
is collected and duplicated normally. For <link linkend='g-variant-get'><function>g_variant_get()</function></link>
|
|
it means that instead of creating a newly allocated copy of the string, a pointer to the serialised data is
|
|
returned. This pointer should not be freed. Validity checks are performed to ensure that the string data will
|
|
always be properly nul-terminated.
|
|
</para>
|
|
|
|
<refsect3>
|
|
<title>Examples</title>
|
|
<informalexample><programlisting>
|
|
<![CDATA[{
|
|
const gchar *str;
|
|
GVariant *value;
|
|
|
|
value = g_variant_new ("&s", "hello world");
|
|
g_variant_get (value, "&s", &str);
|
|
g_print ("string is: %s\n", str);
|
|
/* no need to free str */
|
|
}]]></programlisting></informalexample>
|
|
</refsect3>
|
|
</refsect2>
|
|
|
|
<refsect2 id='gvariant-format-strings-convenience'>
|
|
<title>Convenience Conversions</title>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Characters: <literal>^</literal>
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
The '<literal>^</literal>' character currently supports conversion to and from bytestrings or to and from arrays
|
|
of strings or bytestrings. It does not support byte arrays. It has a number of forms.
|
|
</para>
|
|
|
|
<para>
|
|
In all forms, when used with <link linkend='g-variant-new'><function>g_variant_new()</function></link> one
|
|
pointer value is collected from the variable arguments and passed to a function (as given in the table below).
|
|
The result of that function is used as the value for this position. When used with
|
|
<link linkend='g-variant-get'><function>g_variant_get()</function></link> one pointer value is produced by using
|
|
the function (given in the table) and returned by reference.
|
|
</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols='2'>
|
|
<colspec colname='col_0'/>
|
|
<colspec colname='col_1'/>
|
|
<colspec colname='col_2'/>
|
|
<tbody>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>Conversion</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Used with <link linkend='g-variant-new'><function>g_variant_new()</function></link>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
Used with <link linkend='g-variant-get'><function>g_variant_get()</function></link>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^as</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1' morerows='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-new-strv'><function>g_variant_new_strv()</function></link>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-dup-strv'><function>g_variant_dup_strv()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^a&s</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-get-strv'><function>g_variant_get_strv()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^ao</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1' morerows='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-new-objv'><function>g_variant_new_objv()</function></link>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-dup-objv'><function>g_variant_dup_objv()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^a&o</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-get-objv'><function>g_variant_get_objv()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^ay</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1' morerows='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-new-bytestring'><function>g_variant_new_bytestring()</function></link>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-dup-bytestring'><function>g_variant_dup_bytestring()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^&ay</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-get-bytestring'><function>g_variant_get_bytestring()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^aay</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1' morerows='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-new-bytestring-array'><function>g_variant_new_bytestring_array()</function></link>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-dup-bytestring-array'><function>g_variant_dup_bytestring_array()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
<row rowsep='1'>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
<emphasis role='strong'>
|
|
<literal>^a&ay</literal>
|
|
</emphasis>
|
|
</para>
|
|
</entry>
|
|
<entry colsep='1' rowsep='1'>
|
|
<para>
|
|
equivalent to <link linkend='g-variant-get-bytestring-array'><function>g_variant_get_bytestring_array()</function></link>
|
|
</para>
|
|
</entry>
|
|
</row>
|
|
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</refsect2>
|
|
</refsect1>
|
|
</refentry>
|