You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apreq-cvs@httpd.apache.org by jo...@apache.org on 2003/06/15 12:33:01 UTC
cvs commit: httpd-apreq-2/src apreq.h apreq_cookie.h apreq_params.h apreq_parsers.h
joes 2003/06/15 03:33:01
Modified: build README doxygen.conf
env libapreq_cgi.c mod_apreq.c
glue/perl Makefile.PL README
glue/perl/xsbuilder apreq_xs_postperl.h
glue/perl/xsbuilder/Apache/Cookie Apache__Cookie.h Cookie_pm
glue/perl/xsbuilder/Apache/Request Apache__Request.h
glue/perl/xsbuilder/maps apreq_functions.map
src apreq.h apreq_cookie.h apreq_params.h
apreq_parsers.h
Log:
Lots of doxygen updates. Preliminary changes to prefetch code in mod_apreq.c, and some XS fixes to allow constructors to derive their classname from the caller.
Revision Changes Path
1.4 +18 -3 httpd-apreq-2/build/README
Index: README
===================================================================
RCS file: /home/cvs/httpd-apreq-2/build/README,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- README 6 May 2003 02:11:35 -0000 1.3
+++ README 15 Jun 2003 10:33:00 -0000 1.4
@@ -1,14 +1,14 @@
build/
- General Info on the httpd-apreq community.
+ General Info on the apreq community.
Utility scripts for building & packaging httpd-apreq-2.
-UPDATING THE httpd-apreq WEBSITE:
+UPDATING THE WEBSITE:
(cf: http://jakarta.apache.org/site/jakarta-site2.html )
+ RedHat Linux Instructions:
-RedHat Linux Instructions:
1) Download and install j2re and j2sdk rpms from Sun's
website:
@@ -38,3 +38,18 @@
$ cd /www/httpd.apache.org
$ cvs update index.html apreq/
+
+
+
+BUILDING THE DOXYGEN DOCUMENTATION:
+
+ Be sure doxygen is installed on your machine. Then cd to
+ the base directory (httpd-apreq-2) and run
+
+ % make docs
+
+ This will generate the C documentation in the docs/ directory
+ using build/doxygen.conf as the config file for doxygen.
+
+
+
1.2 +2 -2 httpd-apreq-2/build/doxygen.conf
Index: doxygen.conf
===================================================================
RCS file: /home/cvs/httpd-apreq-2/build/doxygen.conf,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- doxygen.conf 15 Jun 2003 05:25:37 -0000 1.1
+++ doxygen.conf 15 Jun 2003 10:33:00 -0000 1.2
@@ -301,7 +301,7 @@
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = src env
+INPUT = src env glue/perl/xsbuilder
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
1.6 +17 -1 httpd-apreq-2/env/libapreq_cgi.c
Index: libapreq_cgi.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/env/libapreq_cgi.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- libapreq_cgi.c 20 May 2003 20:43:22 -0000 1.5
+++ libapreq_cgi.c 15 Jun 2003 10:33:00 -0000 1.6
@@ -63,7 +63,21 @@
#include <stdio.h>
#define dCTX struct env_ctx *ctx = (struct env_ctx *)env
-/* the "warehouse" */
+
+/**
+ * @file libapreq_cgi.c
+ * @brief Source for libapreq_cgi.a.
+ */
+
+/**
+ * libapreq_cgi is a static library that CGI "scripts" (written
+ * in C) can link against to to have libapreq work in a CGI environment.
+ *
+ * @defgroup libapreq_cgi libapreq_cgi.a
+ * @ingroup MODULES
+ * @brief Static library for linking libapreq to a CGI C-script.
+ * @{
+ */
struct env_ctx {
apr_pool_t *pool;
@@ -170,3 +184,5 @@
return apreq_request_parse(apreq_request(env,NULL), ctx->bb);
}
+
+/** @} */
1.16 +62 -25 httpd-apreq-2/env/mod_apreq.c
Index: mod_apreq.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/env/mod_apreq.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- mod_apreq.c 9 Jun 2003 04:00:44 -0000 1.15
+++ mod_apreq.c 15 Jun 2003 10:33:00 -0000 1.16
@@ -69,21 +69,27 @@
#define dR request_rec *r = (request_rec *)env
-/* the "warehouse"
- * The parser body is attached to the filter-selected parser.
- *
- * request & jar are in r->request_config;
- * parser config data inside parser_t
- * (may need to be merged with server/request cfg)
- *
+/**
+ * @file mod_apreq.c
+ * @brief Source for mod_apreq.so.
*/
+/**
+ * Uses apxs to compile and install.
+ * @defgroup mod_apreq mod_apreq.so
+ * @ingroup MODULES
+ * @brief Apache-2 filter module.
+ * @{
+ */
+
+/** The warehouse. */
struct env_config {
apreq_jar_t *jar;
apreq_request_t *req;
ap_filter_t *f;
};
+/** Tracks the filter state */
struct filter_ctx {
apr_bucket_brigade *bb;
apr_off_t bytes_seen;
@@ -91,10 +97,11 @@
};
-const char apreq_env[] = "APACHE2";
+const char apreq_env[] = "APACHE2"; /**< internal name of module */
static const char filter_name[] = "APREQ";
module AP_MODULE_DECLARE_DATA apreq_module;
+/** request logger */
APREQ_DECLARE_LOG(apreq_log)
{
dR;
@@ -124,6 +131,11 @@
return apr_table_get(r->headers_in, name);
}
+/**
+ * r->headers_out.
+ * @bug Sending a Set-Cookie header on a 304
+ * requires a different header table.
+ */
APREQ_DECLARE(apr_status_t)apreq_env_header_out(void *env, const char *name,
char *value)
{
@@ -195,6 +207,13 @@
return c->req;
}
+/**
+ * Reads data directly into the parser.
+ *@bug This function is badly broken. It needs to use
+ * SPECULATIVE mode when doing readsin pre-content-handler
+ * phase, but should use a normal (READBYTES) read otherwise.
+ */
+
APREQ_DECLARE(apr_status_t) apreq_env_read(void *env,
apr_read_type_e block,
apr_off_t bytes)
@@ -207,34 +226,49 @@
return ap_get_brigade(f, NULL, AP_MODE_SPECULATIVE, block, bytes);
}
+APR_INLINE
+static void apreq_filter_make_context(ap_filter_t *f)
+{
+ request_rec *r = f->r;
+ apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(r->pool);
+ struct filter_ctx *ctx = apr_palloc(r->pool, sizeof *ctx);
+ f->ctx = ctx;
+ ctx->bb = apr_brigade_create(r->pool, alloc);
+ ctx->bytes_seen = 0;
+ ctx->status = APR_INCOMPLETE;
+
+ apreq_log(APREQ_DEBUG 0, r,
+ "apreq filter context created." );
+}
+
+APR_INLINE
+static void apreq_filter_relocate(ap_filter_t *f)
+{
+ request_rec *r = f->r;
+ if (f != r->input_filters) {
+ ap_filter_t *top = r->input_filters;
+ ap_remove_input_filter(f);
+ r->input_filters = f;
+ f->next = top;
+ }
+}
static apr_status_t apreq_filter_init(ap_filter_t *f)
{
request_rec *r = f->r;
struct filter_ctx *ctx;
- /* Now we have to deal with the possibility that apreq may have
+ /* We must be inside config.c:ap_invoke_handler ->
+ * ap_invoke_filter_init (r->input_filters), and
+ * we have to deal with the possibility that apreq may have
* prefetched data prior to apache running the ap_invoke_filter_init
* hook.
*/
if (f->ctx) {
-
- /* must be inside config.c:ap_invoke_handler ->
- * ap_invoke_filter_init (r->input_filters)
- */
ctx = f->ctx;
-
- /*
- * first we relocate the filter to the top of the chain.
- */
-
- if (f != r->input_filters) {
- ap_filter_t *top = r->input_filters;
- ap_remove_input_filter(f);
- r->input_filters = f;
- f->next = top;
- }
+ /* first we relocate the filter to the top of the chain. */
+ apreq_filter_relocate(f);
/* We may have already prefetched some data, perhaps
* at the behest of an aaa handler, or during a speculative
@@ -277,6 +311,7 @@
}
+
static apr_status_t apreq_filter(ap_filter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
@@ -290,7 +325,7 @@
apr_status_t rv;
if (f->ctx == NULL)
- apreq_filter_init(f);
+ apreq_filter_make_context(f);
ctx = f->ctx;
@@ -436,3 +471,5 @@
NULL,
register_hooks, /* callback for registering hooks */
};
+
+/** @} */
1.4 +1 -3 httpd-apreq-2/glue/perl/Makefile.PL
Index: Makefile.PL
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/Makefile.PL,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Makefile.PL 10 Jun 2003 10:50:31 -0000 1.3
+++ Makefile.PL 15 Jun 2003 10:33:00 -0000 1.4
@@ -2,8 +2,6 @@
use 5.005;
-use lib qw(/home/joe/src/apache/httpd-test/perl-framework/Apache-Test/lib);
-
use Apache::Test5005compat;
use Apache::TestMM qw(test clean);
@@ -32,7 +30,7 @@
NAME => 'httpd-apreq-2',
VERSION => '0.01',
DIR => [qw(xs)],
- clean => { DIRS => "blib", FILES => "@scripts" },
+ clean => { DIRS => "blib", FILES => "t/TEST @scripts" },
);
__END__
1.4 +13 -8 httpd-apreq-2/glue/perl/README
Index: README
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/README,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- README 9 Jun 2003 04:00:45 -0000 1.3
+++ README 15 Jun 2003 10:33:00 -0000 1.4
@@ -1,14 +1,19 @@
+NOTES on xsbuilder/
+
+ maps/ - stores
+
+
current class diagram:
- apreq_env
+ apreq_xs_env
- / \
+ // \\
- fetch / \ new
+ fetch // \\ new
- / \
+ // \\
Apache::Cookie::Jar Apache::Request
@@ -21,10 +26,10 @@
Apache::Cookie
+legend: double lines ("//" or "\\") represent an inheritance relationship.
+ single lines ("/" or "\") represent method calls.
+
missing components: Apache::Request::Upload
Apache::Request::Parser
-
-
-Can/should we collapse Apache::Cookie::Jar & Apache::Cookie::Table
-into a single package?
+ Apache::Request::Util
1.9 +51 -8 httpd-apreq-2/glue/perl/xsbuilder/apreq_xs_postperl.h
Index: apreq_xs_postperl.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/apreq_xs_postperl.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- apreq_xs_postperl.h 10 Jun 2003 14:43:10 -0000 1.8
+++ apreq_xs_postperl.h 15 Jun 2003 10:33:00 -0000 1.9
@@ -1,7 +1,24 @@
#ifndef APREQ_XS_POSTPERL_H
#define APREQ_XS_POSTPERL_H
-
+/**
+ * @file apreq_xs_postperl.h
+ * @brief XS include file for making Cookie.so and Request.so
+ *
+ */
+/**
+ * @defgroup XS Perl
+ * @ingroup GLUE
+ * @{
+ */
+
+/**
+ * Trace through magic objects & hashrefs looking for original object.
+ * @param in The starting SV *.
+ * @param key The first letter of key is used to search a hashref for
+ * the desired object.
+ * @return The object, if found; otherwise NULL.
+ */
APR_INLINE
static SV *apreq_xs_find_obj(SV *in, const char *key)
{
@@ -36,6 +53,10 @@
/* conversion function templates based on modperl-2's sv2request_rec */
+/**
+ * Searches a perl object ref with apreq_xs_find_obj
+ * and produces a pointer to the object's C analog.
+ */
APR_INLINE
static void *apreq_xs_perl2c(SV* in, const char *name)
{
@@ -46,6 +67,10 @@
return (void *)SvIVX(sv);
}
+/**
+ * Searches a perl object ref with apreq_xs_find_obj
+ * and produces a pointer to the underlying C environment.
+ */
APR_INLINE
static void *apreq_xs_perl2env(SV *sv, const char *name)
{
@@ -56,6 +81,13 @@
return NULL;
}
+/**
+ * Converts a C object, with environment, to a Perl object.
+ * @param obj C object.
+ * @param env C environment.
+ * @param class Class perl object will be blessed into.
+ * @return Reference to the new Perl object in class.
+ */
APR_INLINE
static SV *apreq_xs_c2perl(pTHX_ void *obj, void *env, const char *class)
{
@@ -65,6 +97,13 @@
return rv;
}
+/**
+ * Converts a C object, with environment, to a TIEHASH object.
+ * @param obj C object.
+ * @param env C environment.
+ * @param class Class perl object will be blessed and tied to.
+ * @return Reference to a new TIEHASH object in class.
+ */
APR_INLINE
static SV *apreq_xs_table_c2perl(pTHX_ void *obj, void *env,
const char *class)
@@ -85,6 +124,9 @@
#define apreq_xs_sv2(type,sv)((apreq_##type##_t *)apreq_xs_perl2c(sv, #type))
#define apreq_xs_sv2env(type,sv) apreq_xs_perl2env(sv,#type)
+/** Converts apreq_env to a Perl package, which forms the
+ * base class for Apache::Request and Apache::Jar objects.
+ */
#define APREQ_XS_DEFINE_ENV(type) \
APR_INLINE \
static XS(apreq_xs_##type##_env) \
@@ -117,9 +159,9 @@
}
-/* requires type##2sv macro */
+/** requires type##2sv macro */
-#define APREQ_XS_DEFINE_OBJECT(type,class) \
+#define APREQ_XS_DEFINE_OBJECT(type) \
static XS(apreq_xs_##type) \
{ \
dXSARGS; \
@@ -135,13 +177,13 @@
data = (items == 3) ? SvPV_nolen(ST(2)) : NULL; \
obj = apreq_##type(env, data); \
\
- ST(0) = obj ? sv_2mortal(apreq_xs_2sv(obj,class)) : \
+ ST(0) = obj ? sv_2mortal( apreq_xs_2sv(obj, SvPV_nolen(ST(0))) ) : \
&PL_sv_undef; \
XSRETURN(1); \
}
-/* requires definition of apreq_xs_##type##2sv(t,class) macro */
+/** requires definition of apreq_xs_##type##2sv(t,class) macro */
#define APREQ_XS_DEFINE_MAKE(type) \
static XS(apreq_xs_make_##type) \
@@ -188,10 +230,12 @@
return 1;
}
-/* requires definition of type##2sv macro */
+
#define apreq_table_t apr_table_t
#define apreq_xs_table_sv2table(sv) apreq_xs_sv2(table,sv)
+/** requires definition of type##2sv macro */
+
#define APREQ_XS_DEFINE_GET(type, subtype, subclass) \
static int apreq_xs_##type##_table_values(void *data, const char *key, \
const char *val) \
@@ -209,7 +253,6 @@
PUTBACK; \
return 1; \
} \
- \
static XS(apreq_xs_##type##_table_get) \
{ \
dXSARGS; \
@@ -279,6 +322,6 @@
XSRETURN(1); \
}
-
+/** @} */
#endif /* APREQ_XS_POSTPERL_H */
1.6 +1 -1 httpd-apreq-2/glue/perl/xsbuilder/Apache/Cookie/Apache__Cookie.h
Index: Apache__Cookie.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Cookie/Apache__Cookie.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Apache__Cookie.h 10 Jun 2003 10:50:31 -0000 1.5
+++ Apache__Cookie.h 15 Jun 2003 10:33:00 -0000 1.6
@@ -11,7 +11,7 @@
/* jar */
-APREQ_XS_DEFINE_OBJECT(jar, "Apache::Cookie::Jar");
+APREQ_XS_DEFINE_OBJECT(jar);
APREQ_XS_DEFINE_TABLE(jar, cookies);
APREQ_XS_DEFINE_GET(jar, cookie, "Apache::Cookie");
1.6 +5 -2 httpd-apreq-2/glue/perl/xsbuilder/Apache/Cookie/Cookie_pm
Index: Cookie_pm
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Cookie/Cookie_pm,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Cookie_pm 10 Jun 2003 14:43:10 -0000 1.5
+++ Cookie_pm 15 Jun 2003 10:33:00 -0000 1.6
@@ -12,10 +12,13 @@
package Apache::Cookie;
-push our(@ISA), __PACKAGE__ -> env;
+#push our(@ISA), __PACKAGE__ -> env;
use Devel::Peek;
-sub status { ${$_[0]} + 0 }
+sub jar {
+ my $self = shift;
+ return Apache::Cookie::Jar->new(@_);
+}
sub new {
my ($class, $env, %attrs) = @_;
1.7 +1 -1 httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Apache__Request.h
Index: Apache__Request.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Apache__Request.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Apache__Request.h 10 Jun 2003 10:50:31 -0000 1.6
+++ Apache__Request.h 15 Jun 2003 10:33:00 -0000 1.7
@@ -17,7 +17,7 @@
}
APREQ_XS_DEFINE_ENV(request);
-APREQ_XS_DEFINE_OBJECT(request, "Apache::Request");
+APREQ_XS_DEFINE_OBJECT(request);
APREQ_XS_DEFINE_MAKE(param);
1.6 +2 -1 httpd-apreq-2/glue/perl/xsbuilder/maps/apreq_functions.map
Index: apreq_functions.map
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/maps/apreq_functions.map,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- apreq_functions.map 10 Jun 2003 10:50:31 -0000 1.5
+++ apreq_functions.map 15 Jun 2003 10:33:00 -0000 1.6
@@ -14,7 +14,7 @@
DEFINE_FETCH | apreq_xs_table_table_get |
MODULE=Apache::Cookie PACKAGE=Apache::Cookie
- DEFINE_jar | apreq_xs_jar |
+# DEFINE_jar | apreq_xs_jar |
DEFINE_as_string | apreq_xs_cookie_as_string |
DEFINE_make | apreq_xs_make_cookie |
DEFINE_expires | apreq_xs_cookie_expires |
@@ -26,6 +26,7 @@
apr_status_t:DEFINE_bake2| apreq_cookie_bake2(apreq_xs_sv2(cookie,c), apreq_xs_sv2env(cookie,c)) | SV *:c
MODULE=Apache::Cookie PACKAGE=Apache::Cookie::Jar PREFIX=Apache__Cookie__Jar_
+ DEFINE_new | apreq_xs_jar |
DEFINE_env | apreq_xs_jar_env |
DEFINE_get | apreq_xs_jar_table_get |
DEFINE_cookies | apreq_xs_jar_cookies |
1.21 +11 -1 httpd-apreq-2/src/apreq.h
Index: apreq.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- apreq.h 15 Jun 2003 05:25:37 -0000 1.20
+++ apreq.h 15 Jun 2003 10:33:01 -0000 1.21
@@ -66,6 +66,10 @@
extern "C" {
#endif
+/** @defgroup LIBRARY libapreq.so.2 */
+/** @defgroup MODULES Environments */
+/** @defgroup GLUE Language Bindings*/
+
/**
* @mainpage
* @verbinclude README
@@ -82,11 +86,15 @@
* @file apreq.h
* @brief Common functions, structures and macros.
*/
+/**
+ * @defgroup Utils Common functions, structures and macros
+ * @ingroup LIBRARY
+ * @{
+ */
/* XXX temporary workaround for Win32 */
#ifndef WIN32
-/** @def */
#define APREQ_DECLARE(d) APR_DECLARE(d)
#define APREQ_DECLARE_NONSTD(d) APR_DECLARE_NONSTD(d)
#else
@@ -312,6 +320,8 @@
*/
APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s);
+
+/** @} */
#ifdef __cplusplus
}
1.15 +6 -0 httpd-apreq-2/src/apreq_cookie.h
Index: apreq_cookie.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_cookie.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- apreq_cookie.h 15 Jun 2003 05:25:37 -0000 1.14
+++ apreq_cookie.h 15 Jun 2003 10:33:01 -0000 1.15
@@ -68,6 +68,11 @@
* @file apreq_cookie.h
* @brief Cookies and Jars.
*/
+/**
+ *@defgroup cookies Cookies (request and response)
+ *@ingroup LIBRARY
+ * @{
+ */
/** Cookie Jar */
typedef struct apreq_jar_t {
@@ -231,6 +236,7 @@
APREQ_DECLARE(apreq_cookie_version_t) apreq_ua_cookie_version(void *env);
+/** @} */
#ifdef __cplusplus
}
1.16 +6 -0 httpd-apreq-2/src/apreq_params.h
Index: apreq_params.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_params.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -r1.15 -r1.16
--- apreq_params.h 15 Jun 2003 05:25:37 -0000 1.15
+++ apreq_params.h 15 Jun 2003 10:33:01 -0000 1.16
@@ -71,6 +71,11 @@
* @file apreq_params.h
* @brief Request and param stuff.
*/
+/**
+ * @defgroup params Request params
+ * @ingroup LIBRARY
+ * @{
+ */
#define APREQ_CHARSET UTF_8;
@@ -176,6 +181,7 @@
APREQ_DECLARE(apr_status_t)apreq_parse_request(apreq_request_t *req,
apr_bucket_brigade *bb);
+/** @} */
#ifdef __cplusplus
}
#endif
1.13 +6 -0 httpd-apreq-2/src/apreq_parsers.h
Index: apreq_parsers.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- apreq_parsers.h 15 Jun 2003 05:25:37 -0000 1.12
+++ apreq_parsers.h 15 Jun 2003 10:33:01 -0000 1.13
@@ -16,6 +16,11 @@
* @file apreq_parsers.h
* @brief Parser and Hook stuff.
*/
+/**
+ * @defgroup parsers Parsers and Hooks
+ * @ingroup LIBRARY
+ * @{
+ */
/** Request config */
typedef struct apreq_cfg_t {
@@ -78,6 +83,7 @@
APREQ_DECLARE(apreq_parser_t *)apreq_parser(void *env, apreq_hook_t *hook);
+/** @} */
#ifdef __cplusplus
}
#endif