php-doc-en/internals/zendapi/structure.xml
Gabor Hojtsy 811a7db395 New internals documentation section added:
- PHP 3 development appendix moved to this part
 - Streams API docs moved to this part
 - ZendAPI docs with figures integrated in this part

More info: http://news.php.net/php.doc/969369673


git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@194089 c90b9560-bf6c-de11-be94-00142212c4b1
2005-08-21 16:27:09 +00:00

712 lines
29 KiB
XML

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!-- $Revision: 1.1 $ -->
<sect1 id="zend.structure">
<title>Source Discussion</title>
<para>
Now that you've got a safe build environment and you're able to include
the modules into PHP files, it's time to discuss how everything works.
</para>
<sect2 id="zend.structure.module">
<title>Module Structure</title>
<para>
All PHP modules follow a common structure:
<itemizedlist>
<listitem>
<para>
Header file inclusions (to include all required macros, API
definitions, etc.)
</para>
</listitem>
<listitem>
<para>
C declaration of exported functions (required to declare the Zend
function block)
</para>
</listitem>
<listitem>
<para>Declaration of the Zend function block</para>
</listitem>
<listitem>
<para>Declaration of the Zend module block</para>
</listitem>
<listitem>
<para>Implementation of <function>get_module</function></para>
</listitem>
<listitem>
<para>Implementation of all exported functions</para>
</listitem>
</itemizedlist></para>
</sect2>
<sect2 id="zend.structure.headers">
<title>Header File Inclusions</title>
<para>
The only header file you really have to include for your modules is
<filename>php.h</filename>, located in the PHP directory. This file makes all
macros and API definitions required to build new modules available to your
code.
</para>
<para>
<emphasis>Tip:</emphasis> It's good practice to create a separate
header file for your module that contains module-specific
definitions. This header file should contain all the forward
definitions for exported functions and include
<filename>php.h</filename>. If you created your module using
<literal>ext_skel</literal> you already have such a header file
prepared.
</para>
</sect2>
<sect2 id="zend.structure.exporting-functions">
<title>Declaring Exported Functions</title>
<para>
To declare functions that are to be exported (i.e., made available to PHP
as new native functions), Zend provides a set of macros. A sample declaration
looks like this:
<programlisting>
ZEND_FUNCTION ( my_function );
</programlisting>
</para>
<para>
<literal>ZEND_FUNCTION</literal> declares a new C function that complies
with Zend's internal API. This means that the function is of
type <literal>void</literal> and
accepts <literal>INTERNAL_FUNCTION_PARAMETERS</literal> (another macro) as
parameters. Additionally, it prefixes the function name with
<literal>zif</literal>. The immediately expanded version of the above
definitions would look like this:
<programlisting>
void zif_my_function ( INTERNAL_FUNCTION_PARAMETERS );
</programlisting>
Expanding <literal>INTERNAL_FUNCTION_PARAMETERS</literal>
results in the following:
<programlisting>
void zif_my_function( int ht
, zval * return_value
, zval * this_ptr
, int return_value_used
, zend_executor_globals * executor_globals
);
</programlisting>
</para>
<para>
Since the interpreter and executor core have been separated from
the main PHP package, a second API defining macros and function
sets has evolved: the Zend API. As the Zend API now handles quite
a few of the responsibilities that previously belonged to PHP, a
lot of PHP functions have been reduced to macros aliasing to calls
into the Zend API. The recommended practice is to use the Zend API
wherever possible, as the old API is only preserved for
compatibility reasons. For example, the types <envar>zval</envar>
and <envar>pval</envar> are identical. <envar>zval</envar> is
Zend's definition; <envar>pval</envar> is PHP's definition
(actually, <envar>pval</envar> is an alias for <envar>zval</envar>
now). As the macro <literal>INTERNAL_FUNCTION_PARAMETERS</literal>
is a Zend macro, the above declaration contains
<envar>zval</envar>. When writing code, you should always use
<envar>zval</envar> to conform to the new Zend API.
</para>
<para>
The parameter list of this declaration is very important; you should keep these parameters in mind (see <xref linkend='tab.parameters'/> for descriptions).
<table id='tab.parameters'>
<title>Zend's Parameters to Functions Called from PHP</title>
<tgroup cols="2">
<colspec colnum="1" colname="col1" colwidth="1.00*"/>
<colspec colnum="2" colname="col2" colwidth="1.79*"/>
<tbody>
<row>
<entry colname="col1">Parameter</entry>
<entry colname="col2">Description</entry>
</row>
<row>
<entry colname="col1"><envar>ht</envar></entry>
<entry colname="col2">
The number of arguments passed to the Zend function.
You should not touch this directly, but instead use ZEND_NUM_ARGS() to obtain the
value.
</entry>
</row>
<row>
<entry colname="col1">
<envar>return_value</envar></entry>
<entry colname="col2">
This variable is used to pass any return values of
your function back to PHP. Access to this variable is best done using the
predefined macros. For a description of these see below.
</entry>
</row>
<row>
<entry colname="col1"><envar>this_ptr</envar></entry>
<entry colname="col2">
Using this variable, you can gain access to the object
in which your function is contained, if it's used within an object. Use
the function <function>getThis</function> to obtain this pointer.
</entry>
</row>
<row>
<entry colname="col1"><envar>return_value_used</envar></entry>
<entry colname="col2">
This flag indicates whether an eventual return value
from this function will actually be used by the calling script.
<literal>0</literal> indicates that the return value is not used;
<literal>1</literal> indicates that the caller expects a return value.
Evaluation of this flag can be done to verify correct usage of the function as
well as speed optimizations in case returning a value requires expensive
operations (for an example, see how <filename>array.c</filename> makes use of
this).
</entry>
</row>
<row>
<entry colname="col1"><envar>executor_globals</envar></entry>
<entry colname="col2">
This variable points to global settings of the Zend
engine. You'll find this useful when creating new variables, for example
(more about this later). The executor globals can also be introduced to your
function by using the macro <literal>TSRMLS_FETCH()</literal>.
</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</sect2>
<sect2 id="zend.structure.function-block">
<title>Declaration of the Zend Function Block</title>
<para>
Now that you have declared the functions to be exported, you also
have to introduce them to Zend. Introducing the list of functions is done by
using an array of <envar>zend_function_entry</envar>. This array consecutively
contains all functions that are to be made available externally, with the function's name
as it should appear in PHP and its name as defined in the C source.
Internally, <envar>zend_function_entry</envar> is defined as shown in
<xref linkend='example.zend-function-entry'/>.
</para>
<para>
<example id='example.zend-function-entry'>
<title>Internal declaration of <envar>zend_function_entry</envar>.</title>
<programlisting>
typedef struct _zend_function_entry {
char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
unsigned char *func_arg_types;
} zend_function_entry;
</programlisting>
<informaltable>
<tgroup cols="2">
<colspec colnum="1" colname="col1" colwidth="1.00*"/>
<colspec colnum="2" colname="col2" colwidth="1.82*"/>
<tbody>
<row>
<entry colname="col1">Entry</entry>
<entry colname="col2">Description</entry>
</row>
<row>
<entry colname="col1"><envar>fname</envar></entry>
<entry colname="col2">
Denotes the function name as seen in PHP (for
example, <literal>fopen</literal>, <literal>mysql_connect</literal>, or, in our
example, <literal>first_module</literal>).
</entry>
</row>
<row>
<entry colname="col1"><envar>handler</envar></entry>
<entry colname="col2">
Pointer to the C function responsible for handling calls
to this function. For example, see the standard macro
<literal>INTERNAL_FUNCTION_PARAMETERS</literal> discussed earlier.
</entry>
</row>
<row>
<entry colname="col1"><envar>func_arg_types</envar></entry>
<entry colname="col2">
Allows you to mark certain parameters so that they're forced
to be passed by reference. You usually should set this to
NULL.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</example>
In the example above, the declaration looks like this:
<programlisting>
zend_function_entry firstmod_functions[] =
{
ZEND_FE(first_module, NULL)
{NULL, NULL, NULL}
};
</programlisting>
You can see that the last entry in the list always has to be
<literal>{NULL, NULL, NULL}</literal>.
This marker has to be set for Zend to know when the end of the
list of exported functions is reached.
</para>
<note>
<para>
You <emphasis>cannot</emphasis> use the predefined macros for the
end marker, as these would try to refer to a function named "NULL"!
</para>
</note>
<para>
The macro <literal>ZEND_FE</literal> (short for 'Zend Function
Entry') simply expands to a structure entry in
<envar>zend_function_entry</envar>. Note that these macros
introduce a special naming scheme to your functions - your C
functions will be prefixed with <literal>zif_</literal>, meaning
that <literal>ZEND_FE(first_module)</literal> will refer to a C
function <function>zif_first_module</function>. If you want to mix
macro usage with hand-coded entries (not a good practice), keep
this in mind.
</para>
<para>
Tip: Compilation errors that refer to functions
named <function>zif_*</function> relate to functions defined
with <literal>ZEND_FE</literal>.
</para>
<para>
<xref linkend='tab.funcdef-macros'/> shows a list of all the macros
that you can use to define functions.
</para>
<table id='tab.funcdef-macros'>
<title>Macros for Defining Functions</title>
<tgroup cols="2">
<colspec colnum="1" colname="col1" colwidth="1.00*"/>
<colspec colnum="2" colname="col2" colwidth="1.08*"/>
<tbody>
<row>
<entry colname="col1">Macro Name</entry>
<entry colname="col2">Description</entry>
</row>
<row>
<entry colname="col1"><literal>ZEND_FE(name, arg_types)</literal></entry>
<entry colname="col2">
Defines a function entry of the name <envar>name</envar> in
<envar>zend_function_entry</envar>. Requires a corresponding C
function. <envar>arg_types</envar> needs to be set to <literal>NULL</literal>.
This function uses automatic C function name generation by prefixing the PHP
function name with <literal>zif_</literal>.
For example, <literal>ZEND_FE("first_module", NULL)</literal> introduces a
function <function>first_module</function> to PHP and links it to the C
function <function>zif_first_module</function>. Use in conjunction
with <literal>ZEND_FUNCTION</literal>.
</entry>
</row>
<row>
<entry colname="col1">
<literal>ZEND_NAMED_FE(php_name, name, arg_types)</literal>
</entry>
<entry colname="col2">
Defines a function that will be available to PHP by the
name <envar>php_name</envar> and links it to the corresponding C
function <envar>name</envar>. <envar>arg_types</envar> needs to be set
to <literal>NULL</literal>. Use this function if you don't want the automatic
name prefixing introduced by <literal>ZEND_FE</literal>. Use in conjunction
with <literal>ZEND_NAMED_FUNCTION</literal>.
</entry>
</row>
<row>
<entry colname="col1">
<literal>ZEND_FALIAS(name, alias, arg_types)</literal>
</entry>
<entry colname="col2">
Defines an alias named <envar>alias</envar> for
<envar>name</envar>. <envar>arg_types</envar> needs to be set
to <literal>NULL</literal>. Doesn't require a corresponding C
function; refers to the alias target instead.
</entry>
</row>
<row>
<entry colname="col1"><literal>PHP_FE(name, arg_types)</literal></entry>
<entry colname="col2">
Old PHP API equivalent of <literal>ZEND_FE</literal>.
</entry>
</row>
<row>
<entry colname="col1">
<literal>PHP_NAMED_FE(runtime_name, name, arg_types)</literal>
</entry>
<entry colname="col2">
Old PHP API equivalent of <literal>ZEND_NAMED_FE</literal>.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<emphasis>Note:</emphasis> You can't use
<literal>ZEND_FE</literal> in conjunction with
<literal>PHP_FUNCTION</literal>, or <literal>PHP_FE</literal> in
conjunction with <literal>ZEND_FUNCTION</literal>. However, it's
perfectly legal to mix <literal>ZEND_FE</literal> and
<literal>ZEND_FUNCTION</literal> with <literal>PHP_FE</literal>
and <literal>PHP_FUNCTION</literal> when staying with the same
macro set for each function to be declared. But mixing is
<emphasis>not</emphasis> recommended; instead, you're advised to
use the <literal>ZEND_*</literal> macros only.
</para>
</sect2>
<sect2 id="zend.structure.module-block">
<title>Declaration of the Zend Module Block</title>
<para>
This block is stored in the structure
<envar>zend_module_entry</envar> and contains all necessary
information to describe the contents of this module to Zend. You can
see the internal definition of this module in
<xref linkend='example.zend-module-entry'/>.
</para>
<example id='example.zend-module-entry'>
<title>Internal declaration of <envar>zend_module_entry</envar>.</title>
<programlisting>
typedef struct _zend_module_entry zend_module_entry;
struct _zend_module_entry {
unsigned short size;
unsigned int zend_api;
unsigned char zend_debug;
unsigned char zts;
char *name;
zend_function_entry *functions;
int (*module_startup_func)(INIT_FUNC_ARGS);
int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
int (*request_startup_func)(INIT_FUNC_ARGS);
int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);
void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);
char *version;
[ Rest of the structure is not interesting here ]
};
</programlisting>
<informaltable>
<tgroup cols="2">
<colspec colnum="1" colname="col1" colwidth="1.00*"/>
<colspec colnum="2" colname="col2" colwidth="1.69*"/>
<thead>
<row>
<entry colname="col1">Entry</entry>
<entry colname="col2">Description</entry>
</row>
</thead>
<tbody>
<row>
<entry colname="col1">
<envar>size</envar>, <envar>zend_api</envar>,
<envar>zend_debug</envar> and <envar>zts</envar>
</entry>
<entry colname="col2">
Usually filled with the
<literal>"STANDARD_MODULE_HEADER"</literal>, which fills these
four members with the size of the whole zend_module_entry, the
<literal>ZEND_MODULE_API_NO</literal>, whether it is a debug
build or normal build (<literal>ZEND_DEBUG</literal>) and if
ZTS is enabled (<literal>USING_ZTS</literal>).
</entry>
</row>
<row>
<entry colname="col1"><envar>name</envar></entry>
<entry colname="col2">
Contains the module name (for example, <literal>"File
functions"</literal>, <literal>"Socket functions"</literal>,
<literal>"Crypt"</literal>, etc.). This name will show up in
<function>phpinfo</function>, in the section "Additional
Modules."
</entry>
</row>
<row>
<entry colname="col1"><envar>functions</envar></entry>
<entry colname="col2">
Points to the Zend function block, discussed in the preceding
section.
</entry>
</row>
<row>
<entry colname="col1"><envar>module_startup_func</envar></entry>
<entry colname="col2">
This function is called once upon module initialization and can
be used to do one-time initialization steps (such as initial
memory allocation, etc.). To indicate a failure during
initialization, return <literal>FAILURE</literal>; otherwise,
<literal>SUCCESS</literal>. To mark this field as unused, use
<literal>NULL</literal>. To declare a function, use the macro
<literal>ZEND_MINIT</literal>.
</entry>
</row>
<row>
<entry colname="col1"><envar>module_shutdown_func</envar></entry>
<entry colname="col2">
This function is called once upon module shutdown and can be
used to do one-time deinitialization steps (such as memory
deallocation). This is the counterpart to
<function>module_startup_func</function>. To indicate a failure
during deinitialization, return <literal>FAILURE</literal>;
otherwise, <literal>SUCCESS</literal>. To mark this field as
unused, use <literal>NULL</literal>. To declare a function, use
the macro <literal>ZEND_MSHUTDOWN</literal>.
</entry>
</row>
<row>
<entry colname="col1"><envar>request_startup_func</envar></entry>
<entry colname="col2">
This function is called once upon every page request and can be
used to do one-time initialization steps that are required to
process a request. To indicate a failure here, return
<literal>FAILURE</literal>; otherwise,
<literal>SUCCESS</literal>. <emphasis>Note:</emphasis> As
dynamic loadable modules are loaded only on page requests, the
request startup function is called right after the module
startup function (both initialization events happen at the same
time). To mark this field as unused, use
<literal>NULL</literal>. To declare a function, use the macro
<literal>ZEND_RINIT</literal>.
</entry>
</row>
<row>
<entry colname="col1"><envar>request_shutdown_func</envar></entry>
<entry colname="col2">
This function is called once after every page request and works
as counterpart to <function>request_startup_func</function>. To
indicate a failure here, return <literal>FAILURE</literal>;
otherwise, <literal>SUCCESS</literal>.
<emphasis>Note:</emphasis> As dynamic loadable modules are
loaded only on page requests, the request shutdown function is
immediately followed by a call to the module shutdown handler
(both deinitialization events happen at the same time). To mark
this field as unused, use <literal>NULL</literal>. To declare a
function, use the macro <literal>ZEND_RSHUTDOWN</literal>.
</entry>
</row>
<row>
<entry colname="col1"><envar>info_func</envar></entry>
<entry colname="col2">
When <function>phpinfo</function> is called in a script, Zend
cycles through all loaded modules and calls this function.
Every module then has the chance to print its own "footprint"
into the output page. Generally this is used to dump
environmental or statistical information. To mark this field as
unused, use <literal>NULL</literal>. To declare a function, use
the macro <literal>ZEND_MINFO</literal>.
</entry>
</row>
<row>
<entry colname="col1"><envar>version</envar></entry>
<entry colname="col2">
The version of the module. You can use
<literal>NO_VERSION_YET</literal> if you don't want to give the
module a version number yet, but we really recommend that you
add a version string here. Such a version string can look like
this (in chronological order): <literal>"2.5-dev"</literal>,
<literal>"2.5RC1"</literal>, <literal>"2.5"</literal> or
<literal>"2.5pl3"</literal>.
</entry>
</row>
<row>
<entry colname="col1">Remaining structure elements</entry>
<entry colname="col2">
These are used internally and can be prefilled by using the
macro <literal>STANDARD_MODULE_PROPERTIES_EX</literal>. You
should not assign any values to them. Use
<literal>STANDARD_MODULE_PROPERTIES_EX</literal> only if you
use global startup and shutdown functions; otherwise, use
<literal>STANDARD_MODULE_PROPERTIES</literal> directly.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</example>
<para>
In our example, this structure is implemented as follows:
<programlisting>
zend_module_entry firstmod_module_entry =
{
STANDARD_MODULE_HEADER,
"First Module",
firstmod_functions,
NULL, NULL, NULL, NULL, NULL,
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES,
};
</programlisting>
This is basically the easiest and most minimal set of values you
could ever use. The module name is set to <literal>First
Module</literal>, then the function list is referenced, after which
all startup and shutdown functions are marked as being unused.
</para>
<para>
For reference purposes, you can find a list of the macros involved
in declared startup and shutdown functions in
<xref linkend='tab.init-shutdown'/>. These are
not used in our basic example yet, but will be demonstrated later
on. You should make use of these macros to declare your startup and
shutdown functions, as these require special arguments to be passed
(<literal>INIT_FUNC_ARGS</literal> and
<literal>SHUTDOWN_FUNC_ARGS</literal>), which are automatically
included into the function declaration when using the predefined
macros. If you declare your functions manually and the PHP
developers decide that a change in the argument list is necessary,
you'll have to change your module sources to remain compatible.
</para>
<table id='tab.init-shutdown'>
<title>Macros to Declare Startup and Shutdown Functions</title>
<tgroup cols="2">
<colspec colnum="1" colname="col1" colwidth="1.00*"/>
<colspec colnum="2" colname="col2" colwidth="1.41*"/>
<tbody>
<row>
<entry colname="col1">Macro</entry>
<entry colname="col2">Description</entry>
</row>
<row>
<entry colname="col1"><literal>ZEND_MINIT(module)</literal></entry>
<entry colname="col2">
Declares a function for module startup. The generated name will
be <literal>zend_minit_&lt;module&gt;</literal> (for example,
<literal>zend_minit_first_module</literal>). Use in
conjunction with <literal>ZEND_MINIT_FUNCTION</literal>.
</entry>
</row>
<row>
<entry colname="col1"><literal>ZEND_MSHUTDOWN(module)</literal></entry>
<entry colname="col2">
Declares a function for module shutdown. The generated name
will be <literal>zend_mshutdown_&lt;module&gt;</literal> (for
example, <literal>zend_mshutdown_first_module</literal>). Use
in conjunction with <literal>ZEND_MSHUTDOWN_FUNCTION</literal>.
</entry>
</row>
<row>
<entry colname="col1"><literal>ZEND_RINIT(module)</literal></entry>
<entry colname="col2">
Declares a function for request startup. The generated name
will be <literal>zend_rinit_&lt;module&gt;</literal> (for
example, <literal>zend_rinit_first_module</literal>). Use in
conjunction with <literal>ZEND_RINIT_FUNCTION</literal>.
</entry>
</row>
<row>
<entry colname="col1"><literal>ZEND_RSHUTDOWN(module)</literal></entry>
<entry colname="col2">
Declares a function for request shutdown. The generated name
will be <literal>zend_rshutdown_&lt;module&gt;</literal> (for
example, <literal>zend_rshutdown_first_module</literal>). Use
in conjunction with <literal>ZEND_RSHUTDOWN_FUNCTION</literal>.
</entry>
</row>
<row>
<entry colname="col1"><literal>ZEND_MINFO(module)</literal></entry>
<entry colname="col2">
Declares a function for printing module information, used when
<function>phpinfo</function> is called. The generated name will
be <literal>zend_info_&lt;module&gt;</literal> (for example,
<literal>zend_info_first_module</literal>). Use in conjunction
with <literal>ZEND_MINFO_FUNCTION</literal>.
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="zend.structure.get-module">
<title>Creation of <function>get_module</function></title>
<para>
This function is special to all dynamic loadable modules. Take a
look at the creation via the <literal>ZEND_GET_MODULE</literal>
macro first:
</para>
<programlisting>
#if COMPILE_DL_FIRSTMOD
ZEND_GET_MODULE(firstmod)
#endif
</programlisting>
<para>
The function implementation is surrounded by a conditional
compilation statement. This is needed since the function
<function>get_module</function> is only required if your module is
built as a dynamic extension. By specifying a definition of
<literal>COMPILE_DL_FIRSTMOD</literal> in the compiler command
(see above for a discussion of the compilation instructions
required to build a dynamic extension), you can instruct your
module whether you intend to build it as a dynamic extension or as
a built-in module. If you want a built-in module, the
implementation of <function>get_module</function> is simply left
out.
</para>
<para>
<function>get_module</function> is called by Zend at load time
of the module. You can think of it as being invoked by the
<function>dl</function> call in your script. Its purpose is to pass the
module information block back to Zend in order to inform the engine about the
module contents.
</para>
<para>
If you don't implement a <function>get_module</function> function in
your dynamic loadable module, Zend will compliment you with an error message
when trying to access it.
</para>
</sect2>
<sect2 id="zend.structure.implementation">
<title>Implementation of All Exported Functions</title>
<para>Implementing the exported functions is the final step. The
example function in <literal>first_module</literal> looks like this:
<programlisting>
ZEND_FUNCTION(first_module)
{
long parameter;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &amp;parameter) == FAILURE) {
return;
}
RETURN_LONG(parameter);
}
</programlisting>
The function declaration is done
using <literal>ZEND_FUNCTION</literal>, which corresponds
to <literal>ZEND_FE</literal> in the function entry table (discussed
earlier).
</para>
<para>
After the declaration, code for checking and retrieving the function's
arguments, argument conversion, and return value generation follows (more on
this later).
</para>
</sect2>
<sect2 id="zend.structure.summary">
<title>Summary</title>
<para>
That's it, basically - there's nothing more to implementing PHP modules.
Built-in modules are structured similarly to dynamic modules, so, equipped
with the information presented in the previous sections, you'll be able to
fight the odds when encountering PHP module source files.
</para>
<para>
Now, in the following sections, read on about how to make use of PHP's
internals to build powerful extensions.
</para>
</sect2>
</sect1>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"../../../manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->