[zb4osgi-changeset] [scm] ZigBee 4 OSGi repository change: r598 - in /projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL: ./ shttpd/ shttpd/include/ shttpd/src/ tinyxml/

scm-notify at zb4osgi.aaloa.org scm-notify at zb4osgi.aaloa.org
Fri Jan 11 10:25:07 CET 2013


Author: andrea.ranalli
Date: Fri Jan 11 10:25:07 2013
New Revision: 598

Log:
Small changes to be fully compilable (in particular, added the whole shttpd project)

Added:
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/README
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h.1.37d
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/Makefile
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/auth.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/cgi.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/config.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/defs.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_cgi.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_dir.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_emb.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_file.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_socket.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssi.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssl.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/llist.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/log.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd   (with props)
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.1
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/ssl.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/standalone.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/std_includes.h
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/string.c
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/tinyxml.h
Modified:
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/README
    projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile.cross

Modified: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/README
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/README (original)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/README Fri Jan 11 10:25:07 2013
@@ -11,7 +11,6 @@
 The software uses the following open source software developed by 3rd parties:
 - libupnp (current release 1.6.15). This product uses software downloaded at Sourceforge (http://sourceforge.net/projects/pupnp/files/pupnp/libUPnP%201.6.15/libupnp-1.6.15.tar.bz2/download ) licensed under the BSD License.
 - curl (current release 7.27.0). This product uses software developed Sourceforge (http://curl.haxx.se/download/curl-7.27.0.tar.gz) licensed under the MIT License.
-- shttpd (release 1.42) This product uses software developed Sourceforge (http://sourceforge.net/projects/shttpd/files/shttpd/1.42/shttpd-1.42.tar.gz/download ) licensed under the Public Domain License. This project has been ported to a new project called mongoose (current release 3.1), licensed under the MIT License (but not used by GAL at the moment)
 - tinyxml (release 2.5.3). This product uses software developed at Sourceforge (http://sourceforge.net/projects/tinyxml/files/tinyxml/2.5.3/tinyxml_2_5_3.tar.gz/download )licensed under the zlib/libpng License.
 -	iniparser (release 3.1). This product uses software developed and licensed under the MIT License, freely downloadable at http://ndevilla.free.fr/iniparser/iniparser-3.1.tar.gz
 
@@ -21,6 +20,7 @@
 	- Apache License 2.0
 	- ZigBee Non-Member License
 
+Note: shttpd (release 1.42) is a software downloaded on 2008 from http://sourceforge.net/projects/shttpd/files/shttpd/1.42/shttpd-1.42.tar.gz/download and later on modified by Telecom Italia. The project has been ported to a new project called mongoose (current release 3.1), licensed under the MIT License (but not used by GAL at the moment). The owner of the original project, Sergey Lyubka, has copyrighted the code with "THE BEER-WARE LICENSE" (Revision 42): "Sergey Lyubka wrote this file.  As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return". based on this, the shttpd project modified by Telecom Italia can be distributed together with the GAL's source code.
 	
 *****************************
 ***** II - References *******
@@ -53,11 +53,10 @@
 3) Download the open source software developed by 3rd parties companies:
 - libupnp-1.6.15	- http://sourceforge.net/projects/pupnp/files/pupnp/libUPnP%201.6.15/libupnp-1.6.15.tar.bz2/download
 - curl-7.27.0 		- http://curl.haxx.se/download/curl-7.27.0.tar.gz
-- shttpd-1.42 		- http://sourceforge.net/projects/shttpd/files/shttpd/1.42/shttpd-1.42.tar.gz/download
 - tinyxml-2.5.3 	- http://sourceforge.net/projects/tinyxml/files/tinyxml/2.5.3/tinyxml_2_5_3.tar.gz/download
-- iniparser-3.1 	- http://ndevilla.free.fr/iniparser/iniparser-3.1.tar.gz
-
-4) Unpack each of the above files and put them into GAL's subfolders, according to their name. Please be aware to maintain the Makefile.cross file present in each of those subfolders. Also, just for the iniparser, be aware that the files dictionary.h and iniparser.h has been changed to support the cross compilation for the C++ environment. In particular, the following lines has been added at the beginning and at the end of each file:
+- iniparser-3.1 	- https://github.com/ndevilla/iniparser/archive/master.zip
+
+4) Unpack each of the above files and put them into GAL's subfolders, according to their name. Please be aware to maintain the Makefile.cross file present in each of those subfolders. For the tinyxml folder, please substitute also the makefile file. Finally, just for the iniparser, be aware that the files dictionary.h and iniparser.h has been changed to support the cross compilation for the C++ environment. In particular, the following lines has been added at the beginning and at the end of each file:
 
 	#ifdef __cplusplus
 	extern "C" {
@@ -76,6 +75,8 @@
 make -f Makefile.cross genmake
 cd ..
 make all
+(make distclean)
+(make all)
 
 The output generated by the previous commands is the gal file, present in linuxgal for debugging, and another gal present in [...]/fs/usr/ti/bin, that has been stripped and that shall be used as executable file for a trial. The macro called 'galfs' brings you where the files has been installed:
 bin -> exe gal

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/README
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/README (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/README Fri Jan 11 10:25:07 2013
@@ -1,0 +1,21 @@
+SHTTPD is small, fast and easy to use web server. It supports CGI, SSL,
+Digest Authorization. The unique feature of SHTTPD is the ability to
+embed it into existing C/C++ applications. Embedded API is very clean
+and simple. SHTTPD has small memory footprint. Use it when other
+web servers like Apache are too heavy for your tasks.
+
+WWW:    http://shttpd.sourceforge.net
+
+
+
+Changelog
+
+Version 1.42b 
+
+- Added shttpd_unregister_uri to remove an existing URI from the related list.
+int shttpd_unregister_uri(struct shttpd_ctx *ctx, const char *uri);	
+
+- Added shttpd_get_option to read SHTTPD options current values
+const char *shttpd_get_option(struct shttpd_ctx *ctx, const char *opt);
+
+- Makefile modified to compile the project in Cygwin environment

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,113 @@
+/*
+ * Copyright (c) 2004-2008 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ *
+ * $Id: shttpd.h,v 1.18 2008/08/23 08:34:50 drozd Exp $
+ */
+
+#ifndef SHTTPD_HEADER_INCLUDED
+#define	SHTTPD_HEADER_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct ubuf {
+	char		*buf;		/* Buffer pointer		*/
+	int		len;		/* Size of a buffer		*/
+	int		num_bytes;	/* Bytes processed by callback	*/
+};
+
+/*
+ * This structure is passed to the user callback function
+ */
+struct shttpd_arg {
+	void		*priv;		/* Private! Do not touch!	*/
+	void		*state;		/* User state			*/
+	void		*user_data;	/* Data from register_uri()	*/
+	struct ubuf	in;		/* Input is here, POST data	*/
+	struct ubuf	out;		/* Output goes here		*/
+
+	unsigned int	flags;
+#define	SHTTPD_END_OF_OUTPUT	1	/* No more data do send		*/
+#define	SHTTPD_CONNECTION_ERROR	2	/* Server closed the connection	*/
+#define	SHTTPD_MORE_POST_DATA	4	/* arg->in has incomplete data	*/
+#define	SHTTPD_POST_BUFFER_FULL	8	/* arg->in has max data		*/
+#define	SHTTPD_SSI_EVAL_TRUE	16	/* SSI eval callback must set it*/
+#define	SHTTPD_SUSPEND		32	/* User wants to suspend output	*/
+};
+
+/*
+ * User callback function. Called when certain registered URLs have been
+ * requested. These are the requirements to the callback function:
+ *
+ * 1. It must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
+ *	and record how many bytes are copied, into 'out.num_bytes'
+ * 2. It must not call any blocking functions
+ * 3. It must set SHTTPD_END_OF_OUTPUT flag when there is no more data to send
+ * 4. For POST requests, it must process the incoming data (in.buf) of length
+ *	'in.len', and set 'in.num_bytes', which is how many bytes of POST
+ *	data was processed and can be discarded by SHTTPD.
+ * 5. If callback allocates arg->state, to keep state, it must deallocate it
+ *    at the end of coonection SHTTPD_CONNECTION_ERROR or SHTTPD_END_OF_OUTPUT
+ * 6. If callback function wants to suspend until some event, it must store
+ *	arg->priv pointer elsewhere, set SHTTPD_SUSPEND flag and return. When
+ *	the event happens, user code should call shttpd_wakeup(priv).
+ *	It is safe to call shttpd_wakeup() from any thread. User code must
+ *	not call shttpd_wakeup once the connection is closed.
+ */
+typedef void (*shttpd_callback_t)(struct shttpd_arg *);
+
+/*
+ * shttpd_init		Initialize shttpd context
+ * shttpd_fini		Dealocate the context, close all connections
+ * shttpd_set_option	Set new value for option
+ * shttpd_register_uri	Setup the callback function for specified URL
+ * shttpd_poll		Do connections processing
+ * shttpd_version	return string with SHTTPD version
+ * shttpd_get_var	Fetch POST/GET variable value by name. Return value len
+ * shttpd_get_header	return value of the specified HTTP header
+ * shttpd_get_env	return values for the following	pseudo-variables:
+ 			"REQUEST_METHOD", "REQUEST_URI",
+ *			"REMOTE_USER" and "REMOTE_ADDR"
+ * shttpd_printf	helper function to output data
+ * shttpd_handle_error	register custom HTTP error handler
+ * shttpd_wakeup	clear SHTTPD_SUSPEND state for the connection
+ */
+
+struct shttpd_ctx;
+
+struct shttpd_ctx *shttpd_init(int argc, char *argv[]);
+int shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val);
+const char *shttpd_get_option(struct shttpd_ctx *ctx, const char *opt);			//@@	Add
+void shttpd_fini(struct shttpd_ctx *);
+void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri,
+		shttpd_callback_t callback, void *const user_data);
+int shttpd_unregister_uri(struct shttpd_ctx *ctx, const char *uri);			//@@	Add
+void shttpd_poll(struct shttpd_ctx *, int milliseconds);
+const char *shttpd_version(void);
+int shttpd_get_var(const char *var, const char *buf, int buf_len,
+		char *value, int value_len);
+const char *shttpd_get_header(struct shttpd_arg *, const char *header_name);
+const char *shttpd_get_env(struct shttpd_arg *, const char *name);
+void shttpd_get_http_version(struct shttpd_arg *,
+		unsigned long *major, unsigned long *minor);
+size_t shttpd_printf(struct shttpd_arg *, const char *fmt, ...);
+void shttpd_handle_error(struct shttpd_ctx *ctx, int status,
+		shttpd_callback_t func, void *const data);
+void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
+		shttpd_callback_t func, void *const user_data);
+void shttpd_wakeup(const void *priv);
+int shttpd_join(struct shttpd_ctx *, fd_set *, fd_set *, int *max_fd);
+int  shttpd_socketpair(int sp[2]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SHTTPD_HEADER_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h.1.37d
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h.1.37d (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/include/shttpd.h.1.37d Fri Jan 11 10:25:07 2013
@@ -1,0 +1,134 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * $Id: shttpd.h,v 1.1.1.1 2007/08/01 07:53:05 claudio Exp $
+ */
+
+#ifndef SHTTPD_HEADER_INCLUDED
+#define	SHTTPD_HEADER_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * This structure is passed to the user callback function
+ */
+struct shttpd_arg {
+	void		*priv;		/* Private! Do not touch!	*/
+	void		*state;		/* User state			*/
+	void		*user_data;	/* User-defined data		*/
+
+	struct {
+		char	*buf;		/* Buffer pointer		*/
+		int	len;		/* Size of a buffer		*/
+		int	num_bytes;	/* Bytes processed by callback	*/
+	} in, out;	/* POST data buffer (in) and output buffer (out) */
+
+	unsigned int	flags;
+#define	SHTTPD_END_OF_OUTPUT	1
+#define	SHTTPD_CONNECTION_ERROR	2
+#define	SHTTPD_MORE_POST_DATA	4
+#define	SHTTPD_POST_BUFFER_FULL	8
+};
+
+/*
+ * User callback function. Called when certain registered URLs have been
+ * requested. These are the requirements to the callback function:
+ *
+ * 1. it must copy data into 'out_buf', not more than 'out_buf_max_len' bytes,
+ *	and record how many bytes are copied, into 'out_buf_written_len'
+ * 2. it must not block the execution
+ * 3. it must set 'last' in shttpd_arg to 1 if there is no more data
+ * 4. for POST requests, it must process the incoming data (in_buf), and
+ *	set 'in_buf_read_len', which is how many bytes of POST data is read
+ *	and can be discarded by SHTTPD.
+ */
+typedef void (*shttpd_callback_t)(struct shttpd_arg *);
+
+/*
+ * shttpd_init		Initialize shttpd context. Parameters: configuration
+ *			file name (may be NULL), then NULL-terminated
+ *			sequence of pairs "option_name", "option_value".
+ * shttpd_init2		Same as shttpd_init, but the list of option/value
+ *			pairs is passed in arrays
+ * shttpd_fini		Dealocate the context
+ * shttpd_register_uri	Setup the callback function for specified URL.
+ * shttpd_protect_uri	Associate authorization file with an URL.
+ * shttpd_add_mime_type	Add mime type
+ * shtppd_listen	Setup a listening socket in the SHTTPD context
+ * shttpd_poll		Do connections processing
+ * shttpd_version	return string with SHTTPD version
+ * shttpd_get_var	Return POST/GET variable value for given variable name.
+ * shttpd_get_header	return value of the specified HTTP header
+ * shttpd_get_env	return string values for the following
+ *			pseudo-variables: "REQUEST_METHOD", "REQUEST_URI",
+ *			"REMOTE_USER" and "REMOTE_ADDR".
+ */
+
+struct shttpd_ctx;
+
+struct shttpd_ctx *shttpd_init(const char *config_file, ...);
+struct shttpd_ctx *shttpd_init2(const char *config_file,
+		char *names[], char *values[], size_t num_options);
+void shttpd_fini(struct shttpd_ctx *);
+void shttpd_add_mime_type(struct shttpd_ctx *,
+		const char *ext, const char *mime);
+int shttpd_listen(struct shttpd_ctx *ctx, int port);
+void shttpd_register_uri(struct shttpd_ctx *ctx,
+		const char *uri, shttpd_callback_t callback, void *user_data);
+
+//@add(29 June 2007)@
+int shttpd_unregister_uri(struct shttpd_ctx *ctx, const char *uri);
+
+
+void shttpd_protect_uri(struct shttpd_ctx *ctx,
+		const char *uri, const char *file);
+void shttpd_poll(struct shttpd_ctx *, int milliseconds);
+const char *shttpd_version(void);
+int shttpd_get_var(const char *var, const char *buf, int buf_len,
+		char *value, int value_len);
+const char *shttpd_get_header(struct shttpd_arg *, const char *);
+const char *shttpd_get_env(struct shttpd_arg *, const char *);
+void shttpd_get_http_version(struct shttpd_arg *,
+		unsigned long *major, unsigned long *minor);
+size_t shttpd_printf(struct shttpd_arg *, const char *fmt, ...);
+void shttpd_handle_error(struct shttpd_ctx *ctx, int status,
+		shttpd_callback_t func, void *data);
+
+/*
+ * The following three functions are for applications that need to
+ * load-balance the connections on their own. Many threads may be spawned
+ * with one SHTTPD context per thread. Boss thread may only wait for
+ * new connections by means of shttpd_accept(). Then it may scan thread
+ * pool for the idle thread by means of shttpd_active(), and add new
+ * connection to the context by means of shttpd_add().
+ */
+void shttpd_add_socket(struct shttpd_ctx *, int sock);
+int shttpd_accept(int lsn_sock, int milliseconds);
+int shttpd_active(struct shttpd_ctx *);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SHTTPD_HEADER_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/Makefile
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/Makefile (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/Makefile Fri Jan 11 10:25:07 2013
@@ -1,0 +1,88 @@
+SRCS=		string.c shttpd.c log.c auth.c md5.c cgi.c io_ssi.c \
+		io_file.c io_socket.c io_ssl.c io_emb.c io_dir.c io_cgi.c
+HDRS=		defs.h llist.h shttpd.h std_includes.h io.h md5.h ssl.h \
+		compat_unix.h compat_win32.h compat_rtems.h config.h
+OBJS=		$(SRCS:%.c=%.o) compat_unix.c
+PROG=		shttpd
+CL_FLAGS=	/MD /TC /nologo /DNDEBUG /Os 	# MSVC compiler flags
+
+
+REF_SSL_VER = 0.9.8
+
+ifdef SSL_VER
+	CFLAGS += -D CYGWIN
+	ifeq ($(SSL_VER), $(REF_SSL_VER))
+		CFLAGS += -D SSL_0_9_8
+	endif
+endif
+				
+
+# Possible flags: (in brackets are rough numbers for 'gcc -O2' on i386)
+# -DHAVE_MD5		- use system md5 library (-2kb)
+# -DNDEBUG		- strip off all debug code (-5kb)
+# -D_DEBUG		- build debug version (very noisy) (+6kb)
+# -DNO_CGI		- disable CGI support (-5kb)
+# -DNO_SSL		- disable SSL functionality (-2kb)
+# -DNO_AUTH		- disable authorization support (-4kb)
+# -DCONFIG=\"file\"	- use `file' as the default config file
+# -DNO_SSI		- disable SSI support (-4kb)
+# -DNO_THREADS		- disable threads support (?)
+
+# XXX Note for the windows users. In order to build shttpd, MSVS6 is needed.
+# Follow these steps:
+# 1. Add c:\path_to_msvs6\bin to the system Path environment variable.
+# 2. Add two new system environment variables:
+#    LIB=c:\path_to_msvs6\lib
+#    INCLUDE=c:\path_to_msvs6\include
+# 3. start console, go to shttpd-VERSION\src\ directory
+# 4. type "nmake msvc"
+# 5. go to shttpd-VERSION\examples , type "nmake msvc"
+
+
+all:
+	@echo "make (unix|cygwin|msvc|mingw|rtems)"
+	@echo 'Linux: "LIBS=-ldl make unix"'
+	@echo 'Cygwin: "SSL_VER=0.9.8 make cygwin" / "SSL_VER=0.9.7 make cygwin"'
+	@echo 'BSD: "LIBS=-lpthread make unix"'
+	@echo 'Solaris: "LIBS="-lpthread -lnsl -lsocket" make unix"'
+
+.c.o:
+	$(CC) -c $(CFLAGS) $< -o $@
+
+lib$(PROG).a: $(OBJS) compat_unix.o
+	$(AR) -r lib$(PROG).a $(OBJS) compat_unix.o 2>&1
+	ranlib lib$(PROG).a 2>&1
+
+unix: lib$(PROG).a
+	$(CC) $(CFLAGS) standalone.c -o $(PROG) $(LIBS) -L. -l$(PROG) -lpthread -ldl
+#	$(CC) $(CFLAGS) standalone.c -o $(PROG) $(LIBS) -L. -l$(PROG)
+#$(CC) $(CFLAGS) -fpic $(SRCS) compat_unix.c -shared -o lib$(PROG).so
+
+cygwin: lib$(PROG).a
+	$(CC) $(CFLAGS) standalone.c -o $(PROG) $(LIBS) -L. -l$(PROG) -lpthread -ldl 
+
+rtems:
+	$(CC) -c $(CFLAGS) $(SRCS) compat_rtems.c
+	$(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a 
+
+$(PROG).lib: $(SRCS) $(HDRS) compat_win32.c
+	del *.obj
+	cl /c $(CL_FLAGS) compat_win32.c $(SRCS)
+	lib /nologo *.obj /out:$@
+
+msvc:	$(PROG).lib
+	cl $(CL_FLAGS) standalone.c /link /out:$(PROG).exe \
+	ws2_32.lib user32.lib advapi32.lib shell32.lib $(PROG).lib
+
+mingw:
+	$(CC) -c $(CFLAGS) $(SRCS) compat_win32.c
+	$(AR) -r lib$(PROG).a *.o && ranlib lib$(PROG).a 
+	$(CC) $(CFLAGS) $(SRCS) compat_win32.c standalone.c \
+		-o $(PROG) $(LIBS) -lws2_32 -lcomdlg32 -lcomctl32
+
+man:
+	cat shttpd.1 | tbl | groff -man -Tascii | col -b > shttpd.1.txt
+	cat shttpd.1 | tbl | groff -man -Tascii | less
+
+clean:
+	rm -rf *.o *.core *.exe $(PROG) lib$(PROG).a *.lib *.obj

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/auth.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/auth.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/auth.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,419 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+#if !defined(NO_AUTH)
+/*
+ * Stringify binary data. Output buffer must be twice as big as input,
+ * because each byte takes 2 bytes in string representation
+ */
+static void
+bin2str(char *to, const unsigned char *p, size_t len)
+{
+	const char	*hex = "0123456789abcdef";
+
+	for (;len--; p++) {
+		*to++ = hex[p[0] >> 4];
+		*to++ = hex[p[0] & 0x0f];
+	}
+}
+
+/*
+ * Return stringified MD5 hash for list of vectors.
+ * buf must point to at least 32-bytes long buffer
+ */
+static void
+md5(char *buf, ...)
+{
+	unsigned char	hash[16];
+	const struct vec *v;
+	va_list		ap;
+	MD5_CTX	ctx;
+	int		i;
+
+	MD5Init(&ctx);
+
+	va_start(ap, buf);
+	for (i = 0; (v = va_arg(ap, const struct vec *)) != NULL; i++) {
+		assert(v->len >= 0);
+		if (v->len == 0)
+			continue;
+		if (i > 0)
+			MD5Update(&ctx, (unsigned char *) ":", 1);
+		MD5Update(&ctx,(unsigned char *)v->ptr,(unsigned int)v->len);
+	}
+	va_end(ap);
+
+	MD5Final(hash, &ctx);
+	bin2str(buf, hash, sizeof(hash));
+}
+
+/*
+ * Compare to vectors. Return 1 if they are equal
+ */
+static int
+vcmp(const struct vec *v1, const struct vec *v2)
+{
+	return (v1->len == v2->len && !memcmp(v1->ptr, v2->ptr, v1->len));
+}
+
+struct digest {
+	struct vec	user;
+	struct vec	uri;
+	struct vec	nonce;
+	struct vec	cnonce;
+	struct vec	resp;
+	struct vec	qop;
+	struct vec	nc;
+};
+
+static const struct auth_keyword {
+	size_t		offset;
+	struct vec	vec;
+} known_auth_keywords[] = {
+	{offsetof(struct digest, user),		{"username=",	9}},
+	{offsetof(struct digest, cnonce),	{"cnonce=",	7}},
+	{offsetof(struct digest, resp),		{"response=",	9}},
+	{offsetof(struct digest, uri),		{"uri=",	4}},
+	{offsetof(struct digest, qop),		{"qop=",	4}},
+	{offsetof(struct digest, nc),		{"nc=",		3}},
+	{offsetof(struct digest, nonce),	{"nonce=",	6}},
+	{0,					{NULL,		0}}
+};
+
+static void
+parse_authorization_header(const struct vec *h, struct digest *dig)
+{
+	const unsigned char	*p, *e, *s;
+	struct vec		*v, vec;
+	const struct auth_keyword *kw;
+
+	(void) memset(dig, 0, sizeof(*dig));
+	p = (unsigned char *) h->ptr + 7;
+	e = (unsigned char *) h->ptr + h->len;
+
+	while (p < e) {
+
+		/* Skip spaces */
+		while (p < e && (*p == ' ' || *p == ','))
+			p++;
+
+		/* Skip to "=" */
+		for (s = p; s < e && *s != '='; )
+			s++;
+		s++;
+
+		/* Is it known keyword ? */
+		for (kw = known_auth_keywords; kw->vec.len > 0; kw++)
+			if (kw->vec.len <= s - p &&
+			    !memcmp(p, kw->vec.ptr, kw->vec.len))
+				break;
+
+		if (kw->vec.len == 0)
+			v = &vec;		/* Dummy placeholder	*/
+		else
+			v = (struct vec *) ((char *) dig + kw->offset);
+
+		if (*s == '"') {
+			p = ++s;
+			while (p < e && *p != '"')
+				p++;
+		} else {
+			p = s;
+			while (p < e && *p != ' ' && *p != ',')
+				p++;
+		}
+
+		v->ptr = (char *) s;
+		v->len = p - s;
+
+		if (*p == '"')
+			p++;
+
+		DBG(("auth field [%.*s]", v->len, v->ptr));
+	}
+}
+
+/*
+ * Check the user's password, return 1 if OK
+ */
+static int
+check_password(int method, const struct vec *ha1, const struct digest *digest)
+{
+	char		a2[32], resp[32];
+	struct vec	vec_a2;
+
+	/* XXX  Due to a bug in MSIE, we do not compare the URI	 */
+	/* Also, we do not check for authentication timeout */
+	if (/*strcmp(dig->uri, c->ouri) != 0 || */
+	    digest->resp.len != 32 /*||
+	    now - strtoul(dig->nonce, NULL, 10) > 3600 */)
+		return (0);
+
+	md5(a2, &_shttpd_known_http_methods[method], &digest->uri, NULL);
+	vec_a2.ptr = a2;
+	vec_a2.len = sizeof(a2);
+	md5(resp, ha1, &digest->nonce, &digest->nc,
+	    &digest->cnonce, &digest->qop, &vec_a2, NULL);
+	DBG(("%s: uri [%.*s] expected_resp [%.*s] resp [%.*s]",
+	    "check_password", digest->uri.len, digest->uri.ptr,
+	    32, resp, digest->resp.len, digest->resp.ptr));
+
+	return (!memcmp(resp, digest->resp.ptr, 32));
+}
+
+static FILE *
+open_auth_file(struct shttpd_ctx *ctx, const char *path)
+{
+	char 		name[FILENAME_MAX];
+	const char	*p, *e;
+	FILE		*fp = NULL;
+	int		fd;
+
+	if (ctx->options[OPT_AUTH_GPASSWD] != NULL) {
+		/* Use global passwords file */
+		_shttpd_snprintf(name, sizeof(name), "%s",
+		    ctx->options[OPT_AUTH_GPASSWD]);
+	} else {
+		/*
+		 * Try to find .htpasswd in requested directory.
+		 * Given the path, create the path to .htpasswd file
+		 * in the same directory. Find the right-most
+		 * directory separator character first. That would be the
+		 * directory name. If directory separator character is not
+		 * found, 'e' will point to 'p'.
+		 */
+		for (p = path, e = p + strlen(p) - 1; e > p; e--)
+			if (IS_DIRSEP_CHAR(*e))
+				break;
+
+		/*
+		 * Make up the path by concatenating directory name and
+		 * .htpasswd file name.
+		 */
+		(void) _shttpd_snprintf(name, sizeof(name), "%.*s/%s",
+		    (int) (e - p), p, HTPASSWD);
+	}
+
+	if ((fd = _shttpd_open(name, O_RDONLY, 0)) == -1) {
+		DBG(("open_auth_file: open(%s)", name));
+	} else if ((fp = fdopen(fd, "r")) == NULL) {
+		DBG(("open_auth_file: fdopen(%s)", name));
+		(void) close(fd);
+	}
+
+	return (fp);
+}
+
+/*
+ * Parse the line from htpasswd file. Line should be in form of
+ * "user:domain:ha1". Fill in the vector values. Return 1 if successful.
+ */
+static int
+parse_htpasswd_line(const char *s, struct vec *user,
+				struct vec *domain, struct vec *ha1)
+{
+	user->len = domain->len = ha1->len = 0;
+
+	for (user->ptr = s; *s != '\0' && *s != ':'; s++, user->len++);
+	if (*s++ != ':')
+		return (0);
+
+	for (domain->ptr = s; *s != '\0' && *s != ':'; s++, domain->len++);
+	if (*s++ != ':')
+		return (0);
+
+	for (ha1->ptr = s; *s != '\0' && !isspace(* (unsigned char *) s);
+	    s++, ha1->len++);
+
+	DBG(("parse_htpasswd_line: [%.*s] [%.*s] [%.*s]", user->len, user->ptr,
+	    domain->len, domain->ptr, ha1->len, ha1->ptr));
+
+	return (user->len > 0 && domain->len > 0 && ha1->len > 0);
+}
+
+/*
+ * Authorize against the opened passwords file. Return 1 if authorized.
+ */
+static int
+authorize(struct conn *c, FILE *fp)
+{
+	struct vec 	*auth_vec = &c->ch.auth.v_vec;
+	struct vec	*user_vec = &c->ch.user.v_vec;
+	struct vec	user, domain, ha1;
+	struct digest	digest;
+	int		ok = 0;
+	char		line[256];
+
+	if (auth_vec->len > 20 &&
+	    !_shttpd_strncasecmp(auth_vec->ptr, "Digest ", 7)) {
+
+		parse_authorization_header(auth_vec, &digest);
+		*user_vec = digest.user;
+
+		while (fgets(line, sizeof(line), fp) != NULL) {
+
+			if (!parse_htpasswd_line(line, &user, &domain, &ha1))
+				continue;
+
+			DBG(("[%.*s] [%.*s] [%.*s]", user.len, user.ptr,
+			    domain.len, domain.ptr, ha1.len, ha1.ptr));
+
+			if (vcmp(user_vec, &user) &&
+			    !memcmp(c->ctx->options[OPT_AUTH_REALM],
+			    domain.ptr, domain.len)) {
+				ok = check_password(c->method, &ha1, &digest);
+				break;
+			}
+		}
+	}
+
+	return (ok);
+}
+
+int
+_shttpd_check_authorization(struct conn *c, const char *path)
+{
+	FILE		*fp = NULL;
+	int		len, n, authorized = 1;
+	const char	*p, *s = c->ctx->options[OPT_PROTECT];
+	char		protected_path[FILENAME_MAX];
+
+	FOR_EACH_WORD_IN_LIST(s, len) {
+
+		if ((p = memchr(s, '=', len)) == NULL || p >= s + len || p == s)
+			continue;
+
+		if (!memcmp(c->uri, s, p - s)) {
+			
+			n = s + len - p;
+			if (n > (int) sizeof(protected_path) - 1)
+				n = sizeof(protected_path) - 1;
+
+			_shttpd_strlcpy(protected_path, p + 1, n);
+
+			if ((fp = fopen(protected_path, "r")) == NULL)
+				_shttpd_elog(E_LOG, c,
+				    "check_auth: cannot open %s: %s",
+				    protected_path, strerror(errno));
+			break;
+		}
+	}
+
+	if (fp == NULL)
+		fp = open_auth_file(c->ctx, path);
+
+	if (fp != NULL) {
+		authorized = authorize(c, fp);
+		(void) fclose(fp);
+	}
+
+	return (authorized);
+}
+
+int
+_shttpd_is_authorized_for_put(struct conn *c)
+{
+	FILE	*fp;
+	int	ret = 0;
+
+	if ((fp = fopen(c->ctx->options[OPT_AUTH_PUT], "r")) != NULL) {
+		ret = authorize(c, fp);
+		(void) fclose(fp);
+	}
+
+	return (ret);
+}
+
+void
+_shttpd_send_authorization_request(struct conn *c)
+{
+	char	buf[512];
+
+	(void) _shttpd_snprintf(buf, sizeof(buf), "Unauthorized\r\n"
+	    "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
+	    "nonce=\"%lu\"", c->ctx->options[OPT_AUTH_REALM],
+	    (unsigned long) _shttpd_current_time);
+
+	_shttpd_send_server_error(c, 401, buf);
+}
+
+/*
+ * Edit the passwords file.
+ */
+int
+_shttpd_edit_passwords(const char *fname, const char *domain,
+		const char *user, const char *pass)
+{
+	int		ret = EXIT_SUCCESS, found = 0;
+	struct vec	u, d, p;
+	char		line[512], tmp[FILENAME_MAX], ha1[32];
+	FILE		*fp = NULL, *fp2 = NULL;
+
+	(void) _shttpd_snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
+
+	/* Create the file if does not exist */
+	if ((fp = fopen(fname, "a+")))
+		(void) fclose(fp);
+
+	/* Open the given file and temporary file */
+	if ((fp = fopen(fname, "r")) == NULL)
+		_shttpd_elog(E_FATAL, NULL,
+		    "Cannot open %s: %s", fname, strerror(errno));
+	else if ((fp2 = fopen(tmp, "w+")) == NULL)
+		_shttpd_elog(E_FATAL, NULL,
+		    "Cannot open %s: %s", tmp, strerror(errno));
+
+	p.ptr = pass;
+	p.len = strlen(pass);
+
+	/* Copy the stuff to temporary file */
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		u.ptr = line;
+		if ((d.ptr = strchr(line, ':')) == NULL)
+			continue;
+		u.len = d.ptr - u.ptr;
+		d.ptr++;
+		if (strchr(d.ptr, ':') == NULL)
+			continue;
+		d.len = strchr(d.ptr, ':') - d.ptr;
+
+		if ((int) strlen(user) == u.len &&
+		    !memcmp(user, u.ptr, u.len) &&
+		    (int) strlen(domain) == d.len &&
+		    !memcmp(domain, d.ptr, d.len)) {
+			found++;
+			md5(ha1, &u, &d, &p, NULL);
+			(void) fprintf(fp2, "%s:%s:%.32s\n", user, domain, ha1);
+		} else {
+			(void) fprintf(fp2, "%s", line);
+		}
+	}
+
+	/* If new user, just add it */
+	if (found == 0) {
+		u.ptr = user; u.len = strlen(user);
+		d.ptr = domain; d.len = strlen(domain);
+		md5(ha1, &u, &d, &p, NULL);
+		(void) fprintf(fp2, "%s:%s:%.32s\n", user, domain, ha1);
+	}
+
+	/* Close files */
+	(void) fclose(fp);
+	(void) fclose(fp2);
+
+	/* Put the temp file in place of real file */
+	(void) _shttpd_remove(fname);
+	(void) _shttpd_rename(tmp, fname);
+
+	return (ret);
+}
+#endif /* NO_AUTH */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/cgi.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/cgi.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/cgi.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,229 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+#if !defined(NO_CGI)
+struct env_block {
+	char	buf[ENV_MAX];		/* Environment buffer		*/
+	int	len;			/* Space taken			*/
+	char	*vars[CGI_ENV_VARS];	/* Point into the buffer	*/
+	int	nvars;			/* Number of variables		*/
+};
+
+static void
+addenv(struct env_block *block, const char *fmt, ...)
+{
+	int	n, space;
+	va_list	ap;
+
+	space = sizeof(block->buf) - block->len - 2;
+	assert(space >= 0);
+
+	va_start(ap, fmt);
+	n = vsnprintf(block->buf + block->len, space, fmt, ap);
+	va_end(ap);
+
+	if (n > 0 && n < space && block->nvars < CGI_ENV_VARS - 2) {
+		block->vars[block->nvars++] = block->buf + block->len;
+		block->len += n + 1;	/* Include \0 terminator */
+	}
+}
+
+static void
+add_http_headers_to_env(struct env_block *b, const char *s, int len)
+{
+	const char	*p, *v, *e = s + len;
+	int		space, n, i, ch;
+
+	/* Loop through all headers in the request */
+	while (s < e) {
+
+		/* Find where this header ends. Remember where value starts */
+		for (p = s, v = NULL; p < e && *p != '\n'; p++)
+			if (v == NULL && *p == ':') 
+				v = p;
+
+		/* 2 null terminators and "HTTP_" */
+		space = (sizeof(b->buf) - b->len) - (2 + 5);
+		assert(space >= 0);
+	
+		/* Copy header if enough space in the environment block */
+		if (v > s && p > v + 2 && space > p - s) {
+
+			/* Store var */
+			if (b->nvars < (int) NELEMS(b->vars) - 1)
+				b->vars[b->nvars++] = b->buf + b->len;
+
+			(void) memcpy(b->buf + b->len, "HTTP_", 5);
+			b->len += 5;
+
+			/* Copy header name. Substitute '-' to '_' */
+			n = v - s;
+			for (i = 0; i < n; i++) {
+				ch = s[i] == '-' ? '_' : s[i];
+				b->buf[b->len++] = toupper(ch);
+			}
+
+			b->buf[b->len++] = '=';
+
+			/* Copy header value */
+			v += 2;
+			n = p[-1] == '\r' ? (p - v) - 1 : p - v;
+			for (i = 0; i < n; i++)
+				b->buf[b->len++] = v[i];
+
+			/* Null-terminate */
+			b->buf[b->len++] = '\0';
+		}
+
+		s = p + 1;	/* Shift to the next header */
+	}
+}
+
+static void
+prepare_environment(const struct conn *c, const char *prog,
+		struct env_block *blk)
+{
+	const struct headers	*h = &c->ch;
+	const char		*s, *fname, *root = c->ctx->options[OPT_ROOT];
+	size_t			len;
+
+	blk->len = blk->nvars = 0;
+
+	/* SCRIPT_FILENAME */
+	fname = prog;
+	if ((s = strrchr(prog, '/')))
+		fname = s + 1;
+
+	/* Prepare the environment block */
+	addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
+	addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
+	addenv(blk, "%s", "REDIRECT_STATUS=200");	/* PHP */
+	addenv(blk, "SERVER_PORT=%d", c->loc_port);
+	addenv(blk, "SERVER_NAME=%s", c->ctx->options[OPT_AUTH_REALM]);
+	addenv(blk, "SERVER_ROOT=%s", root);
+	addenv(blk, "DOCUMENT_ROOT=%s", root);
+	addenv(blk, "REQUEST_METHOD=%s",
+			_shttpd_known_http_methods[c->method].ptr);
+	addenv(blk, "REMOTE_ADDR=%s", inet_ntoa(c->sa.u.sin.sin_addr));
+	addenv(blk, "REMOTE_PORT=%hu", ntohs(c->sa.u.sin.sin_port));
+	addenv(blk, "REQUEST_URI=%s", c->uri);
+	addenv(blk, "SCRIPT_NAME=%s", prog + strlen(root));
+	addenv(blk, "SCRIPT_FILENAME=%s", fname);	/* PHP */
+	addenv(blk, "PATH_TRANSLATED=%s", prog);
+
+	if (h->ct.v_vec.len > 0)
+		addenv(blk, "CONTENT_TYPE=%.*s", 
+		    h->ct.v_vec.len, h->ct.v_vec.ptr);
+
+	if (c->query != NULL)
+		addenv(blk, "QUERY_STRING=%s", c->query);
+
+	if (c->path_info != NULL)
+		addenv(blk, "PATH_INFO=/%s", c->path_info);
+
+	if (h->cl.v_big_int > 0)
+		addenv(blk, "CONTENT_LENGTH=%lu", h->cl.v_big_int);
+
+	if ((s = getenv("PATH")) != NULL)
+		addenv(blk, "PATH=%s", s);
+
+#ifdef _WIN32
+	if ((s = getenv("COMSPEC")) != NULL)
+		addenv(blk, "COMSPEC=%s", s);
+	if ((s = getenv("SYSTEMROOT")) != NULL)
+		addenv(blk, "SYSTEMROOT=%s", s);
+#else
+	if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
+		addenv(blk, "LD_LIBRARY_PATH=%s", s);
+#endif /* _WIN32 */
+
+	if ((s = getenv("PERLLIB")) != NULL)
+		addenv(blk, "PERLLIB=%s", s);
+
+	if (h->user.v_vec.len > 0) {
+		addenv(blk, "REMOTE_USER=%.*s",
+		    h->user.v_vec.len, h->user.v_vec.ptr);
+		addenv(blk, "%s", "AUTH_TYPE=Digest");
+	}
+
+	/* Add user-specified variables */
+	s = c->ctx->options[OPT_CGI_ENVIRONMENT];
+	FOR_EACH_WORD_IN_LIST(s, len)
+		addenv(blk, "%.*s", len, s);
+
+	/* Add all headers as HTTP_* variables */
+	add_http_headers_to_env(blk, c->headers,
+	    c->rem.headers_len - (c->headers - c->request));
+
+	blk->vars[blk->nvars++] = NULL;
+	blk->buf[blk->len++] = '\0';
+
+	assert(blk->nvars < CGI_ENV_VARS);
+	assert(blk->len > 0);
+	assert(blk->len < (int) sizeof(blk->buf));
+
+	/* Debug stuff to view passed environment */
+	DBG(("%s: %d vars, %d env size", prog, blk->nvars, blk->len));
+	{
+		int i;
+		for (i = 0 ; i < blk->nvars; i++)
+			DBG(("[%s]", blk->vars[i] ? blk->vars[i] : "null"));
+	}
+}
+
+int
+_shttpd_run_cgi(struct conn *c, const char *prog)
+{
+	struct env_block	blk;
+	char			dir[FILENAME_MAX], *p;
+	int			ret, pair[2];
+
+	prepare_environment(c, prog, &blk);
+	pair[0] = pair[1] = -1;
+
+	/* CGI must be executed in its own directory */
+	(void) _shttpd_snprintf(dir, sizeof(dir), "%s", prog);
+	for (p = dir + strlen(dir) - 1; p > dir; p--)
+		if (*p == '/') {
+			*p++ = '\0';
+			break;
+		}
+	
+	if (shttpd_socketpair(pair) != 0) {
+		ret = -1;
+	} else if (_shttpd_spawn_process(c,
+	    prog, blk.buf, blk.vars, pair[1], dir)) {
+		ret = -1;
+		(void) closesocket(pair[0]);
+		(void) closesocket(pair[1]);
+	} else {
+		ret = 0;
+		c->loc.chan.sock = pair[0];
+	}
+
+	return (ret);
+}
+
+void
+_shttpd_do_cgi(struct conn *c)
+{
+	DBG(("running CGI: [%s]", c->uri));
+	assert(c->loc.io.size > CGI_REPLY_LEN);
+	memcpy(c->loc.io.buf, CGI_REPLY, CGI_REPLY_LEN);
+	c->loc.io.head = c->loc.io.tail = c->loc.io.total = CGI_REPLY_LEN;
+	c->loc.io_class = &_shttpd_io_cgi;
+	c->loc.flags = FLAG_R;
+	if (c->method == METHOD_POST)
+		c->loc.flags |= FLAG_W;
+}
+
+#endif /* !NO_CGI */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,198 @@
+/**********************************************************************
+ *
+ *  rtems shttpd management
+ *
+ *  FILE NAME   : rtems_shttpd.c
+ *
+ *  AUTHOR      : Steven Johnson
+ *
+ *  DESCRIPTION : Defines the interface functions to the shttp daemon
+ *
+ *  REVISION    : $Id: compat_rtems.c,v 1.2 2006/11/12 03:29:17 infidel Exp $
+ *
+ *  COMMENTS    :
+ *
+ **********************************************************************/
+
+ /**********************************************************************
+ * INCLUDED MODULES
+ **********************************************************************/
+#include <rtems.h>
+#include "defs.h"
+
+#define MAX_WEB_BASE_PATH_LENGTH 256
+#define MIN_SHTTPD_STACK         (8*1024)
+
+typedef struct RTEMS_HTTPD_ARGS {
+    rtems_shttpd_init     init_callback;
+    rtems_shttpd_addpages addpages_callback;
+    char                  webroot[MAX_WEB_BASE_PATH_LENGTH];
+} RTEMS_HTTPD_ARGS;
+
+static int rtems_webserver_running = FALSE; //not running.
+
+static rtems_task rtems_httpd_daemon(rtems_task_argument args )
+{
+  RTEMS_HTTPD_ARGS *httpd_args = (RTEMS_HTTPD_ARGS*)args;
+
+  struct shttpd_ctx       *ctx;
+
+  if (httpd_args != NULL)
+    if (httpd_args->init_callback != NULL)
+      httpd_args->init_callback();
+
+/**************************************
+ *  Initialize the web server
+ */
+  /*
+    * Initialize SHTTPD context.
+    * Set WWW root to current WEB_ROOT_PATH.
+    */
+  ctx = shttpd_init(NULL, "document_root", httpd_args->webroot, NULL);
+
+  if (httpd_args != NULL)
+    if (httpd_args->addpages_callback != NULL)
+      httpd_args->addpages_callback(ctx);
+
+  /* Finished with args, so free them */
+  if (httpd_args != NULL)
+    free(httpd_args);
+
+  /* Open listening socket */
+  shttpd_listen(ctx, 9000);
+
+  rtems_webserver_running = TRUE;
+
+  /* Serve connections infinitely until someone kills us */
+  while (rtems_webserver_running)
+    shttpd_poll(ctx, 1000);
+
+  /* Unreached, because we will be killed by a signal */
+  shttpd_fini(ctx);
+
+  rtems_task_delete( RTEMS_SELF );
+}
+
+rtems_status_code rtems_initialize_webserver(rtems_task_priority   initial_priority,
+                                             rtems_unsigned32      stack_size,
+                                             rtems_mode            initial_modes,
+                                             rtems_attribute       attribute_set,
+                                             rtems_shttpd_init     init_callback,
+                                             rtems_shttpd_addpages addpages_callback,
+                                             char                 *webroot
+                                            )
+{
+  rtems_status_code   sc;
+  rtems_id            tid;
+  RTEMS_HTTPD_ARGS    *args;
+
+  if (stack_size < MIN_SHTTPD_STACK)
+    stack_size = MIN_SHTTPD_STACK;
+
+  args = malloc(sizeof(RTEMS_HTTPD_ARGS));
+
+  if (args != NULL)
+  {
+    args->init_callback = init_callback;
+    args->addpages_callback = addpages_callback;
+    strncpy(args->webroot,webroot,MAX_WEB_BASE_PATH_LENGTH);
+
+    sc = rtems_task_create(rtems_build_name('H', 'T', 'P', 'D'),
+                           initial_priority,
+                           stack_size,
+                           initial_modes,
+                           attribute_set,
+                           &tid);
+
+    if (sc == RTEMS_SUCCESSFUL)
+    {
+      sc = rtems_task_start(tid, rtems_httpd_daemon, (rtems_task_argument)args);
+    }
+  }
+  else
+  {
+    sc = RTEMS_NO_MEMORY;
+  }
+
+  return sc;
+}
+
+void rtems_terminate_webserver(void)
+{
+  rtems_webserver_running = FALSE; //not running, so terminate
+}
+
+int rtems_webserver_ok(void)
+{
+  return rtems_webserver_running;
+}
+
+void
+set_close_on_exec(int fd)
+{
+        // RTEMS Does not have a functional "execve"
+        // so technically this call does not do anything,
+        // but it doesnt hurt either.
+        (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+int
+my_stat(const char *path, struct stat *stp)
+{
+        return (stat(path, stp));
+}
+
+int
+my_open(const char *path, int flags, int mode)
+{
+        return (open(path, flags, mode));
+}
+
+int
+my_remove(const char *path)
+{
+	return (remove(path));
+}
+
+int
+my_rename(const char *path1, const char *path2)
+{
+	return (rename(path1, path2));
+}
+
+int
+my_mkdir(const char *path, int mode)
+{
+	return (mkdir(path, mode));
+}
+
+char *
+my_getcwd(char *buffer, int maxlen)
+{
+	return (getcwd(buffer, maxlen));
+}
+
+int
+set_non_blocking_mode(int fd)
+{
+        int     ret = -1;
+        int     flags;
+
+        if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
+                DBG(("nonblock: fcntl(F_GETFL): %d", ERRNO));
+        } else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
+                DBG(("nonblock: fcntl(F_SETFL): %d", ERRNO));
+        } else {
+                ret = 0;        /* Success */
+        }
+
+        return (ret);
+}
+
+#if !defined(NO_CGI)
+int
+spawn_process(struct conn *c, const char *prog, char *envblk, char **envp)
+{
+        return (-1); // RTEMS does not have subprocess support as standard.
+}
+#endif

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_rtems.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,60 @@
+/**
+ * @file rtems/rtems-shttpd.h
+ */
+
+#ifndef _rtems_rtems_webserver_h
+#define _rtems_rtems_webserver_h
+
+#include "shttpd.h"
+
+#include <rtems.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <dirent.h>
+
+/* RTEMS is an Real Time Embedded operating system, for operation in hardware.
+  It does not have SSL or CGI support, as it does not have dynamic library
+  loading or sub-processes. */
+#define EMBEDDED
+#define NO_SSL
+#define NO_CGI
+
+#define DIRSEP                          '/'
+#define O_BINARY                        0
+#define ERRNO                           errno
+
+/* RTEMS version is Thread Safe */
+#define InitializeCriticalSection(x)  rtems_semaphore_create( \
+                                  rtems_build_name('H','T','P','X'), \
+                                  1, /* Not Held Yet.*/ \
+                                  RTEMS_FIFO | \
+                                  RTEMS_BINARY_SEMAPHORE, \
+                                  0, \
+                                  x);
+#define EnterCriticalSection(x) rtems_semaphore_obtain(*(x),RTEMS_WAIT,RTEMS_NO_TIMEOUT)
+#define LeaveCriticalSection(x) rtems_semaphore_release(*(x))
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*rtems_shttpd_addpages)(struct shttpd_ctx *ctx);
+typedef void (*rtems_shttpd_init)(void);
+
+rtems_status_code rtems_initialize_webserver(rtems_task_priority   initial_priority,
+                                             rtems_unsigned32      stack_size,
+                                             rtems_mode            initial_modes,
+                                             rtems_attribute       attribute_set,
+                                             rtems_shttpd_init     init_callback,
+                                             rtems_shttpd_addpages addpages_callback,
+                                             char                 *webroot
+                                            );
+void rtems_terminate_webserver(void);
+int  rtems_webserver_ok(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,128 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+void 
+_shttpd_set_close_on_exec(int fd)
+{
+	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+int
+_shttpd_stat(const char *path, struct stat *stp)
+{
+	return (stat(path, stp));
+}
+
+int
+_shttpd_open(const char *path, int flags, int mode)
+{
+	return (open(path, flags, mode));
+}
+
+int
+_shttpd_remove(const char *path)
+{
+	return (remove(path));
+}
+
+int
+_shttpd_rename(const char *path1, const char *path2)
+{
+	return (rename(path1, path2));
+}
+
+int
+_shttpd_mkdir(const char *path, int mode)
+{
+	return (mkdir(path, mode));
+}
+
+char *
+_shttpd_getcwd(char *buffer, int maxlen)
+{
+	return (getcwd(buffer, maxlen));
+}
+
+int
+_shttpd_set_non_blocking_mode(int fd)
+{
+	int	ret = -1;
+	int	flags;
+
+	if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
+		DBG(("nonblock: fcntl(F_GETFL): %d", ERRNO));
+	} else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) {
+		DBG(("nonblock: fcntl(F_SETFL): %d", ERRNO));
+	} else {
+		ret = 0;	/* Success */
+	}
+
+	return (ret);
+}
+
+#ifndef NO_CGI
+int
+_shttpd_spawn_process(struct conn *c, const char *prog, char *envblk,
+		char *envp[], int sock, const char *dir)
+{
+	int		ret;
+	pid_t		pid;
+	const char	*p, *interp = c->ctx->options[OPT_CGI_INTERPRETER];
+
+	envblk = NULL;	/* unused */
+
+	if ((pid = vfork()) == -1) {
+
+		ret = -1;
+		_shttpd_elog(E_LOG, c, "redirect: fork: %s", strerror(errno));
+
+	} else if (pid == 0) {
+
+		/* Child */
+
+		(void) chdir(dir);
+		(void) dup2(sock, 0);
+		(void) dup2(sock, 1);
+		(void) closesocket(sock);
+
+		/* If error file is specified, send errors there */
+		if (c->ctx->error_log)
+			(void) dup2(fileno(c->ctx->error_log), 2);
+
+		if ((p = strrchr(prog, '/')) != NULL)
+			p++;
+		else
+			p = prog;
+
+		/* Execute CGI program */
+		if (interp == NULL) {
+			(void) execle(p, p, NULL, envp);
+			_shttpd_elog(E_FATAL, c, "redirect: exec(%s)", prog);
+		} else {
+			(void) execle(interp, interp, p, NULL, envp);
+			_shttpd_elog(E_FATAL, c, "redirect: exec(%s %s)",
+			    interp, prog);
+		}
+
+		/* UNREACHED */
+		exit(EXIT_FAILURE);
+
+	} else {
+
+		/* Parent */
+		ret = 0;
+		(void) closesocket(sock);
+	}
+
+	return (ret);
+}
+#endif /* !NO_CGI */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_unix.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,44 @@
+/*
+ * Copyright (c) 2004-2007 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/mman.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <dlfcn.h>
+
+#if !defined(NO_THREADS)
+#include "pthread.h"
+#define	_beginthread(a, b, c) do { pthread_t tid; \
+	pthread_create(&tid, NULL, (void *(*)(void *))a, c); } while (0)
+#endif /* !NO_THREADS */
+
+#if !defined(CYGWIN)									//@@ Add
+#define	SSL_LIB				"libssl.so"
+#elif defined(CYGWIN)									//@@ Add
+	#if defined(SSL_0_9_8)
+		#define	SSL_LIB				"cygssl-0.9.8.dll"			//@@ Add
+	#elif !defined(SSL_0_9_8)									//@@ Add
+		#define	SSL_LIB				"cygssl-0.9.7.dll"			//@@ Add
+	#endif														//@@ Add
+#endif 															//@@ Add	/* CYGWIN */
+
+#define	DIRSEP				'/'
+#define	IS_DIRSEP_CHAR(c)		((c) == '/')
+#define	O_BINARY			0
+#define	closesocket(a)			close(a)
+#define	ERRNO				errno

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,687 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+static SERVICE_STATUS		ss; 
+static SERVICE_STATUS_HANDLE	hStatus; 
+static SERVICE_DESCRIPTION	service_descr = {"Web server"};
+
+static void
+fix_directory_separators(char *path)
+{
+	for (; *path != '\0'; path++) {
+		if (*path == '/')
+			*path = '\\';
+		if (*path == '\\')
+			while (path[1] == '\\' || path[1] == '/') 
+				(void) memmove(path + 1,
+				    path + 2, strlen(path + 2) + 1);
+	}
+}
+
+static int
+protect_against_code_disclosure(const wchar_t *path)
+{
+	WIN32_FIND_DATAW	data;
+	HANDLE			handle;
+	const wchar_t		*p;
+
+	/*
+	 * Protect against CGI code disclosure under Windows.
+	 * This is very nasty hole. Windows happily opens files with
+	 * some garbage in the end of file name. So fopen("a.cgi    ", "r")
+	 * actually opens "a.cgi", and does not return an error! And since
+	 * "a.cgi    " does not have valid CGI extension, this leads to
+	 * the CGI code disclosure.
+	 * To protect, here we delete all fishy characters from the
+	 * end of file name.
+	 */
+
+	if ((handle = FindFirstFileW(path, &data)) == INVALID_HANDLE_VALUE)
+		return (FALSE);
+
+	FindClose(handle);
+
+	for (p = path + wcslen(path); p > path && p[-1] != L'\\';)
+		p--;
+	
+	if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+	    wcscmp(data.cFileName, p) != 0)
+		return (FALSE);
+
+	return (TRUE);
+}
+
+int
+_shttpd_open(const char *path, int flags, int mode)
+{
+	char	buf[FILENAME_MAX];
+	wchar_t	wbuf[FILENAME_MAX];
+
+	_shttpd_strlcpy(buf, path, sizeof(buf));
+	fix_directory_separators(buf);
+	MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+	if (protect_against_code_disclosure(wbuf) == FALSE)
+		return (-1);
+
+	return (_wopen(wbuf, flags));
+}
+
+int
+_shttpd_stat(const char *path, struct stat *stp)
+{
+	char	buf[FILENAME_MAX], *p;
+	wchar_t	wbuf[FILENAME_MAX];
+
+	_shttpd_strlcpy(buf, path, sizeof(buf));
+	fix_directory_separators(buf);
+
+	p = buf + strlen(buf) - 1;
+	while (p > buf && *p == '\\' && p[-1] != ':')
+		*p-- = '\0';
+
+	MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+	return (_wstat(wbuf, (struct _stat *) stp));
+}
+
+int
+_shttpd_remove(const char *path)
+{
+	char	buf[FILENAME_MAX];
+	wchar_t	wbuf[FILENAME_MAX];
+
+	_shttpd_strlcpy(buf, path, sizeof(buf));
+	fix_directory_separators(buf);
+
+	MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+	return (_wremove(wbuf));
+}
+
+int
+_shttpd_rename(const char *path1, const char *path2)
+{
+	char	buf1[FILENAME_MAX];
+	char	buf2[FILENAME_MAX];
+	wchar_t	wbuf1[FILENAME_MAX];
+	wchar_t	wbuf2[FILENAME_MAX];
+
+	_shttpd_strlcpy(buf1, path1, sizeof(buf1));
+	_shttpd_strlcpy(buf2, path2, sizeof(buf2));
+	fix_directory_separators(buf1);
+	fix_directory_separators(buf2);
+
+	MultiByteToWideChar(CP_UTF8, 0, buf1, -1, wbuf1, sizeof(wbuf1));
+	MultiByteToWideChar(CP_UTF8, 0, buf2, -1, wbuf2, sizeof(wbuf2));
+
+	return (_wrename(wbuf1, wbuf2));
+}
+
+int
+_shttpd_mkdir(const char *path, int mode)
+{
+	char	buf[FILENAME_MAX];
+	wchar_t	wbuf[FILENAME_MAX];
+
+	_shttpd_strlcpy(buf, path, sizeof(buf));
+	fix_directory_separators(buf);
+
+	MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+	return (_wmkdir(wbuf));
+}
+
+static char *
+wide_to_utf8(const wchar_t *str)
+{
+	char *buf = NULL;
+	if (str) {
+		int nchar = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+		if (nchar > 0) {
+			buf = malloc(nchar);
+			if (!buf)
+				errno = ENOMEM;
+			else if (!WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, nchar, NULL, NULL)) {
+				free(buf);
+				buf = NULL;
+				errno = EINVAL;
+			}
+		} else
+			errno = EINVAL;
+	} else
+		errno = EINVAL;
+	return buf;
+}
+
+char *
+_shttpd_getcwd(char *buffer, int maxlen)
+{
+	char *result = NULL;
+	wchar_t *wbuffer, *wresult;
+
+	if (buffer) {
+		/* User-supplied buffer */
+		wbuffer = malloc(maxlen * sizeof(wchar_t));
+		if (wbuffer == NULL)
+			return NULL;
+	} else
+		/* Dynamically allocated buffer */
+		wbuffer = NULL;
+	wresult = _wgetcwd(wbuffer, maxlen);
+	if (wresult) {
+		int err = errno;
+		if (buffer) {
+			/* User-supplied buffer */
+			int n = WideCharToMultiByte(CP_UTF8, 0, wresult, -1, buffer, maxlen, NULL, NULL);
+			if (n == 0)
+				err = ERANGE;
+			free(wbuffer);
+			result = buffer;
+		} else {
+			/* Buffer allocated by _wgetcwd() */
+			result = wide_to_utf8(wresult);
+			err = errno;
+			free(wresult);
+		}
+		errno = err;
+	}
+	return result;
+}
+
+DIR *
+opendir(const char *name)
+{
+	DIR		*dir = NULL;
+	char		path[FILENAME_MAX];
+	wchar_t		wpath[FILENAME_MAX];
+
+	if (name == NULL || name[0] == '\0') {
+		errno = EINVAL;
+	} else if ((dir = malloc(sizeof(*dir))) == NULL) {
+		errno = ENOMEM;
+	} else {
+		_shttpd_snprintf(path, sizeof(path), "%s/*", name);
+		fix_directory_separators(path);
+		MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, sizeof(wpath));
+		dir->handle = FindFirstFileW(wpath, &dir->info);
+
+		if (dir->handle != INVALID_HANDLE_VALUE) {
+			dir->result.d_name[0] = '\0';
+		} else {
+			free(dir);
+			dir = NULL;
+		}
+	}
+
+	return (dir);
+}
+
+int
+closedir(DIR *dir)
+{
+	int result = -1;
+
+	if (dir != NULL) {
+		if (dir->handle != INVALID_HANDLE_VALUE)
+			result = FindClose(dir->handle) ? 0 : -1;
+
+		free(dir);
+	}
+
+	if (result == -1) 
+		errno = EBADF;
+
+	return (result);
+}
+
+struct dirent *
+readdir(DIR *dir)
+{
+	struct dirent *result = 0;
+
+	if (dir && dir->handle != INVALID_HANDLE_VALUE) {
+		if(!dir->result.d_name ||
+		    FindNextFileW(dir->handle, &dir->info)) {
+			result = &dir->result;
+
+			WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName,
+			    -1, result->d_name,
+			    sizeof(result->d_name), NULL, NULL);
+		}
+	} else {
+		errno = EBADF;
+	}
+
+	return (result);
+}
+
+int
+_shttpd_set_non_blocking_mode(int fd)
+{
+	unsigned long	on = 1;
+
+	return (ioctlsocket(fd, FIONBIO, &on));
+}
+
+void
+_shttpd_set_close_on_exec(int fd)
+{
+	fd = 0;	/* Do nothing. There is no FD_CLOEXEC on Windows */
+}
+
+#if !defined(NO_CGI)
+
+struct threadparam {
+	SOCKET	s;
+	HANDLE	hPipe;
+	big_int_t content_len;
+};
+
+
+enum ready_mode_t {IS_READY_FOR_READ, IS_READY_FOR_WRITE};
+
+/*
+ * Wait until given socket is in ready state. Always return TRUE.
+ */
+static int
+is_socket_ready(int sock, enum ready_mode_t mode)
+{
+	fd_set		read_set, write_set;
+
+	FD_ZERO(&read_set);
+	FD_ZERO(&write_set);
+
+	if (mode == IS_READY_FOR_READ)
+		FD_SET(sock, &read_set);
+	else
+		FD_SET(sock, &write_set);
+
+	select(sock + 1, &read_set, &write_set, NULL, NULL);
+
+	return (TRUE);
+}
+
+/*
+ * Thread function that reads POST data from the socket pair
+ * and writes it to the CGI process.
+ */
+static void//DWORD WINAPI
+stdoutput(void *arg)
+{
+	struct threadparam	*tp = arg;
+	int			n, sent, stop = 0;
+	big_int_t		total = 0;
+	DWORD k;
+	char			buf[BUFSIZ];
+	size_t			max_recv;
+
+	max_recv = min(sizeof(buf), tp->content_len - total);
+	while (!stop &&
+	    max_recv > 0 &&
+	    is_socket_ready(tp->s, IS_READY_FOR_READ) &&
+	    (n = recv(tp->s, buf, max_recv, 0)) > 0) {
+		if (n == -1 && ERRNO == EWOULDBLOCK)
+			continue;
+		for (sent = 0; !stop && sent < n; sent += k)
+			if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0))
+				stop++;
+		total += n;
+		max_recv = min(sizeof(buf), tp->content_len - total);
+	}
+	
+	CloseHandle(tp->hPipe);	/* Suppose we have POSTed everything */
+	free(tp);
+}
+
+/*
+ * Thread function that reads CGI output and pushes it to the socket pair.
+ */
+static void
+stdinput(void *arg)
+{
+	struct threadparam	*tp = arg;
+	static			int ntotal;
+	int			k, stop = 0;
+	DWORD n, sent;
+	char			buf[BUFSIZ];
+
+	while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
+		ntotal += n;
+		for (sent = 0; !stop && sent < n; sent += k) {
+			if (is_socket_ready(tp->s, IS_READY_FOR_WRITE) &&
+			    (k = send(tp->s, buf + sent, n - sent, 0)) <= 0) {
+				if (k == -1 && ERRNO == EWOULDBLOCK) {
+					k = 0;
+					continue;
+				}
+				stop++;
+			}
+		}
+	}
+	CloseHandle(tp->hPipe);
+	
+	/*
+	 * Windows is a piece of crap. When this thread closes its end
+	 * of the socket pair, the other end (get_cgi() function) may loose
+	 * some data. I presume, this happens if get_cgi() is not fast enough,
+	 * and the data written by this end does not "push-ed" to the other
+	 * end socket buffer. So after closesocket() the remaining data is
+	 * gone. If I put shutdown() before closesocket(), that seems to
+	 * fix the problem, but I am not sure this is the right fix.
+	 * XXX (submitted by James Marshall) we do not do shutdown() on UNIX.
+	 * If fork() is called from user callback, shutdown() messes up things.
+	 */
+	shutdown(tp->s, 2);
+
+	closesocket(tp->s);
+	free(tp);
+
+	_endthread();
+}
+
+static void
+spawn_stdio_thread(int sock, HANDLE hPipe, void (*func)(void *),
+		big_int_t content_len)
+{
+	struct threadparam	*tp;
+	DWORD			tid;
+
+	tp = malloc(sizeof(*tp));
+	assert(tp != NULL);
+
+	tp->s		= sock;
+	tp->hPipe	= hPipe;
+	tp->content_len = content_len;
+	_beginthread(func, 0, tp);
+}
+
+int
+_shttpd_spawn_process(struct conn *c, const char *prog, char *envblk,
+		char *envp[], int sock, const char *dir)
+{
+	HANDLE	a[2], b[2], h[2], me;
+	DWORD	flags;
+	char	*p, *interp, cmdline[FILENAME_MAX], line[FILENAME_MAX];
+	FILE	*fp;
+	STARTUPINFOA		si;
+	PROCESS_INFORMATION	pi;
+
+	me = GetCurrentProcess();
+	flags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+
+	/* FIXME add error checking code here */
+	CreatePipe(&a[0], &a[1], NULL, 0);
+	CreatePipe(&b[0], &b[1], NULL, 0);
+	DuplicateHandle(me, a[0], me, &h[0], 0, TRUE, flags);
+	DuplicateHandle(me, b[1], me, &h[1], 0, TRUE, flags);
+	
+	(void) memset(&si, 0, sizeof(si));
+	(void) memset(&pi, 0, sizeof(pi));
+
+	/* XXX redirect CGI errors to the error log file */
+	si.cb		= sizeof(si);
+	si.dwFlags	= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+	si.wShowWindow	= SW_HIDE;
+	si.hStdOutput	= h[1];
+	si.hStdInput	= h[0];
+
+	/* If CGI file is a script, try to read the interpreter line */
+	interp = c->ctx->options[OPT_CGI_INTERPRETER];
+	if (interp == NULL) {
+		if ((fp = fopen(prog, "r")) != NULL) {
+			(void) fgets(line, sizeof(line), fp);
+			if (memcmp(line, "#!", 2) != 0)
+				line[2] = '\0';
+			/* Trim whitespaces from interpreter name */
+			for (p = &line[strlen(line) - 1]; p > line &&
+			    isspace(*p); p--)
+				*p = '\0';
+			(void) fclose(fp);
+		}
+		interp = line + 2;
+		(void) _shttpd_snprintf(cmdline, sizeof(cmdline), "%s%s%s",
+		    line + 2, line[2] == '\0' ? "" : " ", prog);
+	}
+
+	if ((p = strrchr(prog, '/')) != NULL)
+		prog = p + 1;
+
+	(void) _shttpd_snprintf(cmdline, sizeof(cmdline), "%s %s", interp, prog);
+
+	(void) _shttpd_snprintf(line, sizeof(line), "%s", dir);
+	fix_directory_separators(line);
+	fix_directory_separators(cmdline);
+
+	/*
+	 * Spawn reader & writer threads before we create CGI process.
+	 * Otherwise CGI process may die too quickly, loosing the data
+	 */
+	spawn_stdio_thread(sock, b[0], stdinput, 0);
+	spawn_stdio_thread(sock, a[1], stdoutput, c->rem.content_len);
+
+	if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
+	    CREATE_NEW_PROCESS_GROUP, envblk, line, &si, &pi) == 0) {
+		_shttpd_elog(E_LOG, c,
+		    "redirect: CreateProcess(%s): %d", cmdline, ERRNO);
+		return (-1);
+	} else {
+		CloseHandle(h[0]);
+		CloseHandle(h[1]);
+		CloseHandle(pi.hThread);
+		CloseHandle(pi.hProcess);
+	}
+
+	return (0);
+}
+
+#endif /* !NO_CGI */
+
+#define	ID_TRAYICON	100
+#define	ID_QUIT		101
+static NOTIFYICONDATA	ni;
+
+static LRESULT CALLBACK
+WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	POINT	pt;
+	HMENU	hMenu; 	 
+
+	switch (msg) {
+	case WM_COMMAND:
+		switch (LOWORD(wParam)) {
+		case ID_QUIT:
+			exit(EXIT_SUCCESS);
+			break;
+		}
+		break;
+	case WM_USER:
+		switch (lParam) {
+		case WM_RBUTTONUP:
+		case WM_LBUTTONUP:
+		case WM_LBUTTONDBLCLK:
+			hMenu = CreatePopupMenu();
+			AppendMenu(hMenu, 0, ID_QUIT, "Exit SHTTPD");
+			GetCursorPos(&pt);
+			TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
+			DestroyMenu(hMenu);
+			break;
+		}
+		break;
+	}
+
+	return (DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+static void
+systray(void *arg)
+{
+	WNDCLASS	cls;
+	HWND		hWnd;
+	MSG		msg;
+
+	(void) memset(&cls, 0, sizeof(cls));
+
+	cls.lpfnWndProc = (WNDPROC) WindowProc; 
+	cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+	cls.lpszClassName = "shttpd v." VERSION; 
+
+	if (!RegisterClass(&cls)) 
+		_shttpd_elog(E_FATAL, NULL, "RegisterClass: %d", ERRNO);
+	else if ((hWnd = CreateWindow(cls.lpszClassName, "",
+	    WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, arg)) == NULL)
+		_shttpd_elog(E_FATAL, NULL, "CreateWindow: %d", ERRNO);
+	ShowWindow(hWnd, SW_HIDE);
+	
+	ni.cbSize = sizeof(ni);
+	ni.uID = ID_TRAYICON;
+	ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+	ni.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+	ni.hWnd = hWnd;
+	_shttpd_snprintf(ni.szTip, sizeof(ni.szTip), "SHTTPD web server");
+	ni.uCallbackMessage = WM_USER;
+	Shell_NotifyIcon(NIM_ADD, &ni);
+
+	while (GetMessage(&msg, hWnd, 0, 0)) { 
+		TranslateMessage(&msg); 
+		DispatchMessage(&msg); 
+	}
+}
+
+int
+_shttpd_set_systray(struct shttpd_ctx *ctx, const char *opt)
+{
+	HWND		hWnd;
+	char		title[512];
+	static WNDPROC	oldproc;
+
+	if (!_shttpd_is_true(opt))
+		return (TRUE);
+
+	FreeConsole();
+	GetConsoleTitle(title, sizeof(title));
+	hWnd = FindWindow(NULL, title);
+	ShowWindow(hWnd, SW_HIDE);
+	_beginthread(systray, 0, hWnd);
+
+	return (TRUE);
+}
+
+int
+_shttpd_set_nt_service(struct shttpd_ctx *ctx, const char *action)
+{
+	SC_HANDLE	hSCM, hService;
+	char		path[FILENAME_MAX], key[128];
+	HKEY		hKey;
+	DWORD		dwData;
+
+
+	if (!strcmp(action, "install")) {
+		if ((hSCM = OpenSCManager(NULL, NULL,
+		    SC_MANAGER_ALL_ACCESS)) == NULL)
+			_shttpd_elog(E_FATAL, NULL, "Error opening SCM (%d)", ERRNO);
+
+		GetModuleFileName(NULL, path, sizeof(path));
+
+		hService = CreateService(hSCM, SERVICE_NAME, SERVICE_NAME,
+		    SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+		    SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path,
+		    NULL, NULL, NULL, NULL, NULL);
+
+		if (!hService)
+			_shttpd_elog(E_FATAL, NULL,
+			    "Error installing service (%d)", ERRNO);
+
+		ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION,
+		    &service_descr);
+		_shttpd_elog(E_FATAL, NULL, "Service successfully installed");
+
+
+	} else if (!strcmp(action, "uninstall")) {
+
+		if ((hSCM = OpenSCManager(NULL, NULL,
+		    SC_MANAGER_ALL_ACCESS)) == NULL) {
+			_shttpd_elog(E_FATAL, NULL, "Error opening SCM (%d)", ERRNO);
+		} else if ((hService = OpenService(hSCM,
+		    SERVICE_NAME, DELETE)) == NULL) {
+			_shttpd_elog(E_FATAL, NULL,
+			    "Error opening service (%d)", ERRNO);
+		} else if (!DeleteService(hService)) {
+			_shttpd_elog(E_FATAL, NULL,
+			    "Error deleting service (%d)", ERRNO);
+		} else {
+			_shttpd_elog(E_FATAL, NULL, "Service deleted");
+		}
+
+	} else {
+		_shttpd_elog(E_FATAL, NULL, "Use -service <install|uninstall>");
+	}
+
+	/* NOTREACHED */
+	return (TRUE);
+}
+
+static void WINAPI
+ControlHandler(DWORD code) 
+{ 
+	if (code == SERVICE_CONTROL_STOP || code == SERVICE_CONTROL_SHUTDOWN) {
+		ss.dwWin32ExitCode	= 0; 
+		ss.dwCurrentState	= SERVICE_STOPPED; 
+	} 
+ 
+	SetServiceStatus(hStatus, &ss);
+}
+
+static void WINAPI
+ServiceMain(int argc, char *argv[]) 
+{
+	char	path[MAX_PATH], *p, *av[] = {"shttpd_service", path, NULL};
+	struct shttpd_ctx	*ctx;
+
+	ss.dwServiceType      = SERVICE_WIN32; 
+	ss.dwCurrentState     = SERVICE_RUNNING; 
+	ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+
+	hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ControlHandler);
+	SetServiceStatus(hStatus, &ss); 
+
+	GetModuleFileName(NULL, path, sizeof(path));
+
+	if ((p = strrchr(path, DIRSEP)) != NULL)
+		*++p = '\0';
+
+	strcat(path, CONFIG_FILE);	/* woo ! */
+
+	ctx = shttpd_init(NELEMS(av) - 1, av);
+	if ((ctx = shttpd_init(NELEMS(av) - 1, av)) == NULL)
+		_shttpd_elog(E_FATAL, NULL, "Cannot initialize SHTTP context");
+
+	while (ss.dwCurrentState == SERVICE_RUNNING)
+		shttpd_poll(ctx, INT_MAX);
+	shttpd_fini(ctx);
+
+	ss.dwCurrentState  = SERVICE_STOPPED; 
+	ss.dwWin32ExitCode = -1; 
+	SetServiceStatus(hStatus, &ss); 
+}
+
+void
+try_to_run_as_nt_service(void)
+{
+	static SERVICE_TABLE_ENTRY service_table[] = {
+		{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
+		{NULL, NULL}
+	};
+
+	if (StartServiceCtrlDispatcher(service_table))
+		exit(EXIT_SUCCESS);
+}

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_win32.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,83 @@
+/*
+ * Copyright (c) 2004-2007 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+/* Tip from Justin Maximilian, suppress errors from winsock2.h */
+#define _WINSOCKAPI_
+
+#include <windows.h>
+#include <winsock2.h>
+#include <commctrl.h>
+#include <winnls.h>
+#include <shlobj.h>
+#include <shellapi.h>
+
+#ifndef _WIN32_WCE
+
+#include <process.h>
+#include <direct.h>
+#include <io.h>
+
+#else /* _WIN32_WCE */
+
+/* Windows CE-specific definitions */
+#define NO_CGI	/* WinCE has no pipes */
+#define NO_GUI	/* temporarily until it is fixed */
+#pragma comment(lib,"ws2")
+/* WinCE has both Unicode and ANSI versions of GetProcAddress */
+#undef GetProcAddress
+#define GetProcAddress GetProcAddressA
+#include "compat_wince.h"
+
+#endif /* _WIN32_WCE */
+
+#define	ERRNO			GetLastError()
+#define	NO_SOCKLEN_T
+#define	SSL_LIB			L"ssleay32.dll"
+#define	DIRSEP			'\\'
+#define	IS_DIRSEP_CHAR(c)	((c) == '/' || (c) == '\\')
+#define	O_NONBLOCK		0
+#define	EWOULDBLOCK		WSAEWOULDBLOCK
+#define	snprintf		_snprintf
+#define	vsnprintf		_vsnprintf
+#define	mkdir(x,y)		_mkdir(x)
+#define	popen(x,y)		_popen(x, y)
+#define	pclose(x)		_pclose(x)
+#define	dlopen(x,y)		LoadLibraryW(x)
+#define	dlsym(x,y)		(void *) GetProcAddress(x,y)
+#define	_POSIX_
+
+#ifdef __LCC__
+#include <stdint.h>
+#endif /* __LCC__ */
+
+#ifdef _MSC_VER /* MinGW already has these */
+typedef unsigned int		uint32_t;
+typedef unsigned short		uint16_t;
+typedef __int64			uint64_t;
+#define S_ISDIR(x)		((x) & _S_IFDIR)
+#endif /* _MSC_VER */
+
+/*
+ * POSIX dirent interface
+ */
+struct dirent {
+	char	d_name[FILENAME_MAX];
+};
+
+typedef struct DIR {
+	HANDLE			handle;
+	WIN32_FIND_DATAW	info;
+	struct dirent		result;
+	char			*name;
+} DIR;
+
+extern DIR *opendir(const char *name);
+extern int closedir(DIR *dir);
+extern struct dirent *readdir(DIR *dir);

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,1593 @@
+/*
+ vi:ts=8:sw=8:noet
+ * Copyright (c) 2006 Luke Dunstan <infidel at users.sourceforge.net>
+ * Partly based on code by David Kashtan, Validus Medical Systems
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This file provides various functions that are available on desktop Windows
+ * but not on Windows CE
+ */
+
+#ifdef _MSC_VER
+/* Level 4 warnings caused by windows.h */
+#pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+#pragma warning(disable : 4115) // named type definition in parentheses
+#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+#pragma warning(disable : 4514) // unreferenced inline function has been removed
+#pragma warning(disable : 4244) // conversion from 'int ' to 'unsigned short ', possible loss of data
+#pragma warning(disable : 4100) // unreferenced formal parameter
+#endif
+
+#include <windows.h>
+#include <stdlib.h>
+
+#include "compat_wince.h"
+
+
+static WCHAR *to_wide_string(LPCSTR pStr)
+{
+	int nwide;
+	WCHAR *buf;
+
+	if(pStr == NULL)
+		return NULL;
+	nwide = MultiByteToWideChar(CP_ACP, 0, pStr, -1, NULL, 0);
+	if(nwide == 0)
+		return NULL;
+	buf = malloc(nwide * sizeof(WCHAR));
+	if(buf == NULL) {
+		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+		return NULL;
+	}
+	if(MultiByteToWideChar(CP_ACP, 0, pStr, -1, buf, nwide) == 0) {
+		free(buf);
+		return NULL;
+	}
+	return buf;
+}
+
+FILE *fdopen(int handle, const char *mode)
+{
+	WCHAR *wmode = to_wide_string(mode);
+	FILE *result;
+
+	if(wmode != NULL)
+		result = _wfdopen((void *)handle, wmode);
+	else
+		result = NULL;
+	free(wmode);
+	return result;
+}
+
+/*
+ *	Time conversion constants
+ */
+#define FT_EPOCH (116444736000000000i64)
+#define	FT_TICKS (10000000i64)
+
+ /*
+ *	Convert a FILETIME to a time_t
+ */
+static time_t convert_FILETIME_to_time_t(FILETIME *File_Time)
+{
+	__int64 Temp;
+
+	/*
+	 *	Convert the FILETIME structure to 100nSecs since 1601 (as a 64-bit value)
+	 */
+	Temp = (((__int64)File_Time->dwHighDateTime) << 32) + (__int64)File_Time->dwLowDateTime;
+	/*
+	 *	Convert to seconds from 1970
+	 */
+	return((time_t)((Temp - FT_EPOCH) / FT_TICKS));
+}
+
+/*
+ *	Convert a FILETIME to a tm structure
+ */
+static struct tm *Convert_FILETIME_To_tm(FILETIME *File_Time)
+{
+	SYSTEMTIME System_Time;
+	static struct tm tm = {0};
+	static const short Day_Of_Year_By_Month[12] = {(short)(0),
+						       (short)(31),
+						       (short)(31 + 28),
+						       (short)(31 + 28 + 31),
+						       (short)(31 + 28 + 31 + 30),
+						       (short)(31 + 28 + 31 + 30 + 31),
+						       (short)(31 + 28 + 31 + 30 + 31 + 30),
+						       (short)(31 + 28 + 31 + 30 + 31 + 30 + 31),
+						       (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31),
+						       (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30),
+						       (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31),
+						       (short)(31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30)};
+
+
+	/*
+	 *	Turn the FILETIME into a SYSTEMTIME
+	 */
+	FileTimeToSystemTime(File_Time, &System_Time);
+	/*
+	 *	Use SYSTEMTIME to fill in the tm structure
+	 */
+	tm.tm_sec = System_Time.wSecond;
+	tm.tm_min = System_Time.wMinute;
+	tm.tm_hour = System_Time.wHour;
+	tm.tm_mday = System_Time.wDay;
+	tm.tm_mon = System_Time.wMonth - 1;
+	tm.tm_year = System_Time.wYear - 1900;
+	tm.tm_wday = System_Time.wDayOfWeek;
+	tm.tm_yday = Day_Of_Year_By_Month[tm.tm_mon] + tm.tm_mday - 1;
+	if (tm.tm_mon >= 2) {
+		/*
+		 *	Check for leap year (every 4 years but not every 100 years but every 400 years)
+		 */
+		if ((System_Time.wYear % 4) == 0) {
+			/*
+			 *	It Is a 4th year
+			 */
+			if ((System_Time.wYear % 100) == 0) {
+				/*
+				 *	It is a 100th year
+				 */
+				if ((System_Time.wYear % 400) == 0) {
+					/*
+					 *	It is a 400th year: It is a leap year
+					 */
+					tm.tm_yday++;
+				}
+			} else {
+				/*
+				 *	It is not a 100th year: It is a leap year
+				 */
+				tm.tm_yday++;
+			}
+		}
+	}
+	return(&tm);
+}
+
+/*
+ *	Convert a time_t to a FILETIME
+ */
+static void Convert_time_t_To_FILETIME(time_t Time, FILETIME *File_Time)
+{
+	__int64 Temp;
+
+	/*
+	 *	Use 64-bit calculation to convert seconds since 1970 to
+	 *	100nSecs since 1601
+	 */
+	Temp = ((__int64)Time * FT_TICKS) + FT_EPOCH;
+	/*
+	 *	Put it into the FILETIME structure
+	 */
+	File_Time->dwLowDateTime = (DWORD)Temp;
+	File_Time->dwHighDateTime = (DWORD)(Temp >> 32);
+}
+
+/*
+ *	Convert a tm structure to a FILETIME
+ */
+static FILETIME *Convert_tm_To_FILETIME(struct tm *tm)
+{
+	SYSTEMTIME System_Time;
+	static FILETIME File_Time = {0};
+
+	/*
+	 *	Use the tm structure to fill in a SYSTEM
+	 */
+	System_Time.wYear = tm->tm_year + 1900;
+	System_Time.wMonth = tm->tm_mon + 1;
+	System_Time.wDayOfWeek = tm->tm_wday;
+	System_Time.wDay = tm->tm_mday;
+	System_Time.wHour = tm->tm_hour;
+	System_Time.wMinute = tm->tm_min;
+	System_Time.wSecond = tm->tm_sec;
+	System_Time.wMilliseconds = 0;
+	/*
+	 *	Convert it to a FILETIME and return it
+	 */
+	SystemTimeToFileTime(&System_Time, &File_Time);
+	return(&File_Time);
+}
+
+
+/************************************************************************/
+/*									*/
+/*	Errno emulation:  There is no errno on Windows/CE and we need	*/
+/*			  to make it per-thread.  So we have a function	*/
+/*			  that returns a pointer to the errno for the	*/
+/*			  current thread.				*/
+/*									*/
+/*			  If there is ONLY the main thread then we can	*/
+/* 			  quickly return some static storage.		*/
+/*									*/
+/*			  If we have multiple threads running, we use	*/
+/*			  Thread-Local Storage to hold the pointer	*/
+/*									*/
+/************************************************************************/
+
+/*
+ *	Function pointer for returning errno pointer
+ */
+static int *Initialize_Errno(void);
+int *(*__WinCE_Errno_Pointer_Function)(void) = Initialize_Errno;
+
+/*
+ *	Static errno storage for the main thread
+ */
+static int Errno_Storage = 0;
+
+/*
+ *	Thread-Local storage slot for errno
+ */
+static int TLS_Errno_Slot = 0xffffffff;
+
+/*
+ *	Number of threads we have running and critical section protection
+ *	for manipulating it
+ */
+static int Number_Of_Threads = 0;
+static CRITICAL_SECTION Number_Of_Threads_Critical_Section;
+
+/*
+ *	For the main thread only -- return the errno pointer
+ */
+static int *Get_Main_Thread_Errno(void)
+{
+	return &Errno_Storage;
+}
+
+/*
+ *	When there is more than one thread -- return the errno pointer
+ */
+static int *Get_Thread_Errno(void)
+{
+	return (int *)TlsGetValue(TLS_Errno_Slot);
+}
+
+/*
+ *	Initialize a thread's errno
+ */
+static void Initialize_Thread_Errno(int *Errno_Pointer)
+{
+	/*
+	 *	Make sure we have a slot
+	 */
+	if (TLS_Errno_Slot == 0xffffffff) {
+		/*
+		 *	No: Get one
+		 */
+		TLS_Errno_Slot = (int)TlsAlloc();
+		if (TLS_Errno_Slot == 0xffffffff) ExitProcess(3);
+	}
+	/*
+	 *	We can safely check for 0 threads, because
+	 *	only the main thread will be initializing
+	 *	at this point.  Make sure the critical
+	 *	section that protects the number of threads
+	 *	is initialized
+	 */
+	if (Number_Of_Threads == 0)
+		InitializeCriticalSection(&Number_Of_Threads_Critical_Section);
+	/*
+	 *	Store the errno pointer
+	 */
+	if (TlsSetValue(TLS_Errno_Slot, (LPVOID)Errno_Pointer) == 0) ExitProcess(3);
+	/*
+	 *	Bump the number of threads
+	 */
+	EnterCriticalSection(&Number_Of_Threads_Critical_Section);
+	Number_Of_Threads++;
+	if (Number_Of_Threads > 1) {
+		/*
+		 *	We have threads other than the main thread:
+		 *	  Use thread-local storage
+		 */
+		__WinCE_Errno_Pointer_Function = Get_Thread_Errno;
+	}
+	LeaveCriticalSection(&Number_Of_Threads_Critical_Section);
+}
+
+/*
+ *	Initialize errno emulation on Windows/CE (Main thread)
+ */
+static int *Initialize_Errno(void)
+{
+	/*
+	 *	Initialize the main thread's errno in thread-local storage
+	 */
+	Initialize_Thread_Errno(&Errno_Storage);
+	/*
+	 *	Set the errno function to be the one that returns the
+	 *	main thread's errno
+	 */
+	__WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno;
+	/*
+	 *	Return the main thread's errno
+	 */
+	return &Errno_Storage;
+}
+
+/*
+ *	Initialize errno emulation on Windows/CE (New thread)
+ */
+void __WinCE_Errno_New_Thread(int *Errno_Pointer)
+{
+	Initialize_Thread_Errno(Errno_Pointer);
+}
+
+/*
+ *	Note that a thread has exited
+ */
+void __WinCE_Errno_Thread_Exit(void)
+{
+	/*
+	 *	Decrease the number of threads
+	 */
+	EnterCriticalSection(&Number_Of_Threads_Critical_Section);
+	Number_Of_Threads--;
+	if (Number_Of_Threads <= 1) {
+		/*
+		 *	We only have the main thread
+		 */
+		__WinCE_Errno_Pointer_Function = Get_Main_Thread_Errno;
+	}
+	LeaveCriticalSection(&Number_Of_Threads_Critical_Section);
+}
+
+
+char *
+strerror(int errnum)
+{
+	return "(strerror not implemented)";
+}
+
+#define FT_EPOCH (116444736000000000i64)
+#define	FT_TICKS (10000000i64)
+
+int
+_wstat(const WCHAR *path, struct _stat *buffer)
+{
+	WIN32_FIND_DATA data;
+	HANDLE handle;
+	WCHAR *p;
+
+	/* Fail if wildcard characters are specified */
+	if (wcscspn(path, L"?*") != wcslen(path))
+		return -1;
+
+	handle = FindFirstFile(path, &data);
+	if (handle == INVALID_HANDLE_VALUE) {
+		errno = GetLastError();
+		return -1;
+	}
+	FindClose(handle);
+
+	/* Found: Convert the file times */
+	buffer->st_mtime = convert_FILETIME_to_time_t(&data.ftLastWriteTime);
+	if (data.ftLastAccessTime.dwLowDateTime || data.ftLastAccessTime.dwHighDateTime)
+		buffer->st_atime = convert_FILETIME_to_time_t(&data.ftLastAccessTime);
+	else
+		buffer->st_atime = buffer->st_mtime;
+	if (data.ftCreationTime.dwLowDateTime || data.ftCreationTime.dwHighDateTime)
+		buffer->st_ctime = convert_FILETIME_to_time_t(&data.ftCreationTime);
+	else
+		buffer->st_ctime = buffer->st_mtime;
+
+	/* Convert the file modes */
+	buffer->st_mode = (unsigned short)((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG);
+	buffer->st_mode |= (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE);
+	if((p = wcsrchr(path, L'.')) != NULL) {
+		p++;
+		if (_wcsicmp(p, L".exe") == 0)
+			buffer->st_mode |= S_IEXEC;
+	}
+	buffer->st_mode |= (buffer->st_mode & 0700) >> 3;
+	buffer->st_mode |= (buffer->st_mode & 0700) >> 6;
+	/* Set the other information */
+	buffer->st_nlink = 1;
+	buffer->st_size = (unsigned long int)data.nFileSizeLow;
+	buffer->st_uid = 0;
+	buffer->st_gid = 0;
+	buffer->st_ino = 0 /*data.dwOID ?*/;
+	buffer->st_dev = 0;
+
+	return 0;	/* success */
+}
+
+/*
+ *	Helper function for cemodule -- do an fstat() operation on a Win32 File Handle
+ */
+int
+_fstat(int handle, struct _stat *st)
+{
+	BY_HANDLE_FILE_INFORMATION Data;
+
+	/*
+	 *	Get the file information
+	 */
+	if (!GetFileInformationByHandle((HANDLE)handle, &Data)) {
+		/*
+		 *	Return error
+		 */
+		errno = GetLastError();
+		return(-1);
+	}
+	/*
+	 *	Found: Convert the file times
+	 */
+	st->st_mtime=(time_t)((*(__int64*)&Data.ftLastWriteTime-FT_EPOCH)/FT_TICKS);
+	if(Data.ftLastAccessTime.dwLowDateTime || Data.ftLastAccessTime.dwHighDateTime)
+		st->st_atime=(time_t)((*(__int64*)&Data.ftLastAccessTime-FT_EPOCH)/FT_TICKS);
+	else
+		st->st_atime=st->st_mtime ;
+	if(Data.ftCreationTime.dwLowDateTime || Data.ftCreationTime.dwHighDateTime )
+		st->st_ctime=(time_t)((*(__int64*)&Data.ftCreationTime-FT_EPOCH)/FT_TICKS);
+	else
+		st->st_ctime=st->st_mtime ;
+	/*
+	 *	Convert the file modes
+	 */
+	st->st_mode = (unsigned short)((Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? (S_IFDIR | S_IEXEC) : S_IFREG);
+	st->st_mode |= (Data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : (S_IREAD | S_IWRITE);
+	st->st_mode |= (st->st_mode & 0700) >> 3;
+	st->st_mode |= (st->st_mode & 0700) >> 6;
+	/*
+	 *	Set the other information
+	 */
+	st->st_nlink=1;
+	st->st_size=(unsigned long int)Data.nFileSizeLow;
+	st->st_uid=0;
+	st->st_gid=0;
+	st->st_ino=0;
+	st->st_dev=0;
+	/*
+	 *	Return success
+	 */
+	return(0);
+}
+
+int _wopen(const wchar_t *filename, int oflag, ...)
+{
+	DWORD Access, ShareMode, CreationDisposition;
+	HANDLE Handle;
+	static int Modes[4] = {0, (GENERIC_READ | GENERIC_WRITE), GENERIC_READ, GENERIC_WRITE};
+
+	/*
+	 *	Calculate the CreateFile arguments
+	 */
+	Access = Modes[oflag & O_MODE_MASK];
+	ShareMode = (oflag & O_EXCL) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
+	if (oflag & O_TRUNC)
+		CreationDisposition = (oflag & O_CREAT) ? CREATE_ALWAYS : TRUNCATE_EXISTING;
+	else
+		CreationDisposition = (oflag & O_CREAT) ? CREATE_NEW : OPEN_EXISTING;
+
+	Handle = CreateFileW(filename, Access, ShareMode, NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
+
+	/*
+	 *	Deal with errors
+	 */
+	if (Handle == INVALID_HANDLE_VALUE) {
+		errno = GetLastError();
+		if ((errno == ERROR_ALREADY_EXISTS) || (errno == ERROR_FILE_EXISTS))
+			errno = ERROR_ALREADY_EXISTS;
+		return -1;
+	}
+	/*
+	 *	Return the handle
+	 */
+	return (int)Handle;
+}
+
+int
+_close(int handle)
+{
+	if(CloseHandle((HANDLE)handle))
+		return 0;
+	errno = GetLastError();
+	return -1;
+}
+
+int
+_write(int handle, const void *buffer, unsigned int count)
+{
+	DWORD numwritten = 0;
+	if(!WriteFile((HANDLE)handle, buffer, count, &numwritten, NULL)) {
+		errno = GetLastError();
+		return -1;
+	}
+	return numwritten;
+}
+
+int
+_read(int handle, void *buffer, unsigned int count)
+{
+	DWORD numread = 0;
+	if(!ReadFile((HANDLE)handle, buffer, count, &numread, NULL)) {
+		errno = GetLastError();
+		return -1;
+	}
+	return numread;
+}
+
+long
+_lseek(int handle, long offset, int origin)
+{
+	DWORD dwMoveMethod;
+	DWORD result;
+
+	switch(origin) {
+		default:
+			errno = EINVAL;
+			return -1L;
+		case SEEK_SET:
+			dwMoveMethod = FILE_BEGIN;
+			break;
+		case SEEK_CUR:
+			dwMoveMethod = FILE_CURRENT;
+			break;
+		case SEEK_END:
+			dwMoveMethod = FILE_END;
+			break;
+	}
+	result = SetFilePointer((HANDLE)handle, offset, NULL, dwMoveMethod);
+	if(result == 0xFFFFFFFF) {
+		errno = GetLastError();
+		return -1;
+	}
+	return (long)result;
+}
+
+int
+_wmkdir(const wchar_t *dirname)
+{
+	if(!CreateDirectoryW(dirname, NULL)) {
+		errno = GetLastError();
+		return -1;
+	}
+	return 0;
+}
+
+int
+_wremove(const wchar_t *filename)
+{
+	if(!DeleteFileW(filename)) {
+		errno = GetLastError();
+		return -1;
+	}
+	return 0;
+}
+
+int
+_wrename(const wchar_t *oldname, const wchar_t *newname)
+{
+	if(!MoveFileW(oldname, newname)) {
+		errno = GetLastError();
+		return -1;
+	}
+	return 0;
+}
+
+wchar_t *
+_wgetcwd(wchar_t *buffer, int maxlen)
+{
+	wchar_t *result;
+	WCHAR wszPath[MAX_PATH + 1];
+	WCHAR *p;
+
+	if(!GetModuleFileNameW(NULL, wszPath, MAX_PATH + 1)) {
+		errno = GetLastError();
+		return NULL;
+	}
+	/* Remove the filename part of the path to leave the directory */
+	p = wcsrchr(wszPath, L'\\');
+	if(p)
+		*p = L'\0';
+
+	if(buffer == NULL)
+		result = _wcsdup(wszPath);
+	else if(wcslen(wszPath) + 1 > (size_t)maxlen) {
+		result = NULL;
+		errno = ERROR_INSUFFICIENT_BUFFER;
+	} else {
+		wcsncpy(buffer, wszPath, maxlen);
+		buffer[maxlen - 1] = L'\0';
+		result = buffer;
+	}
+	return result;
+}
+
+/*
+ *	The missing "C" runtime gmtime() function
+ */
+struct tm *gmtime(const time_t *TimeP)
+{
+	FILETIME File_Time;
+
+	/*
+	 *	Deal with null time pointer
+	 */
+	if (!TimeP) return(NULL);
+	/*
+	 *	time_t -> FILETIME -> tm
+	 */
+	Convert_time_t_To_FILETIME(*TimeP, &File_Time);
+	return(Convert_FILETIME_To_tm(&File_Time));
+}
+
+/*
+ *	The missing "C" runtime localtime() function
+ */
+struct tm *localtime(const time_t *TimeP)
+{
+	FILETIME File_Time, Local_File_Time;
+
+	/*
+	 *	Deal with null time pointer
+	 */
+	if (!TimeP) return(NULL);
+	/*
+	 *	time_t -> FILETIME -> Local FILETIME -> tm
+	 */
+	Convert_time_t_To_FILETIME(*TimeP, &File_Time);
+	FileTimeToLocalFileTime(&File_Time, &Local_File_Time);
+	return(Convert_FILETIME_To_tm(&Local_File_Time));
+}
+
+/*
+ *	The missing "C" runtime mktime() function
+ */
+time_t mktime(struct tm *tm)
+{
+	FILETIME *Local_File_Time;
+	FILETIME File_Time;
+
+	/*
+	 *	tm -> Local FILETIME -> FILETIME -> time_t
+	 */
+	Local_File_Time = Convert_tm_To_FILETIME(tm);
+	LocalFileTimeToFileTime(Local_File_Time, &File_Time);
+	return(convert_FILETIME_to_time_t(&File_Time));
+}
+
+/*
+ *	Missing "C" runtime time() function
+ */
+time_t time(time_t *TimeP)
+{
+	SYSTEMTIME System_Time;
+	FILETIME File_Time;
+	time_t Result;
+
+	/*
+	 *	Get the current system time
+	 */
+	GetSystemTime(&System_Time);
+	/*
+	 *	SYSTEMTIME -> FILETIME -> time_t
+	 */
+	SystemTimeToFileTime(&System_Time, &File_Time);
+	Result = convert_FILETIME_to_time_t(&File_Time);
+	/*
+	 *	Return the time_t
+	 */
+	if (TimeP) *TimeP = Result;
+	return(Result);
+}
+
+static char Standard_Name[32] = "GMT";
+static char Daylight_Name[32] = "GMT";
+char *tzname[2] = {Standard_Name, Daylight_Name};
+long timezone = 0;
+int daylight = 0;
+
+void tzset(void)
+{
+	TIME_ZONE_INFORMATION Info;
+	int Result;
+
+	/*
+	 *	Get our current timezone information
+	 */
+	Result = GetTimeZoneInformation(&Info);
+	switch(Result) {
+		/*
+		 *	We are on standard time
+		 */
+		case TIME_ZONE_ID_STANDARD:
+			daylight = 0;
+			break;
+		/*
+		 *	We are on daylight savings time
+		 */
+		case TIME_ZONE_ID_DAYLIGHT:
+			daylight = 1;
+			break;
+		/*
+		 *	We don't know the timezone information (leave it GMT)
+		 */
+		default: return;
+	}
+	/*
+	 *	Extract the timezone information
+	 */
+	timezone = Info.Bias * 60;
+	if (Info.StandardName[0])
+		WideCharToMultiByte(CP_ACP, 0, Info.StandardName, -1, Standard_Name, sizeof(Standard_Name) - 1, NULL, NULL);
+	if (Info.DaylightName[0])
+		WideCharToMultiByte(CP_ACP, 0, Info.DaylightName, -1, Daylight_Name, sizeof(Daylight_Name) - 1, NULL, NULL);
+}
+
+/*** strftime() from newlib libc/time/strftime.c ***/
+
+/*
+ * Sane snprintf(). Acts like snprintf(), but never return -1 or the
+ * value bigger than supplied buffer.
+ */
+static int
+Snprintf(char *buf, size_t buflen, const char *fmt, ...)
+{
+	va_list		ap;
+	int		n;
+
+	if (buflen == 0)
+		return (0);
+
+	va_start(ap, fmt);
+	n = _vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+
+	if (n < 0 || n > (int) buflen - 1) {
+		n = buflen - 1;
+	}
+	buf[n] = '\0';
+
+	return (n);
+}
+
+#define snprintf Snprintf
+
+/* from libc/include/_ansi.h */
+#define _CONST const
+#define	_DEFUN(name, arglist, args)	name(args)
+#define	_AND		,
+/* from libc/time/local.h */
+#define TZ_LOCK
+#define TZ_UNLOCK
+#define _tzname tzname
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#define YEAR_BASE	1900
+#define SECSPERMIN	60L
+#define MINSPERHOUR	60L
+#define HOURSPERDAY	24L
+#define SECSPERHOUR	(SECSPERMIN * MINSPERHOUR)
+
+/*
+ * strftime.c
+ * Original Author:	G. Haley
+ * Additions from:	Eric Blake
+ *
+ * Places characters into the array pointed to by s as controlled by the string
+ * pointed to by format. If the total number of resulting characters including
+ * the terminating null character is not more than maxsize, returns the number
+ * of characters placed into the array pointed to by s (not including the
+ * terminating null character); otherwise zero is returned and the contents of
+ * the array indeterminate.
+ */
+
+/*
+FUNCTION
+<<strftime>>---flexible calendar time formatter
+
+INDEX
+	strftime
+
+ANSI_SYNOPSIS
+	#include <time.h>
+	size_t strftime(char *<[s]>, size_t <[maxsize]>,
+			const char *<[format]>, const struct tm *<[timp]>);
+
+TRAD_SYNOPSIS
+	#include <time.h>
+	size_t strftime(<[s]>, <[maxsize]>, <[format]>, <[timp]>)
+	char *<[s]>;
+	size_t <[maxsize]>;
+	char *<[format]>;
+	struct tm *<[timp]>;
+
+DESCRIPTION
+<<strftime>> converts a <<struct tm>> representation of the time (at
+<[timp]>) into a null-terminated string, starting at <[s]> and occupying
+no more than <[maxsize]> characters.
+
+You control the format of the output using the string at <[format]>.
+<<*<[format]>>> can contain two kinds of specifications: text to be
+copied literally into the formatted string, and time conversion
+specifications.  Time conversion specifications are two- and
+three-character sequences beginning with `<<%>>' (use `<<%%>>' to
+include a percent sign in the output).  Each defined conversion
+specification selects only the specified field(s) of calendar time
+data from <<*<[timp]>>>, and converts it to a string in one of the
+following ways:
+
+o+
+o %a
+A three-letter abbreviation for the day of the week. [tm_wday]
+
+o %A
+The full name for the day of the week, one of `<<Sunday>>',
+`<<Monday>>', `<<Tuesday>>', `<<Wednesday>>', `<<Thursday>>',
+`<<Friday>>', or `<<Saturday>>'. [tm_wday]
+
+o %b
+A three-letter abbreviation for the month name. [tm_mon]
+
+o %B
+The full name of the month, one of `<<January>>', `<<February>>',
+`<<March>>', `<<April>>', `<<May>>', `<<June>>', `<<July>>',
+`<<August>>', `<<September>>', `<<October>>', `<<November>>',
+`<<December>>'. [tm_mon]
+
+o %c
+A string representing the complete date and time, in the form
+`<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13
+1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday]
+
+o %C
+The century, that is, the year divided by 100 then truncated.  For
+4-digit years, the result is zero-padded and exactly two characters;
+but for other years, there may a negative sign or more digits.  In
+this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
+ 
+o %d
+The day of the month, formatted with two digits (from `<<01>>' to
+`<<31>>'). [tm_mday]
+
+o %D
+A string representing the date, in the form `<<"%m/%d/%y">>'.
+[tm_mday, tm_mon, tm_year]
+
+o %e
+The day of the month, formatted with leading space if single digit
+(from `<<1>>' to `<<31>>'). [tm_mday]
+
+o %E<<x>>
+In some locales, the E modifier selects alternative representations of
+certain modifiers <<x>>.  But in the "C" locale supported by newlib,
+it is ignored, and treated as %<<x>>.
+
+o %F
+A string representing the ISO 8601:2000 date format, in the form
+`<<"%Y-%m-%d">>'. [tm_mday, tm_mon, tm_year]
+
+o %g
+The last two digits of the week-based year, see specifier %G (from
+`<<00>>' to `<<99>>'). [tm_year, tm_wday, tm_yday]
+
+o %G
+The week-based year. In the ISO 8601:2000 calendar, week 1 of the year
+includes January 4th, and begin on Mondays. Therefore, if January 1st,
+2nd, or 3rd falls on a Sunday, that day and earlier belong to the last
+week of the previous year; and if December 29th, 30th, or 31st falls
+on Monday, that day and later belong to week 1 of the next year.  For
+consistency with %Y, it always has at least four characters. 
+Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
+Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
+
+o %h
+A three-letter abbreviation for the month name (synonym for
+"%b"). [tm_mon]
+
+o %H
+The hour (on a 24-hour clock), formatted with two digits (from
+`<<00>>' to `<<23>>'). [tm_hour]
+
+o %I
+The hour (on a 12-hour clock), formatted with two digits (from
+`<<01>>' to `<<12>>'). [tm_hour]
+
+o %j
+The count of days in the year, formatted with three digits
+(from `<<001>>' to `<<366>>'). [tm_yday]
+
+o %k
+The hour (on a 24-hour clock), formatted with leading space if single
+digit (from `<<0>>' to `<<23>>'). Non-POSIX extension. [tm_hour]
+
+o %l
+The hour (on a 12-hour clock), formatted with leading space if single
+digit (from `<<1>>' to `<<12>>'). Non-POSIX extension. [tm_hour]
+
+o %m
+The month number, formatted with two digits (from `<<01>>' to `<<12>>').
+[tm_mon]
+
+o %M
+The minute, formatted with two digits (from `<<00>>' to `<<59>>'). [tm_min]
+
+o %n
+A newline character (`<<\n>>').
+
+o %O<<x>>
+In some locales, the O modifier selects alternative digit characters
+for certain modifiers <<x>>.  But in the "C" locale supported by newlib, it
+is ignored, and treated as %<<x>>.
+
+o %p
+Either `<<AM>>' or `<<PM>>' as appropriate. [tm_hour]
+
+o %r
+The 12-hour time, to the second.  Equivalent to "%I:%M:%S %p". [tm_sec,
+tm_min, tm_hour]
+
+o %R
+The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
+
+o %S
+The second, formatted with two digits (from `<<00>>' to `<<60>>').  The
+value 60 accounts for the occasional leap second. [tm_sec]
+
+o %t
+A tab character (`<<\t>>').
+
+o %T
+The 24-hour time, to the second.  Equivalent to "%H:%M:%S". [tm_sec,
+tm_min, tm_hour]
+
+o %u
+The weekday as a number, 1-based from Monday (from `<<1>>' to
+`<<7>>'). [tm_wday]
+
+o %U
+The week number, where weeks start on Sunday, week 1 contains the first
+Sunday in a year, and earlier days are in week 0.  Formatted with two
+digits (from `<<00>>' to `<<53>>').  See also <<%W>>. [tm_wday, tm_yday]
+
+o %V
+The week number, where weeks start on Monday, week 1 contains January 4th,
+and earlier days are in the previous year.  Formatted with two digits
+(from `<<01>>' to `<<53>>').  See also <<%G>>. [tm_year, tm_wday, tm_yday]
+
+o %w
+The weekday as a number, 0-based from Sunday (from `<<0>>' to `<<6>>').
+[tm_wday]
+
+o %W
+The week number, where weeks start on Monday, week 1 contains the first
+Monday in a year, and earlier days are in week 0.  Formatted with two
+digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday]
+
+o %x
+A string representing the complete date, equivalent to "%m/%d/%y".
+[tm_mon, tm_mday, tm_year]
+
+o %X
+A string representing the full time of day (hours, minutes, and
+seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour]
+
+o %y
+The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year]
+
+o %Y
+The full year, equivalent to <<%C%y>>.  It will always have at least four
+characters, but may have more.  The year is accurate even when tm_year
+added to the offset of 1900 overflows an int. [tm_year]
+
+o %z
+The offset from UTC.  The format consists of a sign (negative is west of
+Greewich), two characters for hour, then two characters for minutes
+(-hhmm or +hhmm).  If tm_isdst is negative, the offset is unknown and no
+output is generated; if it is zero, the offset is the standard offset for
+the current time zone; and if it is positive, the offset is the daylight
+savings offset for the current timezone. The offset is determined from
+the TZ environment variable, as if by calling tzset(). [tm_isdst]
+
+o %Z
+The time zone name.  If tm_isdst is negative, no output is generated.
+Otherwise, the time zone name is based on the TZ environment variable,
+as if by calling tzset(). [tm_isdst]
+
+o %%
+A single character, `<<%>>'.
+o-
+
+RETURNS
+When the formatted time takes up no more than <[maxsize]> characters,
+the result is the length of the formatted string.  Otherwise, if the
+formatting operation was abandoned due to lack of room, the result is
+<<0>>, and the string starting at <[s]> corresponds to just those
+parts of <<*<[format]>>> that could be completely filled in within the
+<[maxsize]> limit.
+
+PORTABILITY
+ANSI C requires <<strftime>>, but does not specify the contents of
+<<*<[s]>>> when the formatted string would require more than
+<[maxsize]> characters.  Unrecognized specifiers and fields of
+<<timp>> that are out of range cause undefined results.  Since some
+formats expand to 0 bytes, it is wise to set <<*<[s]>>> to a nonzero
+value beforehand to distinguish between failure and an empty string.
+This implementation does not support <<s>> being NULL, nor overlapping
+<<s>> and <<format>>.
+
+<<strftime>> requires no supporting OS subroutines.
+*/
+
+static _CONST int dname_len[7] =
+{6, 6, 7, 9, 8, 6, 8};
+
+static _CONST char *_CONST dname[7] =
+{"Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"};
+
+static _CONST int mname_len[12] =
+{7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8};
+
+static _CONST char *_CONST mname[12] =
+{"January", "February", "March", "April",
+ "May", "June", "July", "August", "September", "October", "November",
+ "December"};
+
+/* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return
+   -1, 0, or 1 as the adjustment to add to the year for the ISO week
+   numbering used in "%g%G%V", avoiding overflow.  */
+static int
+_DEFUN (iso_year_adjust, (tim_p),
+	_CONST struct tm *tim_p)
+{
+  /* Account for fact that tm_year==0 is year 1900.  */
+  int leap = isleap (tim_p->tm_year + (YEAR_BASE
+				       - (tim_p->tm_year < 0 ? 0 : 2000)));
+
+  /* Pack the yday, wday, and leap year into a single int since there are so
+     many disparate cases.  */
+#define PACK(yd, wd, lp) (((yd) << 4) + (wd << 1) + (lp))
+  switch (PACK (tim_p->tm_yday, tim_p->tm_wday, leap))
+    {
+    case PACK (0, 5, 0): /* Jan 1 is Fri, not leap.  */
+    case PACK (0, 6, 0): /* Jan 1 is Sat, not leap.  */
+    case PACK (0, 0, 0): /* Jan 1 is Sun, not leap.  */
+    case PACK (0, 5, 1): /* Jan 1 is Fri, leap year.  */
+    case PACK (0, 6, 1): /* Jan 1 is Sat, leap year.  */
+    case PACK (0, 0, 1): /* Jan 1 is Sun, leap year.  */
+    case PACK (1, 6, 0): /* Jan 2 is Sat, not leap.  */
+    case PACK (1, 0, 0): /* Jan 2 is Sun, not leap.  */
+    case PACK (1, 6, 1): /* Jan 2 is Sat, leap year.  */
+    case PACK (1, 0, 1): /* Jan 2 is Sun, leap year.  */
+    case PACK (2, 0, 0): /* Jan 3 is Sun, not leap.  */
+    case PACK (2, 0, 1): /* Jan 3 is Sun, leap year.  */
+      return -1; /* Belongs to last week of previous year.  */
+    case PACK (362, 1, 0): /* Dec 29 is Mon, not leap.  */
+    case PACK (363, 1, 1): /* Dec 29 is Mon, leap year.  */
+    case PACK (363, 1, 0): /* Dec 30 is Mon, not leap.  */
+    case PACK (363, 2, 0): /* Dec 30 is Tue, not leap.  */
+    case PACK (364, 1, 1): /* Dec 30 is Mon, leap year.  */
+    case PACK (364, 2, 1): /* Dec 30 is Tue, leap year.  */
+    case PACK (364, 1, 0): /* Dec 31 is Mon, not leap.  */
+    case PACK (364, 2, 0): /* Dec 31 is Tue, not leap.  */
+    case PACK (364, 3, 0): /* Dec 31 is Wed, not leap.  */
+    case PACK (365, 1, 1): /* Dec 31 is Mon, leap year.  */
+    case PACK (365, 2, 1): /* Dec 31 is Tue, leap year.  */
+    case PACK (365, 3, 1): /* Dec 31 is Wed, leap year.  */
+      return 1; /* Belongs to first week of next year.  */
+    }
+  return 0; /* Belongs to specified year.  */
+#undef PACK
+}
+
+size_t
+_DEFUN (strftime, (s, maxsize, format, tim_p),
+	char *s _AND
+	size_t maxsize _AND
+	_CONST char *format _AND
+	_CONST struct tm *tim_p)
+{
+  size_t count = 0;
+  int i;
+
+  for (;;)
+    {
+      while (*format && *format != '%')
+	{
+	  if (count < maxsize - 1)
+	    s[count++] = *format++;
+	  else
+	    return 0;
+	}
+
+      if (*format == '\0')
+	break;
+
+      format++;
+      if (*format == 'E' || *format == 'O')
+	format++;
+
+      switch (*format)
+	{
+	case 'a':
+	  for (i = 0; i < 3; i++)
+	    {
+	      if (count < maxsize - 1)
+		s[count++] =
+		  dname[tim_p->tm_wday][i];
+	      else
+		return 0;
+	    }
+	  break;
+	case 'A':
+	  for (i = 0; i < dname_len[tim_p->tm_wday]; i++)
+	    {
+	      if (count < maxsize - 1)
+		s[count++] =
+		  dname[tim_p->tm_wday][i];
+	      else
+		return 0;
+	    }
+	  break;
+	case 'b':
+	case 'h':
+	  for (i = 0; i < 3; i++)
+	    {
+	      if (count < maxsize - 1)
+		s[count++] =
+		  mname[tim_p->tm_mon][i];
+	      else
+		return 0;
+	    }
+	  break;
+	case 'B':
+	  for (i = 0; i < mname_len[tim_p->tm_mon]; i++)
+	    {
+	      if (count < maxsize - 1)
+		s[count++] =
+		  mname[tim_p->tm_mon][i];
+	      else
+		return 0;
+	    }
+	  break;
+	case 'c':
+	  {
+	    /* Length is not known because of %C%y, so recurse. */
+	    size_t adjust = strftime (&s[count], maxsize - count,
+				      "%a %b %e %H:%M:%S %C%y", tim_p);
+	    if (adjust > 0)
+	      count += adjust;
+	    else
+	      return 0;
+	  }
+	  break;
+	case 'C':
+	  {
+	    /* Examples of (tm_year + YEAR_BASE) that show how %Y == %C%y
+	       with 32-bit int.
+	       %Y		%C		%y
+	       2147485547	21474855	47
+	       10000		100		00
+	       9999		99		99
+	       0999		09		99
+	       0099		00		99
+	       0001		00		01
+	       0000		00		00
+	       -001		-0		01
+	       -099		-0		99
+	       -999		-9		99
+	       -1000		-10		00
+	       -10000		-100		00
+	       -2147481748	-21474817	48
+
+	       Be careful of both overflow and sign adjustment due to the
+	       asymmetric range of years.
+	    */
+	    int neg = tim_p->tm_year < -YEAR_BASE;
+	    int century = tim_p->tm_year >= 0
+	      ? tim_p->tm_year / 100 + YEAR_BASE / 100
+	      : abs (tim_p->tm_year + YEAR_BASE) / 100;
+            count += snprintf (&s[count], maxsize - count, "%s%.*d",
+                               neg ? "-" : "", 2 - neg, century);
+            if (count >= maxsize)
+              return 0;
+	  }
+	  break;
+	case 'd':
+	case 'e':
+	  if (count < maxsize - 2)
+	    {
+	      sprintf (&s[count], *format == 'd' ? "%.2d" : "%2d",
+		       tim_p->tm_mday);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'D':
+	case 'x':
+	  /* %m/%d/%y */
+	  if (count < maxsize - 8)
+	    {
+	      sprintf (&s[count], "%.2d/%.2d/%.2d",
+		       tim_p->tm_mon + 1, tim_p->tm_mday,
+		       tim_p->tm_year >= 0 ? tim_p->tm_year % 100
+		       : abs (tim_p->tm_year + YEAR_BASE) % 100);
+	      count += 8;
+	    }
+	  else
+	    return 0;
+	  break;
+        case 'F':
+	  {
+	    /* Length is not known because of %C%y, so recurse. */
+	    size_t adjust = strftime (&s[count], maxsize - count,
+				      "%C%y-%m-%d", tim_p);
+	    if (adjust > 0)
+	      count += adjust;
+	    else
+	      return 0;
+	  }
+          break;
+        case 'g':
+	  if (count < maxsize - 2)
+	    {
+	      /* Be careful of both overflow and negative years, thanks to
+		 the asymmetric range of years.  */
+	      int adjust = iso_year_adjust (tim_p);
+	      int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
+		: abs (tim_p->tm_year + YEAR_BASE) % 100;
+	      if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
+		adjust = 1;
+	      else if (adjust > 0 && tim_p->tm_year < -YEAR_BASE)
+		adjust = -1;
+	      sprintf (&s[count], "%.2d",
+		       ((year + adjust) % 100 + 100) % 100);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+          break;
+        case 'G':
+	  {
+	    /* See the comments for 'C' and 'Y'; this is a variable length
+	       field.  Although there is no requirement for a minimum number
+	       of digits, we use 4 for consistency with 'Y'.  */
+	    int neg = tim_p->tm_year < -YEAR_BASE;
+	    int adjust = iso_year_adjust (tim_p);
+	    int century = tim_p->tm_year >= 0
+	      ? tim_p->tm_year / 100 + YEAR_BASE / 100
+	      : abs (tim_p->tm_year + YEAR_BASE) / 100;
+	    int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
+	      : abs (tim_p->tm_year + YEAR_BASE) % 100;
+	    if (adjust < 0 && tim_p->tm_year <= -YEAR_BASE)
+	      neg = adjust = 1;
+	    else if (adjust > 0 && neg)
+	      adjust = -1;
+	    year += adjust;
+	    if (year == -1)
+	      {
+		year = 99;
+		--century;
+	      }
+	    else if (year == 100)
+	      {
+		year = 0;
+		++century;
+	      }
+            count += snprintf (&s[count], maxsize - count, "%s%.*d%.2d",
+                               neg ? "-" : "", 2 - neg, century, year);
+            if (count >= maxsize)
+              return 0;
+	  }
+          break;
+	case 'H':
+	case 'k':
+	  if (count < maxsize - 2)
+	    {
+	      sprintf (&s[count], *format == 'k' ? "%2d" : "%.2d",
+		       tim_p->tm_hour);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'I':
+	case 'l':
+	  if (count < maxsize - 2)
+	    {
+	      if (tim_p->tm_hour == 0 ||
+		  tim_p->tm_hour == 12)
+		{
+		  s[count++] = '1';
+		  s[count++] = '2';
+		}
+	      else
+		{
+		  sprintf (&s[count], *format == 'I' ? "%.2d" : "%2d",
+			   tim_p->tm_hour % 12);
+		  count += 2;
+		}
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'j':
+	  if (count < maxsize - 3)
+	    {
+	      sprintf (&s[count], "%.3d",
+		       tim_p->tm_yday + 1);
+	      count += 3;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'm':
+	  if (count < maxsize - 2)
+	    {
+	      sprintf (&s[count], "%.2d",
+		       tim_p->tm_mon + 1);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'M':
+	  if (count < maxsize - 2)
+	    {
+	      sprintf (&s[count], "%.2d",
+		       tim_p->tm_min);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'n':
+	  if (count < maxsize - 1)
+	    s[count++] = '\n';
+	  else
+	    return 0;
+	  break;
+	case 'p':
+	  if (count < maxsize - 2)
+	    {
+	      if (tim_p->tm_hour < 12)
+		s[count++] = 'A';
+	      else
+		s[count++] = 'P';
+
+	      s[count++] = 'M';
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'r':
+	  if (count < maxsize - 11)
+	    {
+	      if (tim_p->tm_hour == 0 ||
+		  tim_p->tm_hour == 12)
+		{
+		  s[count++] = '1';
+		  s[count++] = '2';
+		}
+	      else
+		{
+		  sprintf (&s[count], "%.2d", tim_p->tm_hour % 12);
+		  count += 2;
+		}
+	      s[count++] = ':';
+	      sprintf (&s[count], "%.2d",
+		       tim_p->tm_min);
+	      count += 2;
+	      s[count++] = ':';
+	      sprintf (&s[count], "%.2d",
+		       tim_p->tm_sec);
+	      count += 2;
+	      s[count++] = ' ';
+	      if (tim_p->tm_hour < 12)
+		s[count++] = 'A';
+	      else
+		s[count++] = 'P';
+
+	      s[count++] = 'M';
+	    }
+	  else
+	    return 0;
+	  break;
+        case 'R':
+          if (count < maxsize - 5)
+            {
+              sprintf (&s[count], "%.2d:%.2d", tim_p->tm_hour, tim_p->tm_min);
+              count += 5;
+            }
+          else
+            return 0;
+          break;
+	case 'S':
+	  if (count < maxsize - 2)
+	    {
+	      sprintf (&s[count], "%.2d",
+		       tim_p->tm_sec);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 't':
+	  if (count < maxsize - 1)
+	    s[count++] = '\t';
+	  else
+	    return 0;
+	  break;
+        case 'T':
+        case 'X':
+          if (count < maxsize - 8)
+            {
+              sprintf (&s[count], "%.2d:%.2d:%.2d", tim_p->tm_hour,
+                       tim_p->tm_min, tim_p->tm_sec);
+              count += 8;
+            }
+          else
+            return 0;
+          break;
+        case 'u':
+          if (count < maxsize - 1)
+            {
+              if (tim_p->tm_wday == 0)
+                s[count++] = '7';
+              else
+                s[count++] = '0' + tim_p->tm_wday;
+            }
+          else
+            return 0;
+          break;
+	case 'U':
+	  if (count < maxsize - 2)
+	    {
+	      sprintf (&s[count], "%.2d",
+		       (tim_p->tm_yday + 7 -
+			tim_p->tm_wday) / 7);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+        case 'V':
+	  if (count < maxsize - 2)
+	    {
+	      int adjust = iso_year_adjust (tim_p);
+	      int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
+	      int week = (tim_p->tm_yday + 10 - wday) / 7;
+	      if (adjust > 0)
+		week = 1;
+	      else if (adjust < 0)
+		/* Previous year has 53 weeks if current year starts on
+		   Fri, and also if current year starts on Sat and
+		   previous year was leap year.  */
+		week = 52 + (4 >= (wday - tim_p->tm_yday
+				   - isleap (tim_p->tm_year
+					     + (YEAR_BASE - 1
+						- (tim_p->tm_year < 0
+						   ? 0 : 2000)))));
+	      sprintf (&s[count], "%.2d", week);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+          break;
+	case 'w':
+	  if (count < maxsize - 1)
+            s[count++] = '0' + tim_p->tm_wday;
+	  else
+	    return 0;
+	  break;
+	case 'W':
+	  if (count < maxsize - 2)
+	    {
+	      int wday = (tim_p->tm_wday) ? tim_p->tm_wday - 1 : 6;
+	      sprintf (&s[count], "%.2d",
+		       (tim_p->tm_yday + 7 - wday) / 7);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'y':
+	  if (count < maxsize - 2)
+	    {
+	      /* Be careful of both overflow and negative years, thanks to
+		 the asymmetric range of years.  */
+	      int year = tim_p->tm_year >= 0 ? tim_p->tm_year % 100
+		: abs (tim_p->tm_year + YEAR_BASE) % 100;
+	      sprintf (&s[count], "%.2d", year);
+	      count += 2;
+	    }
+	  else
+	    return 0;
+	  break;
+	case 'Y':
+	  {
+	    /* Length is not known because of %C%y, so recurse. */
+	    size_t adjust = strftime (&s[count], maxsize - count,
+				      "%C%y", tim_p);
+	    if (adjust > 0)
+	      count += adjust;
+	    else
+	      return 0;
+	  }
+	  break;
+        case 'z':
+#ifndef _WIN32_WCE
+          if (tim_p->tm_isdst >= 0)
+            {
+	      if (count < maxsize - 5)
+		{
+		  long offset;
+		  __tzinfo_type *tz = __gettzinfo ();
+		  TZ_LOCK;
+		  /* The sign of this is exactly opposite the envvar TZ.  We
+		     could directly use the global _timezone for tm_isdst==0,
+		     but have to use __tzrule for daylight savings.  */
+		  offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
+		  TZ_UNLOCK;
+		  sprintf (&s[count], "%+03ld%.2ld", offset / SECSPERHOUR,
+			   labs (offset / SECSPERMIN) % 60L);
+		  count += 5;
+		}
+	      else
+		return 0;
+            }
+          break;
+#endif
+	case 'Z':
+	  if (tim_p->tm_isdst >= 0)
+	    {
+	      int size;
+	      TZ_LOCK;
+	      size = strlen(_tzname[tim_p->tm_isdst > 0]);
+	      for (i = 0; i < size; i++)
+		{
+		  if (count < maxsize - 1)
+		    s[count++] = _tzname[tim_p->tm_isdst > 0][i];
+		  else
+		    {
+		      TZ_UNLOCK;
+		      return 0;
+		    }
+		}
+	      TZ_UNLOCK;
+	    }
+	  break;
+	case '%':
+	  if (count < maxsize - 1)
+	    s[count++] = '%';
+	  else
+	    return 0;
+	  break;
+	}
+      if (*format)
+	format++;
+      else
+	break;
+    }
+  if (maxsize)
+    s[count] = '\0';
+
+  return count;
+}

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/compat_wince.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,145 @@
+
+#ifndef INCLUDE_WINCE_COMPAT_H
+#define INCLUDE_WINCE_COMPAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*** ANSI C library ***/
+
+/* Missing ANSI C definitions */
+
+#define BUFSIZ 4096
+
+#define ENOMEM ERROR_NOT_ENOUGH_MEMORY
+#define EBADF ERROR_INVALID_HANDLE
+#define EINVAL ERROR_INVALID_PARAMETER
+#define ENOENT ERROR_FILE_NOT_FOUND
+#define ERANGE ERROR_INSUFFICIENT_BUFFER
+#define EINTR WSAEINTR
+
+/*
+ *	Because we need a per-thread errno, we define a function
+ *	pointer that we can call to return a pointer to the errno
+ *	for the current thread.  Then we define a macro for errno
+ *	that dereferences this function's result.
+ *
+ *	This makes it syntactically just like the "real" errno.
+ *
+ *	Using a function pointer allows us to use a very fast
+ *	function when there are no threads running and a slower
+ *	function when there are multiple threads running.
+ */
+void __WinCE_Errno_New_Thread(int *Errno_Pointer);
+void __WinCE_Errno_Thread_Exit(void);
+extern int *(*__WinCE_Errno_Pointer_Function)(void);
+
+#define	errno (*(*__WinCE_Errno_Pointer_Function)())
+
+char *strerror(int errnum);
+
+struct tm {
+	int tm_sec;     /* seconds after the minute - [0,59] */
+	int tm_min;     /* minutes after the hour - [0,59] */
+	int tm_hour;    /* hours since midnight - [0,23] */
+	int tm_mday;    /* day of the month - [1,31] */
+	int tm_mon;     /* months since January - [0,11] */
+	int tm_year;    /* years since 1900 */
+	int tm_wday;    /* days since Sunday - [0,6] */
+	int tm_yday;    /* days since January 1 - [0,365] */
+	int tm_isdst;   /* daylight savings time flag */
+};
+
+struct tm *gmtime(const time_t *TimeP); /* for future use */
+struct tm *localtime(const time_t *TimeP);
+time_t mktime(struct tm *tm);
+time_t time(time_t *TimeP);
+
+size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *tim_p);
+
+int _wrename(const wchar_t *oldname, const wchar_t *newname);
+int _wremove(const wchar_t *filename);
+
+/* Environment variables are not supported */
+#define getenv(x) (NULL)
+
+/* Redefine fileno so that it returns an integer */
+#undef fileno
+#define fileno(f) (int)_fileno(f)
+
+/* Signals are not supported */
+#define signal(num, handler) (0)
+#define SIGTERM 0
+#define SIGINT 0
+
+
+/*** POSIX API ***/
+
+/* Missing POSIX definitions */
+
+#define FILENAME_MAX MAX_PATH
+
+struct _stat {
+	unsigned long st_size;
+	unsigned long st_ino;
+	int st_mode;
+	unsigned long st_atime;
+	unsigned long st_mtime;
+	unsigned long st_ctime;
+	unsigned short st_dev;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+};
+
+#define S_IFMT   0170000
+#define S_IFDIR  0040000
+#define S_IFREG  0100000
+#define S_IEXEC  0000100
+#define S_IWRITE 0000200 
+#define S_IREAD  0000400
+
+#define _S_IFDIR S_IFDIR	/* MSVCRT compatibilit */
+
+int _fstat(int handle, struct _stat *buffer);
+int _wstat(const wchar_t *path, struct _stat *buffer);
+
+#define stat _stat	/* NOTE: applies to _stat() and also struct _stat */
+#define fstat _fstat
+
+#define	O_RDWR		(1<<0)
+#define	O_RDONLY	(2<<0)
+#define	O_WRONLY	(3<<0)
+#define	O_MODE_MASK	(3<<0)
+#define	O_TRUNC		(1<<2)
+#define	O_EXCL		(1<<3)
+#define	O_CREAT		(1<<4)
+#define O_BINARY 0
+
+int _wopen(const wchar_t *filename, int oflag, ...);
+int _close(int handle);
+int _write(int handle, const void *buffer, unsigned int count);
+int _read(int handle, void *buffer, unsigned int count);
+long _lseek(int handle, long offset, int origin);
+
+#define close _close
+#define write _write
+#define read _read
+#define lseek _lseek
+
+/* WinCE has only a Unicode version of this function */
+FILE *fdopen(int handle, const char *mode);
+
+int _wmkdir(const wchar_t *dirname);
+
+/* WinCE has no concept of current directory so we return a constant path */
+wchar_t *_wgetcwd(wchar_t *buffer, int maxlen);
+
+#define freopen(path, mode, stream) assert(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* INCLUDE_WINCE_COMPAT_H */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/config.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/config.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/config.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,30 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#ifndef CONFIG_HEADER_DEFINED
+#define	CONFIG_HEADER_DEFINED
+
+#define	VERSION		"1.42"		/* Version			*/
+#define	CONFIG_FILE	"shttpd.conf"	/* Configuration file		*/
+#define	HTPASSWD	".htpasswd"	/* Passwords file name		*/
+#define	URI_MAX		16384		/* Default max request size	*/
+//#define	LISTENING_PORTS	"80"		/* Default listening ports	*/	//@@	Modified -> Port 80 can be used only if the program is executed in root mode
+#define	LISTENING_PORTS	"10000"		/* Default listening ports	*/
+#define	INDEX_FILES	"index.html,index.htm,index.php,index.cgi"
+#define	CGI_EXT		"cgi,pl,php"	/* Default CGI extensions	*/
+#define	SSI_EXT		"shtml,shtm"	/* Default SSI extensions	*/
+#define	REALM		"mydomain.com"	/* Default authentication realm	*/
+#define	DELIM_CHARS	","		/* Separators for lists		*/
+#define	EXPIRE_TIME	3600		/* Expiration time, seconds	*/
+#define	ENV_MAX		4096		/* Size of environment block	*/
+#define	CGI_ENV_VARS	64		/* Maximum vars passed to CGI	*/
+#define	SERVICE_NAME	"SHTTPD " VERSION	/* NT service name	*/
+
+#endif /* CONFIG_HEADER_DEFINED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/defs.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/defs.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/defs.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,395 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#ifndef DEFS_HEADER_DEFINED
+#define	DEFS_HEADER_DEFINED
+
+#include "std_includes.h"
+#include "llist.h"
+#include "io.h"
+#include "md5.h"
+#include "config.h"
+#include "shttpd.h"
+
+#define	NELEMS(ar)	(sizeof(ar) / sizeof(ar[0]))
+
+#ifdef _DEBUG
+#define	DBG(x)	do { printf x ; putchar('\n'); fflush(stdout); } while (0)
+#else
+#define	DBG(x)
+#endif /* DEBUG */
+
+/*
+ * Darwin prior to 7.0 and Win32 do not have socklen_t
+ */
+#ifdef NO_SOCKLEN_T
+typedef int socklen_t;
+#endif /* NO_SOCKLEN_T */
+
+/*
+ * For parsing. This guy represents a substring.
+ */
+struct vec {
+	const char	*ptr;
+	int		len;
+};
+
+#if !defined(FALSE)
+enum {FALSE, TRUE};
+#endif /* !FALSE */
+
+enum {METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_DELETE, METHOD_HEAD};
+enum {HDR_DATE, HDR_INT, HDR_STRING};	/* HTTP header types		*/
+enum {E_FATAL = 1, E_LOG = 2};		/* Flags for elog() function	*/
+typedef unsigned long big_int_t;	/* Type for Content-Length	*/
+	
+/*
+ * Unified socket address
+ */
+struct usa {
+	socklen_t len;
+	union {
+		struct sockaddr	sa;
+		struct sockaddr_in sin;
+	} u;
+};
+
+/*
+ * This thing is aimed to hold values of any type.
+ * Used to store parsed headers' values.
+ */
+union variant {
+	char		*v_str;
+	int		v_int;
+	big_int_t	v_big_int;
+	time_t		v_time;
+	void		(*v_func)(void);
+	void		*v_void;
+	struct vec	v_vec;
+};
+
+/*
+ * This is used only in embedded configuration. This structure holds a
+ * registered URI, associated callback function with callback data.
+ * For non-embedded compilation shttpd_callback_t is not defined, so
+ * we use union variant to keep the compiler silent.
+ */
+struct registered_uri {
+	struct llhead	link;
+	const char	*uri;
+	union variant	callback;
+	void		*callback_data;
+};
+
+/*
+ * User may want to handle certain errors. This structure holds the
+ * handlers for corresponding error codes.
+ */
+struct error_handler {
+	struct llhead	link;
+	int		code;
+	union variant	callback;
+	void		*callback_data;
+};
+
+struct http_header {
+	int		len;		/* Header name length		*/
+	int		type;		/* Header type			*/
+	size_t		offset;		/* Value placeholder		*/
+	const char	*name;		/* Header name			*/
+};
+
+/*
+ * This guy holds parsed HTTP headers
+ */
+struct headers {
+	union variant	cl;		/* Content-Length:		*/
+	union variant	ct;		/* Content-Type:		*/
+	union variant	connection;	/* Connection:			*/
+	union variant	ims;		/* If-Modified-Since:		*/
+	union variant	user;		/* Remote user name		*/
+	union variant	auth;		/* Authorization		*/
+	union variant	useragent;	/* User-Agent:			*/
+	union variant	referer;	/* Referer:			*/
+	union variant	cookie;		/* Cookie:			*/
+	union variant	location;	/* Location:			*/
+	union variant	range;		/* Range:			*/
+	union variant	status;		/* Status:			*/
+	union variant	transenc;	/* Transfer-Encoding:		*/
+};
+
+/* Must go after union variant definition */
+#include "ssl.h"
+
+/*
+ * The communication channel
+ */
+union channel {
+	int		fd;		/* Regular static file		*/
+	int		sock;		/* Connected socket		*/
+	struct {
+		int		sock;	/* XXX important. must be first	*/
+		SSL		*ssl;	/* shttpd_poll() assumes that	*/
+	} ssl;				/* SSL-ed socket		*/
+	struct {
+		DIR	*dirp;
+		char	*path;
+	} dir;				/* Opened directory		*/
+	struct {
+		void		*state;	/* For keeping state		*/
+		union variant	func;	/* User callback function	*/
+		void		*data;	/* User defined parameters	*/
+	} emb;				/* Embedded, user callback	*/
+};
+
+struct stream;
+
+/*
+ * IO class descriptor (file, directory, socket, SSL, CGI, etc)
+ * These classes are defined in io_*.c files.
+ */
+struct io_class {
+	const char *name;
+	int (*read)(struct stream *, void *buf, size_t len);
+	int (*write)(struct stream *, const void *buf, size_t len);
+	void (*close)(struct stream *);
+};
+
+/*
+ * Data exchange stream. It is backed by some communication channel:
+ * opened file, socket, etc. The 'read' and 'write' methods are
+ * determined by a communication channel.
+ */
+struct stream {
+	struct conn		*conn;
+	union channel		chan;		/* Descriptor		*/
+	struct io		io;		/* IO buffer		*/
+	const struct io_class	*io_class;	/* IO class		*/
+	int			headers_len;
+	big_int_t		content_len;
+	unsigned int		flags;
+#define	FLAG_HEADERS_PARSED	1
+#define	FLAG_SSL_ACCEPTED	2
+#define	FLAG_R			4		/* Can read in general	*/
+#define	FLAG_W			8		/* Can write in general	*/
+#define	FLAG_CLOSED		16
+#define	FLAG_DONT_CLOSE		32
+#define	FLAG_ALWAYS_READY	64		/* File, dir, user_func	*/
+#define	FLAG_SUSPEND		128
+};
+
+struct worker {
+	struct llhead	link;
+	int		num_conns;	/* Num of active connections 	*/
+	int		exit_flag;	/* Ditto - exit flag		*/
+	int		ctl[2];		/* Control socket pair		*/
+	struct shttpd_ctx *ctx;		/* Context reference		*/
+	struct llhead	connections;	/* List of connections		*/
+};
+
+struct conn {
+	struct llhead	link;		/* Connections chain		*/
+	struct worker	*worker;	/* Worker this conn belongs to	*/
+	struct shttpd_ctx *ctx;		/* Context this conn belongs to */
+	struct usa	sa;		/* Remote socket address	*/
+	time_t		birth_time;	/* Creation time		*/
+	time_t		expire_time;	/* Expiration time		*/
+
+	int		loc_port;	/* Local port			*/
+	int		status;		/* Reply status code		*/
+	int		method;		/* Request method		*/
+	char		*uri;		/* Decoded URI			*/
+	unsigned long	major_version;	/* Major HTTP version number    */
+	unsigned long	minor_version;	/* Minor HTTP version number    */
+	char		*request;	/* Request line			*/
+	char		*headers;	/* Request headers		*/
+	char		*query;		/* QUERY_STRING part of the URI	*/
+	char		*path_info;	/* PATH_INFO thing		*/
+	struct vec	mime_type;	/* Mime type			*/
+
+	struct headers	ch;		/* Parsed client headers	*/
+
+	struct stream	loc;		/* Local stream			*/
+	struct stream	rem;		/* Remote stream		*/
+
+#if !defined(NO_SSI)
+	void			*ssi;	/* SSI descriptor		*/
+#endif /* NO_SSI */
+};
+
+enum {
+	OPT_ROOT, OPT_INDEX_FILES, OPT_PORTS, OPT_DIR_LIST,
+	OPT_CGI_EXTENSIONS, OPT_CGI_INTERPRETER, OPT_CGI_ENVIRONMENT,
+	OPT_SSI_EXTENSIONS, OPT_AUTH_REALM, OPT_AUTH_GPASSWD,
+	OPT_AUTH_PUT, OPT_ACCESS_LOG, OPT_ERROR_LOG, OPT_MIME_TYPES,
+	OPT_SSL_CERTIFICATE, OPT_ALIASES, OPT_ACL, OPT_INETD, OPT_UID,
+	OPT_CFG_URI, OPT_PROTECT, OPT_SERVICE, OPT_HIDE, OPT_THREADS,
+	NUM_OPTIONS
+};
+
+/*
+ * SHTTPD context
+ */
+struct shttpd_ctx {
+	SSL_CTX		*ssl_ctx;	/* SSL context			*/
+
+	struct llhead	registered_uris;/* User urls			*/
+	struct llhead	error_handlers;	/* Embedded error handlers	*/
+	struct llhead	acl;		/* Access control list		*/
+	struct llhead	ssi_funcs;	/* SSI callback functions	*/
+	struct llhead	listeners;	/* Listening sockets		*/
+	struct llhead	workers;	/* Worker workers		*/
+
+	FILE		*access_log;	/* Access log stream		*/
+	FILE		*error_log;	/* Error log stream		*/
+
+	char	*options[NUM_OPTIONS];	/* Configurable options		*/
+#if defined(__rtems__)
+	rtems_id         mutex;
+#endif /* _WIN32 */
+};
+
+struct listener {
+	struct llhead		link;
+	struct shttpd_ctx	*ctx;	/* Context that socket belongs	*/
+	int			sock;	/* Listening socket		*/
+	int			is_ssl;	/* Should be SSL-ed		*/
+};
+
+/* Types of messages that could be sent over the control socket */
+enum {CTL_PASS_SOCKET, CTL_WAKEUP};
+
+/*
+ * In SHTTPD, list of values are represented as comma or space separated
+ * string. For example, list of CGI extensions can be represented as
+ * ".cgi,.php,.pl", or ".cgi .php .pl". The macro that follows allows to
+ * loop through the individual values in that list.
+ *
+ * A "const char *" pointer and size_t variable must be passed to the macro.
+ * Spaces or commas can be used as delimiters (macro DELIM_CHARS).
+ *
+ * In every iteration of the loop, "s" points to the current value, and
+ * "len" specifies its length. The code inside loop must not change
+ * "s" and "len" parameters.
+ */
+#define	FOR_EACH_WORD_IN_LIST(s,len)					\
+	for (; s != NULL && (len = strcspn(s, DELIM_CHARS)) != 0;	\
+			s += len, s+= strspn(s, DELIM_CHARS))
+
+/*
+ * IPv4 ACL entry. Specifies subnet with deny/allow flag
+ */
+struct acl {
+	struct llhead	link;
+	uint32_t	ip;		/* IP, in network byte order	*/
+	uint32_t	mask;		/* Also in network byte order	*/
+	int		flag;		/* Either '+' or '-'		*/
+};
+
+/*
+ * shttpd.c
+ */
+extern time_t	_shttpd_current_time;	/* Current UTC time		*/
+extern int	_shttpd_tz_offset;	/* Offset from GMT time zone	*/
+extern const struct vec _shttpd_known_http_methods[];
+
+extern void	_shttpd_stop_stream(struct stream *stream);
+extern int	_shttpd_url_decode(const char *, int, char *dst, int);
+extern void	_shttpd_send_server_error(struct conn *, int, const char *);
+extern int	_shttpd_get_headers_len(const char *buf, size_t buflen);
+extern void	_shttpd_parse_headers(const char *s, int, struct headers *);
+extern int	_shttpd_is_true(const char *str);
+extern int	_shttpd_socketpair(int pair[2]);
+extern void	_shttpd_get_mime_type(struct shttpd_ctx *,
+			const char *, int, struct vec *);
+
+#define	IS_TRUE(ctx, opt)	_shttpd_is_true((ctx)->options[opt])
+
+/*
+ * config.c
+ */
+extern void	_shttpd_usage(const char *prog);
+
+/*
+ * log.c
+ */
+extern void	_shttpd_elog(int flags, struct conn *c, const char *fmt, ...);
+extern void	_shttpd_log_access(FILE *fp, const struct conn *c);
+
+/*
+ * string.c
+ */
+extern void	_shttpd_strlcpy(register char *, register const char *, size_t);
+extern int	_shttpd_strncasecmp(register const char *,
+			register const char *, size_t);
+extern char	*_shttpd_strndup(const char *ptr, size_t len);
+extern char	*_shttpd_strdup(const char *str);
+extern int	_shttpd_snprintf(char *buf, size_t len, const char *fmt, ...);
+extern int	_shttpd_match_extension(const char *path, const char *ext_list);
+
+/*
+ * compat_*.c
+ */
+extern void	_shttpd_set_close_on_exec(int fd);
+extern int	_shttpd_set_non_blocking_mode(int fd);
+extern int	_shttpd_stat(const char *, struct stat *stp);
+extern int	_shttpd_open(const char *, int flags, int mode);
+extern int	_shttpd_remove(const char *);
+extern int	_shttpd_rename(const char *, const char *);
+extern int	_shttpd_mkdir(const char *, int);
+extern char *	_shttpd_getcwd(char *, int);
+extern int	_shttpd_spawn_process(struct conn *c, const char *prog,
+			char *envblk, char *envp[], int sock, const char *dir);
+
+extern int	_shttpd_set_nt_service(struct shttpd_ctx *, const char *);
+extern int	_shttpd_set_systray(struct shttpd_ctx *, const char *);
+extern void	_shttpd_try_to_run_as_nt_service(void);
+
+/*
+ * io_*.c
+ */
+extern const struct io_class	_shttpd_io_file;
+extern const struct io_class	_shttpd_io_socket;
+extern const struct io_class	_shttpd_io_ssl;
+extern const struct io_class	_shttpd_io_cgi;
+extern const struct io_class	_shttpd_io_dir;
+extern const struct io_class	_shttpd_io_embedded;
+extern const struct io_class	_shttpd_io_ssi;
+
+extern int	_shttpd_put_dir(const char *path);
+extern void	_shttpd_get_dir(struct conn *c);
+extern void	_shttpd_get_file(struct conn *c, struct stat *stp);
+extern void	_shttpd_ssl_handshake(struct stream *stream);
+extern void	_shttpd_setup_embedded_stream(struct conn *,
+			union variant, void *);
+extern struct registered_uri *_shttpd_is_registered_uri(struct shttpd_ctx *,
+			const char *uri);
+extern void	_shttpd_do_ssi(struct conn *);
+extern void	_shttpd_ssi_func_destructor(struct llhead *lp);
+
+/*
+ * auth.c
+ */
+extern int	_shttpd_check_authorization(struct conn *c, const char *path);
+extern int	_shttpd_is_authorized_for_put(struct conn *c);
+extern void	_shttpd_send_authorization_request(struct conn *c);
+extern int	_shttpd_edit_passwords(const char *fname, const char *domain,
+			const char *user, const char *pass);
+
+/*
+ * cgi.c
+ */
+extern int	_shttpd_run_cgi(struct conn *c, const char *prog);
+extern void	_shttpd_do_cgi(struct conn *c);
+
+#define CGI_REPLY	"HTTP/1.1     OK\r\n"
+#define	CGI_REPLY_LEN	(sizeof(CGI_REPLY) - 1)
+
+#endif /* DEFS_HEADER_DEFINED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,97 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#ifndef IO_HEADER_INCLUDED
+#define	IO_HEADER_INCLUDED
+
+#include <assert.h>
+#include <stddef.h>
+
+/*
+ * I/O buffer descriptor
+ */
+struct io {
+	char		*buf;		/* IO Buffer			*/
+	size_t		size;		/* IO buffer size		*/
+	size_t		head;		/* Bytes read			*/
+	size_t		tail;		/* Bytes written		*/
+	size_t		total;		/* Total bytes read		*/
+};
+
+static __inline void
+io_clear(struct io *io)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	io->total = io->tail = io->head = 0;
+}
+
+static __inline char *
+io_space(struct io *io)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	assert(io->head <= io->size);
+	return (io->buf + io->head);
+}
+
+static __inline char *
+io_data(struct io *io)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	assert(io->tail <= io->size);
+	return (io->buf + io->tail);
+}
+
+static __inline size_t
+io_space_len(const struct io *io)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	assert(io->head <= io->size);
+	return (io->size - io->head);
+}
+
+static __inline size_t
+io_data_len(const struct io *io)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	assert(io->head <= io->size);
+	assert(io->tail <= io->head);
+	return (io->head - io->tail);
+}
+
+static __inline void
+io_inc_tail(struct io *io, size_t n)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	assert(io->tail <= io->head);
+	assert(io->head <= io->size);
+	io->tail += n;
+	assert(io->tail <= io->head);
+	if (io->tail == io->head)
+		io->head = io->tail = 0;
+}
+
+static __inline void
+io_inc_head(struct io *io, size_t n)
+{
+	assert(io->buf != NULL);
+	assert(io->size > 0);
+	assert(io->tail <= io->head);
+	io->head += n;
+	io->total += n;
+	assert(io->head <= io->size);
+}
+
+#endif /* IO_HEADER_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_cgi.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_cgi.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_cgi.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,127 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+static int
+write_cgi(struct stream *stream, const void *buf, size_t len)
+{
+	assert(stream->chan.sock != -1);
+	assert(stream->flags & FLAG_W);
+
+	return (send(stream->chan.sock, buf, len, 0));
+}
+
+static int
+read_cgi(struct stream *stream, void *buf, size_t len)
+{
+	struct headers	parsed;
+	char		status[4];
+	int		n;
+
+	assert(stream->chan.sock != -1);
+	assert(stream->flags & FLAG_R);
+
+	stream->flags &= ~FLAG_DONT_CLOSE;
+
+	n = recv(stream->chan.sock, buf, len, 0);
+
+	if (stream->flags & FLAG_HEADERS_PARSED)
+		return (n);
+
+	if (n <= 0 && ERRNO != EWOULDBLOCK) {
+		_shttpd_send_server_error(stream->conn, 500,
+		    "Error running CGI");
+		return (n);
+	}
+
+	/*
+	 * CGI script may output Status: and Location: headers, which
+	 * may alter the status code. Buffer in headers, parse
+	 * them, send correct status code and then forward all data
+	 * from CGI script back to the remote end.
+	 * Reply line was alredy appended to the IO buffer in
+	 * decide_what_to_do(), with blank status code.
+	 */
+
+	stream->flags |= FLAG_DONT_CLOSE;
+	io_inc_head(&stream->io, n);
+
+	stream->headers_len = _shttpd_get_headers_len(stream->io.buf,
+	    stream->io.head);
+	if (stream->headers_len < 0) {
+		stream->flags &= ~FLAG_DONT_CLOSE;
+		_shttpd_send_server_error(stream->conn, 500,
+		    "Bad headers sent");
+		_shttpd_elog(E_LOG, stream->conn,
+		    "CGI script sent invalid headers: "
+		    "[%.*s]", stream->io.head - CGI_REPLY_LEN,
+		    stream->io.buf + CGI_REPLY_LEN);
+		return (0);
+	}
+
+	/*
+	 * If we did not received full headers yet, we must not send any
+	 * data read from the CGI back to the client. Suspend sending by
+	 * setting tail = head, which tells that there is no data in IO buffer
+	 */
+
+	if (stream->headers_len == 0) {
+		stream->io.tail = stream->io.head;
+		return (0);
+	}
+
+	/* Received all headers. Set status code for the connection. */
+	(void) memset(&parsed, 0, sizeof(parsed));
+	_shttpd_parse_headers(stream->io.buf, stream->headers_len, &parsed);
+	stream->content_len = parsed.cl.v_big_int;
+	stream->conn->status = (int) parsed.status.v_big_int;
+
+	/* If script outputs 'Location:' header, set status code to 302 */
+	if (parsed.location.v_vec.len > 0)
+		stream->conn->status = 302;
+
+	/*
+	 * If script did not output neither 'Location:' nor 'Status' headers,
+	 * set the default status code 200, which means 'success'.
+	 */
+	if (stream->conn->status == 0)
+		stream->conn->status = 200;
+
+	/* Append the status line to the beginning of the output */
+	(void) _shttpd_snprintf(status,
+	    sizeof(status), "%3d", stream->conn->status);
+	(void) memcpy(stream->io.buf + 9, status, 3);
+	DBG(("read_cgi: content len %lu status %s",
+	    stream->content_len, status));
+
+	/* Next time, pass output directly back to the client */
+	assert((big_int_t) stream->headers_len <= stream->io.total);
+	stream->io.total -= stream->headers_len;
+	stream->io.tail = 0;
+	stream->flags |= FLAG_HEADERS_PARSED;
+
+	/* Return 0 because we've already shifted the head */
+	return (0);
+}
+
+static void
+close_cgi(struct stream *stream)
+{
+	assert(stream->chan.sock != -1);
+	(void) closesocket(stream->chan.sock);
+}
+
+const struct io_class	_shttpd_io_cgi =  {
+	"cgi",
+	read_cgi,
+	write_cgi,
+	close_cgi
+};

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_dir.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_dir.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_dir.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,153 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+/*
+ * For a given PUT path, create all intermediate subdirectories
+ * for given path. Return 0 if the path itself is a directory,
+ * or -1 on error, 1 if OK.
+ */
+int
+_shttpd_put_dir(const char *path)
+{
+	char		buf[FILENAME_MAX];
+	const char	*s, *p;
+	struct stat	st;
+	size_t		len;
+
+	for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
+		len = p - path;
+		assert(len < sizeof(buf));
+		(void) memcpy(buf, path, len);
+		buf[len] = '\0';
+
+		/* Try to create intermediate directory */
+		if (_shttpd_stat(buf, &st) == -1 &&
+		    _shttpd_mkdir(buf, 0755) != 0)
+			return (-1);
+
+		/* Is path itself a directory ? */
+		if (p[1] == '\0')
+			return (0);
+	}
+
+	return (1);
+}
+
+static int
+read_dir(struct stream *stream, void *buf, size_t len)
+{
+	static const char footer[] = "</table></body></html>\n";
+
+	struct dirent	*dp = NULL;
+	char		file[FILENAME_MAX], line[FILENAME_MAX + 512],
+				size[64], mod[64];
+	struct stat	st;
+	struct conn	*c = stream->conn;
+	int		n, nwritten = 0;
+	const char	*slash = "";
+
+	assert(stream->chan.dir.dirp != NULL);
+	assert(stream->conn->uri[0] != '\0');
+
+	do {
+		if (len < sizeof(line))
+			break;
+
+		if ((dp = readdir(stream->chan.dir.dirp)) == NULL)
+			break;
+		DBG(("read_dir: %s", dp->d_name));
+
+		/* Do not show current dir and passwords file */
+		if (strcmp(dp->d_name, ".") == 0 ||
+		   strcmp(dp->d_name, HTPASSWD) == 0)
+			continue;
+
+		(void) _shttpd_snprintf(file, sizeof(file),
+		    "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
+		(void) _shttpd_stat(file, &st);
+		if (S_ISDIR(st.st_mode)) {
+			_shttpd_snprintf(size,sizeof(size),"%s","<DIR>");
+		} else {
+			if (st.st_size < 1024)
+				(void) _shttpd_snprintf(size, sizeof(size),
+				    "%lu", (unsigned long) st.st_size);
+			else if (st.st_size < 1024 * 1024)
+				(void) _shttpd_snprintf(size,
+				    sizeof(size), "%luk",
+				    (unsigned long) (st.st_size >> 10)  + 1);
+			else
+				(void) _shttpd_snprintf(size, sizeof(size),
+				    "%.1fM", (float) st.st_size / 1048576);
+		}
+		(void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
+			localtime(&st.st_mtime));
+
+		n = _shttpd_snprintf(line, sizeof(line),
+		    "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
+		    "<td> %s</td><td>  %s</td></tr>\n",
+		    c->uri, slash, dp->d_name, dp->d_name,
+		    S_ISDIR(st.st_mode) ? "/" : "", mod, size);
+		(void) memcpy(buf, line, n);
+		buf = (char *) buf + n;
+		nwritten += n;
+		len -= n;
+	} while (dp != NULL);
+
+	/* Append proper HTML footer for the page */
+	if (dp == NULL && len >= sizeof(footer)) {
+		(void) memcpy(buf, footer, sizeof(footer));
+		nwritten += sizeof(footer);
+		stream->flags |= FLAG_CLOSED;
+	}
+
+	return (nwritten);
+}
+
+static void
+close_dir(struct stream *stream)
+{
+	assert(stream->chan.dir.dirp != NULL);
+	assert(stream->chan.dir.path != NULL);
+	(void) closedir(stream->chan.dir.dirp);
+	free(stream->chan.dir.path);
+}
+
+void
+_shttpd_get_dir(struct conn *c)
+{
+	if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) {
+		(void) free(c->loc.chan.dir.path);
+		_shttpd_send_server_error(c, 500, "Cannot open directory");
+	} else {
+		c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
+		    "HTTP/1.1 200 OK\r\n"
+		    "Connection: close\r\n"
+		    "Content-Type: text/html; charset=utf-8\r\n\r\n"
+		    "<html><head><title>Index of %s</title>"
+		    "<style>th {text-align: left;}</style></head>"
+		    "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
+		    "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
+		    "<tr><td colspan=\"3\"><hr></td></tr>",
+		    c->uri, c->uri);
+		io_clear(&c->rem.io);
+		c->status = 200;
+		c->loc.io_class = &_shttpd_io_dir;
+		c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+	}
+}
+
+const struct io_class	_shttpd_io_dir =  {
+	"dir",
+	read_dir,
+	NULL,
+	close_dir
+};

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_emb.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_emb.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_emb.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,329 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+const char *
+shttpd_version(void)
+{
+	return (VERSION);
+}
+
+static void
+call_user(struct conn *c, struct shttpd_arg *arg, shttpd_callback_t func)
+{
+	arg->priv		= c;
+	arg->state		= c->loc.chan.emb.state;
+	arg->out.buf		= io_space(&c->loc.io);
+	arg->out.len		= io_space_len(&c->loc.io);
+	arg->out.num_bytes	= 0;
+	arg->in.buf		= io_data(&c->rem.io);;
+	arg->in.len		= io_data_len(&c->rem.io);
+	arg->in.num_bytes	= 0;
+
+	if (io_data_len(&c->rem.io) >= c->rem.io.size)
+		arg->flags |= SHTTPD_POST_BUFFER_FULL;
+
+	if (c->rem.content_len > 0 && c->rem.io.total < c->rem.content_len)
+		arg->flags |= SHTTPD_MORE_POST_DATA;
+
+	func(arg);
+
+	io_inc_head(&c->loc.io, arg->out.num_bytes);
+	io_inc_tail(&c->rem.io, arg->in.num_bytes);
+	c->loc.chan.emb.state = arg->state;		/* Save state */
+
+	/*
+	 * If callback finished output, that means it did all cleanup.
+	 * If the connection is terminated unexpectedly, we canna call
+	 * the callback via the stream close() method from disconnect.
+	 * However, if cleanup is already done, we set close() method to
+	 * NULL, to prevent the call from disconnect().
+	 */
+
+	if (arg->flags & SHTTPD_END_OF_OUTPUT)
+		c->loc.flags &= ~FLAG_DONT_CLOSE;
+	else
+		c->loc.flags |= FLAG_DONT_CLOSE;
+
+	if (arg->flags & SHTTPD_SUSPEND)
+		c->loc.flags |= FLAG_SUSPEND;
+}
+
+static int
+do_embedded(struct stream *stream, void *buf, size_t len)
+{
+	struct shttpd_arg	arg;
+	buf = NULL; len = 0;		/* Squash warnings */
+
+	arg.user_data	= stream->conn->loc.chan.emb.data;
+	arg.flags	= 0;
+
+	call_user(stream->conn, &arg, (shttpd_callback_t)
+			stream->conn->loc.chan.emb.func.v_func);
+
+	return (0);
+}
+
+static void
+close_embedded(struct stream *stream)
+{
+	struct shttpd_arg	arg;
+	struct conn		*c = stream->conn;
+
+	arg.flags	= SHTTPD_CONNECTION_ERROR;
+	arg.user_data	= c->loc.chan.emb.data;
+
+	/*
+	 * Do not call the user function if SHTTPD_END_OF_OUTPUT was set,
+	 * i.e. the callback already terminated correctly
+	 */
+	if (stream->flags & FLAG_DONT_CLOSE)
+		call_user(stream->conn, &arg, (shttpd_callback_t)
+		    c->loc.chan.emb.func.v_func);
+}
+
+size_t
+shttpd_printf(struct shttpd_arg *arg, const char *fmt, ...)
+{
+	char		*buf = arg->out.buf + arg->out.num_bytes;
+	int		buflen = arg->out.len - arg->out.num_bytes, len = 0;
+	va_list		ap;
+
+	if (buflen > 0) {
+		va_start(ap, fmt);
+		len = vsnprintf(buf, buflen, fmt, ap);
+		va_end(ap);
+
+		if (len < 0 || len > buflen)
+			len = buflen;
+		arg->out.num_bytes += len;
+	}
+
+	return (len);
+}
+
+const char *
+shttpd_get_header(struct shttpd_arg *arg, const char *header_name)
+{
+	struct conn	*c = arg->priv;
+	char		*p, *s, *e;
+	size_t		len;
+
+	p = c->headers;
+	e = c->request + c->rem.headers_len;
+	len = strlen(header_name);
+
+	while (p < e) {
+		if ((s = strchr(p, '\n')) != NULL)
+			s[s[-1] == '\r' ? -1 : 0] = '\0';
+		if (_shttpd_strncasecmp(header_name, p, len) == 0)
+			return (p + len + 2);
+
+		p += strlen(p) + 1;
+	}
+
+	return (NULL);
+}
+
+const char *
+shttpd_get_env(struct shttpd_arg *arg, const char *env_name)
+{
+	struct conn	*c = arg->priv;
+	struct vec	*vec;
+
+	if (strcmp(env_name, "REQUEST_METHOD") == 0) {
+		return (_shttpd_known_http_methods[c->method].ptr);
+	} else if (strcmp(env_name, "REQUEST_URI") == 0) {
+		return (c->uri);
+	} else if (strcmp(env_name, "QUERY_STRING") == 0) {
+		return (c->query);
+	} else if (strcmp(env_name, "REMOTE_USER") == 0) {
+		vec = &c->ch.user.v_vec;
+		if (vec->len > 0) {
+			((char *) vec->ptr)[vec->len] = '\0';
+			return (vec->ptr);
+		}
+	} else if (strcmp(env_name, "REMOTE_ADDR") == 0) {
+		return (inet_ntoa(c->sa.u.sin.sin_addr));/* FIXME NOT MT safe */
+	}
+
+	return (NULL);
+}
+
+void
+shttpd_get_http_version(struct shttpd_arg *arg,
+		unsigned long *major, unsigned long *minor)
+{
+	struct conn *c = arg->priv;
+	
+	*major = c->major_version;
+	*minor = c->minor_version;
+}
+
+void
+shttpd_register_uri(struct shttpd_ctx *ctx,
+		const char *uri, shttpd_callback_t callback, void *data)
+{
+	struct registered_uri	*e;
+
+	if ((e = malloc(sizeof(*e))) != NULL) {
+		e->uri			= _shttpd_strdup(uri);
+		e->callback.v_func	= (void (*)(void)) callback;
+		e->callback_data	= data;
+		LL_TAIL(&ctx->registered_uris, &e->link);
+	}
+}
+
+int
+shttpd_get_var(const char *var, const char *buf, int buf_len,
+		char *value, int value_len)
+{
+	const char	*p, *e, *s;
+	size_t		var_len;
+
+	var_len = strlen(var);
+	e = buf + buf_len;		/* End of QUERY_STRING buffer	*/
+
+	/* buf is "var1=val1&var2=val2...". Find variable first */
+	for (p = buf; p + var_len < e; p++)
+		if ((p == buf || p[-1] == '&') &&
+		    p[var_len] == '=' &&
+		    !_shttpd_strncasecmp(var, p, var_len)) {
+
+			/* Point 'p' to var value, 's' to the end of value */
+			p += var_len + 1;	
+			if ((s = memchr(p, '&', e - p)) == NULL)
+				s = e;
+
+			/* URL-decode value. Return result length */
+			return (_shttpd_url_decode(p, s - p, value, value_len));
+		}
+
+	return (-1);
+}
+
+static int
+match_regexp(const char *regexp, const char *text)
+{
+	if (*regexp == '\0')
+		return (*text == '\0');
+
+	if (*regexp == '*')
+		do {
+			if (match_regexp(regexp + 1, text))
+				return (1);
+		} while (*text++ != '\0');
+
+	if (*text != '\0' && *regexp == *text)
+		return (match_regexp(regexp + 1, text + 1));
+
+	return (0);
+}
+
+struct registered_uri *
+_shttpd_is_registered_uri(struct shttpd_ctx *ctx, const char *uri)
+{
+	struct llhead		*lp;
+	struct registered_uri	*reg_uri;
+
+	LL_FOREACH(&ctx->registered_uris, lp) {
+		reg_uri = LL_ENTRY(lp, struct registered_uri, link);
+		if (match_regexp(reg_uri->uri, uri))
+			return (reg_uri);
+	}
+
+	return (NULL);
+}
+
+
+
+
+
+//@@	Add
+int shttpd_unregister_uri(struct shttpd_ctx *ctx, const char *uri)
+{
+	struct llhead		*lp;
+	struct registered_uri	*reg_uri;
+	int returnValue = -1;			//@mod(December 2008)@
+	lp = NULL;						//@mod(December 2008)@
+
+	LL_FOREACH(&ctx->registered_uris, lp) {
+		reg_uri = LL_ENTRY(lp, struct registered_uri, link);
+		if (match_regexp(reg_uri->uri, uri))
+		{
+			//free((void *)reg_uri->uri);			//@mod(03 September 2007)@
+			//free((char *) reg_uri->uri);			//@mod(03 September 2007)@
+			free((char *) reg_uri->uri);			//@add(27 September 2007)@	OK
+			//free((void *)reg_uri->callback_data);		//@mod(03 September 2007)@
+			((&reg_uri->link)->next)->prev = ((&reg_uri->link)->prev);			
+			((&reg_uri->link)->prev)->next = ((&reg_uri->link)->next);
+			free(reg_uri);					//@mod(03 September 2007)@
+			//return 0;
+			returnValue = 0;
+			break;						//@mod(December 2008)@
+		}
+	}
+
+
+	return returnValue;
+}
+
+
+
+
+
+
+void
+_shttpd_setup_embedded_stream(struct conn *c, union variant func, void *data)
+{
+	c->loc.chan.emb.state = NULL;
+	c->loc.chan.emb.func = func;
+	c->loc.chan.emb.data = data;
+	c->loc.io_class = &_shttpd_io_embedded;
+	c->loc.flags |= FLAG_R | FLAG_W |FLAG_ALWAYS_READY;
+}
+
+void
+shttpd_handle_error(struct shttpd_ctx *ctx, int code,
+		shttpd_callback_t func, void *data)
+{
+	struct error_handler	*e;
+
+	if ((e = malloc(sizeof(*e))) != NULL) {
+		e->code = code;
+		e->callback.v_func = (void (*)(void)) func;
+		e->callback_data = data;
+		LL_TAIL(&ctx->error_handlers, &e->link);
+	}
+}
+
+void
+shttpd_wakeup(const void *priv)
+{
+	const struct conn	*conn = priv;
+	char			buf[sizeof(int) + sizeof(void *)];
+	int			cmd = CTL_WAKEUP;
+
+#if 0
+	conn->flags &= ~SHTTPD_SUSPEND;
+#endif
+	(void) memcpy(buf, &cmd, sizeof(cmd));
+	(void) memcpy(buf + sizeof(cmd), conn, sizeof(conn));
+
+	(void) send(conn->worker->ctl[1], buf, sizeof(buf), 0);
+}
+
+const struct io_class	_shttpd_io_embedded =  {
+	"embedded",
+	do_embedded,
+	(int (*)(struct stream *, const void *, size_t)) do_embedded,
+	close_embedded
+};

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_file.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_file.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_file.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,157 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+static int
+write_file(struct stream *stream, const void *buf, size_t len)
+{
+	struct stat	st;
+	struct stream	*rem = &stream->conn->rem;
+	int		n, fd = stream->chan.fd;
+
+	assert(fd != -1);
+	n = write(fd, buf, len);
+
+	DBG(("put_file(%p, %d): %d bytes", (void *) stream, (int) len, n));
+
+	if (n <= 0 || (rem->io.total >= (big_int_t) rem->content_len)) {
+		(void) fstat(fd, &st);
+		stream->io.head = stream->headers_len =
+		    _shttpd_snprintf(stream->io.buf,
+		    stream->io.size, "HTTP/1.1 %d OK\r\n"
+		    "Content-Length: %lu\r\nConnection: close\r\n\r\n",
+		    stream->conn->status, st.st_size);
+		_shttpd_stop_stream(stream);
+	}
+
+	return (n);
+}
+
+static int
+read_file(struct stream *stream, void *buf, size_t len)
+{
+#ifdef USE_SENDFILE
+	struct	iovec	vec;
+	struct	sf_hdtr	hd = {&vec, 1, NULL, 0}, *hdp = &hd;
+	int		sock, fd, n;
+	size_t		nbytes;
+	off_t		sent;
+
+	sock = stream->conn->rem.chan.sock;
+	fd = stream->chan.fd;
+
+	/* If this is the first call for this file, send the headers */
+	vec.iov_base = stream->io.buf;
+	vec.iov_len = stream->headers_len;
+	if (stream->io.total > 0)
+		hdp = NULL;
+
+	nbytes = stream->content_len - stream->io.total;
+	n = sendfile(fd, sock, lseek(fd, 0, SEEK_CUR), nbytes, hdp, &sent, 0);
+
+	if (n == -1 && ERRNO != EAGAIN) {
+		stream->flags &= ~FLAG_DONT_CLOSE;
+		return (n);
+	}
+
+	stream->conn->ctx->out += sent;
+
+	/* If we have sent the HTTP headers in this turn, clear them off */
+	if (stream->io.total == 0) {
+		assert(sent >= stream->headers_len);
+		sent -= stream->headers_len;
+		io_clear(&stream->io);
+	}
+
+	(void) lseek(fd, sent, SEEK_CUR);
+	stream->io.total += sent;
+	stream->flags |= FLAG_DONT_CLOSE;
+
+	return (0);
+#endif /* USE_SENDFILE */
+
+	assert(stream->chan.fd != -1);
+	return (read(stream->chan.fd, buf, len));
+}
+
+static void
+close_file(struct stream *stream)
+{
+	assert(stream->chan.fd != -1);
+	(void) close(stream->chan.fd);
+}
+
+void
+_shttpd_get_file(struct conn *c, struct stat *stp)
+{
+	char		date[64], lm[64], etag[64], range[64] = "";
+	size_t		n, status = 200;
+	unsigned long	r1, r2;
+	const char	*fmt = "%a, %d %b %Y %H:%M:%S GMT", *msg = "OK";
+	big_int_t	cl; /* Content-Length */
+
+	if (c->mime_type.len == 0)
+		_shttpd_get_mime_type(c->ctx, c->uri,
+		    strlen(c->uri), &c->mime_type); 
+	cl = (big_int_t) stp->st_size;
+
+	/* If Range: header specified, act accordingly */
+	if (c->ch.range.v_vec.len > 0 &&
+	    (n = sscanf(c->ch.range.v_vec.ptr,"bytes=%lu-%lu",&r1, &r2)) > 0) {
+		status = 206;
+		(void) lseek(c->loc.chan.fd, r1, SEEK_SET);
+		cl = n == 2 ? r2 - r1 + 1: cl - r1;
+		(void) _shttpd_snprintf(range, sizeof(range),
+		    "Content-Range: bytes %lu-%lu/%lu\r\n",
+		    r1, r1 + cl - 1, (unsigned long) stp->st_size);
+		msg = "Partial Content";
+	}
+
+	/* Prepare Etag, Date, Last-Modified headers */
+	(void) strftime(date, sizeof(date),
+	    fmt, localtime(&_shttpd_current_time));
+	(void) strftime(lm, sizeof(lm), fmt, localtime(&stp->st_mtime));
+	(void) _shttpd_snprintf(etag, sizeof(etag), "%lx.%lx",
+	    (unsigned long) stp->st_mtime, (unsigned long) stp->st_size);
+
+	/*
+	 * We do not do io_inc_head here, because it will increase 'total'
+	 * member in io. We want 'total' to be equal to the content size,
+	 * and exclude the headers length from it.
+	 */
+	c->loc.io.head = c->loc.headers_len = _shttpd_snprintf(c->loc.io.buf,
+	    c->loc.io.size,
+	    "HTTP/1.1 %d %s\r\n"
+	    "Date: %s\r\n"
+	    "Last-Modified: %s\r\n"
+	    "Etag: \"%s\"\r\n"
+	    "Content-Type: %.*s\r\n"
+	    "Content-Length: %lu\r\n"
+	    "Accept-Ranges: bytes\r\n"
+	    "%s\r\n",
+	    status, msg, date, lm, etag,
+	    c->mime_type.len, c->mime_type.ptr, cl, range);
+
+	c->status = status;
+	c->loc.content_len = cl;
+	c->loc.io_class = &_shttpd_io_file;
+	c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+
+	if (c->method == METHOD_HEAD)
+		_shttpd_stop_stream(&c->loc);
+}
+
+const struct io_class	_shttpd_io_file =  {
+	"file",
+	read_file,
+	write_file,
+	close_file
+};

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_socket.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_socket.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_socket.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,39 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+static int
+read_socket(struct stream *stream, void *buf, size_t len)
+{
+	assert(stream->chan.sock != -1);
+	return (recv(stream->chan.sock, buf, len, 0));
+}
+
+static int
+write_socket(struct stream *stream, const void *buf, size_t len)
+{
+	assert(stream->chan.sock != -1);
+	return (send(stream->chan.sock, buf, len, 0));
+}
+
+static void
+close_socket(struct stream *stream)
+{
+	assert(stream->chan.sock != -1);
+	(void) closesocket(stream->chan.sock);
+}
+
+const struct io_class	_shttpd_io_socket =  {
+	"socket",
+	read_socket,
+	write_socket,
+	close_socket
+};

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssi.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssi.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssi.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,488 @@
+/*
+ * Copyright (c) 2006,2007 Steven Johnson <sjohnson at sakuraindustries.com>
+ * Copyright (c) 2007 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+#if !defined(NO_SSI)
+
+#define	CMDBUFSIZ	512		/* SSI command buffer size	*/
+#define	NEST_MAX	6		/* Maximum nesting level	*/
+
+struct ssi_func {
+	struct llhead	link;
+	void		*user_data;
+	char		*name;
+	shttpd_callback_t func;
+};
+
+struct ssi_inc {
+	int		state;		/* Buffering state		*/
+	int		cond;		/* Conditional state		*/
+	FILE		*fp;		/* Icluded file stream		*/
+	char		buf[CMDBUFSIZ];	/* SSI command buffer		*/
+	size_t		nbuf;		/* Bytes in a command buffer	*/
+	FILE		*pipe;		/* #exec stream			*/
+	struct ssi_func	func;		/* #call function		*/
+};
+
+struct ssi {
+	struct conn	*conn;		/* Connection we belong to	*/
+	int		nest;		/* Current nesting level	*/
+	struct ssi_inc	incs[NEST_MAX];	/* Nested includes		*/
+};
+
+enum { SSI_PASS, SSI_BUF, SSI_EXEC, SSI_CALL };
+enum { SSI_GO, SSI_STOP };		/* Conditional states		*/
+
+static const struct vec	st = {"<!--#", 5};
+
+void
+shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
+		shttpd_callback_t func, void *user_data)
+{
+	struct ssi_func	*e;
+
+	if ((e = malloc(sizeof(*e))) != NULL) {
+		e->name		= _shttpd_strdup(name);
+		e->func		= func;
+		e->user_data	= user_data;
+		LL_TAIL(&ctx->ssi_funcs, &e->link);
+	}
+}
+
+void
+_shttpd_ssi_func_destructor(struct llhead *lp)
+{
+	struct ssi_func	*e = LL_ENTRY(lp, struct ssi_func, link);
+
+	free(e->name);
+	free(e);
+}
+
+static const struct ssi_func *
+find_ssi_func(struct ssi *ssi, const char *name)
+{
+	struct ssi_func	*e;
+	struct llhead	*lp;
+
+	LL_FOREACH(&ssi->conn->ctx->ssi_funcs, lp) {
+		e = LL_ENTRY(lp, struct ssi_func, link);
+		if (!strcmp(name, e->name))
+			return (e);
+	}
+
+	return (NULL);
+}
+
+static void
+call(struct ssi *ssi, const char *name,
+		struct shttpd_arg *arg, char *buf, int len)
+{
+	const struct ssi_func	*ssi_func;
+
+	(void) memset(arg, 0, sizeof(*arg));
+
+	/*
+	 * SSI function may be called with parameters. These parameters
+	 * are passed as arg->in.buf, arg->in.len vector.
+	 */
+	arg->in.buf = strchr(name, ' ');
+	if (arg->in.buf != NULL) {
+		*arg->in.buf++ = '\0';
+		arg->in.len = strlen(arg->in.buf);
+	}
+
+	if ((ssi_func = find_ssi_func(ssi, name)) != NULL) {
+		arg->priv = ssi->conn;
+		arg->user_data = ssi_func->user_data;
+		arg->out.buf = buf;
+		arg->out.len = len;
+		ssi_func->func(arg);
+	}
+}
+
+static int
+evaluate(struct ssi *ssi, const char *name)
+{
+	struct shttpd_arg	arg;
+
+	call(ssi, name, &arg, NULL, 0);
+
+	return (arg.flags & SHTTPD_SSI_EVAL_TRUE);
+}
+
+static void
+pass(struct ssi_inc *inc, void *buf, int *n)
+{
+	if (inc->cond == SSI_GO) {
+		(void) memcpy(buf, inc->buf, inc->nbuf);
+		(*n) += inc->nbuf;
+	}
+	inc->nbuf = 0;
+	inc->state = SSI_PASS;
+}
+
+static int
+get_path(struct conn *conn, const char *src,
+		int src_len, char *dst, int dst_len)
+{
+	static struct vec	accepted[] = {
+		{"\"",		1},	/* Relative to webserver CWD	*/
+		{"file=\"", 	6},	/* Relative to current URI	*/
+		{"virtual=\"", 	9},	/* Relative to document root	*/
+		{NULL,		0},
+	};
+	struct vec	*vec;
+	const char	*p, *root = conn->ctx->options[OPT_ROOT];
+	int		len;
+
+	for (vec = accepted; vec->len > 0; vec++)
+		if (src_len > vec->len && !memcmp(src, vec->ptr, vec->len)) {
+			src += vec->len;
+			src_len -= vec->len;
+			if ((p = memchr(src, '"', src_len)) == NULL)
+				break;
+			if (vec->len == 6) {
+				len = _shttpd_snprintf(dst, dst_len, "%s%c%s",
+				    root, DIRSEP, conn->uri);
+				while (len > 0 && dst[len] != '/')
+					len--;
+				dst += len;
+				dst_len -= len;
+			} else if (vec->len == 9) {
+				len = _shttpd_snprintf(dst, dst_len, "%s%c",
+				    root, DIRSEP);
+				dst += len;
+				dst_len -= len;
+			}
+			_shttpd_url_decode(src, p - src, dst, dst_len);
+			return (1);
+		}
+
+	return (0);
+}
+
+static void
+do_include(struct ssi *ssi)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	char		buf[FILENAME_MAX];
+	FILE		*fp;
+
+	assert(inc->nbuf >= 13);
+
+	if (inc->cond == SSI_STOP) {
+		/* Do nothing - conditional FALSE */
+	} else if (ssi->nest >= (int) NELEMS(ssi->incs) - 1) {
+		_shttpd_elog(E_LOG, ssi->conn,
+		    "ssi: #include: maximum nested level reached");
+	} else if (!get_path(ssi->conn,
+	    inc->buf + 13, inc->nbuf - 13, buf, sizeof(buf))) {
+		_shttpd_elog(E_LOG, ssi->conn, "ssi: bad #include: [%.*s]",
+		    inc->nbuf, inc->buf);
+	} else if ((fp = fopen(buf, "r")) == NULL) {
+		_shttpd_elog(E_LOG, ssi->conn, 
+		    "ssi: fopen(%s): %s", buf, strerror(errno));
+	} else {
+		ssi->nest++;
+		ssi->incs[ssi->nest].fp = fp;
+		ssi->incs[ssi->nest].nbuf = 0;
+		ssi->incs[ssi->nest].cond = SSI_GO;
+	}
+}
+
+static char *
+trim_spaces(struct ssi_inc *inc)
+{
+	char	*p = inc->buf + inc->nbuf - 2;
+
+	/* Trim spaces from the right */
+	*p-- = '\0';
+	while (isspace(* (unsigned char *) p))
+		*p-- = '\0';
+
+	/* Shift pointer to the start of attributes */
+	for (p = inc->buf; !isspace(* (unsigned char *) p); p++);
+	while (*p && isspace(* (unsigned char *) p)) p++;
+
+	return (p);
+}
+
+static void
+do_if(struct ssi *ssi)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	char		*name = trim_spaces(inc);
+
+	inc->cond = evaluate(ssi, name) ? SSI_GO : SSI_STOP;
+}
+
+static void
+do_elif(struct ssi *ssi)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	char		*name = trim_spaces(inc);
+
+	if (inc->cond == SSI_STOP && evaluate(ssi, name))
+		inc->cond = SSI_GO;
+	else
+		inc->cond = SSI_STOP;
+}
+static void
+do_endif(struct ssi *ssi)
+{
+	ssi->incs[ssi->nest].cond = SSI_GO;
+}
+
+static void
+do_else(struct ssi *ssi)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+
+	inc->cond = inc->cond == SSI_GO ? SSI_STOP : SSI_GO;
+}
+
+static void
+do_call2(struct ssi *ssi, char *buf, int len, int *n)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	struct shttpd_arg	arg;
+
+	call(ssi, inc->buf, &arg, buf, len);
+	(*n) += arg.out.num_bytes;
+	if (arg.flags & SHTTPD_END_OF_OUTPUT)
+		inc->state = SSI_PASS;
+}
+
+static void
+do_call(struct ssi *ssi, char *buf, int len, int *n)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	char		*name = trim_spaces(inc);
+
+	if (inc->cond == SSI_GO) {
+		(void) memmove(inc->buf, name, strlen(name) + 1);
+		inc->state = SSI_CALL;
+		do_call2(ssi, buf, len, n);
+	}
+}
+
+static void
+do_exec2(struct ssi *ssi, char *buf, int len, int *n)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	int		i, ch;
+
+	for (i = 0; i < len; i++) {
+		if ((ch = fgetc(inc->pipe)) == EOF) {
+			inc->state = SSI_PASS;
+			(void) pclose(inc->pipe);
+			inc->pipe = NULL;
+			break;
+		}
+		*buf++ = ch;
+		(*n)++;
+	}
+}
+
+static void
+do_exec(struct ssi *ssi, char *buf, int len, int *n)
+{
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	char		cmd[sizeof(inc->buf)], *e, *p;
+
+	p = trim_spaces(inc);
+
+	if (inc->cond == SSI_STOP) {
+		/* Do nothing - conditional FALSE */
+	} else if (*p != '"' || (e = strchr(p + 1, '"')) == NULL) {
+		_shttpd_elog(E_LOG, ssi->conn, "ssi: bad exec(%s)", p);
+	} else if (!_shttpd_url_decode(p + 1, e - p - 1, cmd, sizeof(cmd))) {
+		_shttpd_elog(E_LOG, ssi->conn,
+		    "ssi: cannot url_decode: exec(%s)", p);
+	} else if ((inc->pipe = popen(cmd, "r")) == NULL) {
+		_shttpd_elog(E_LOG, ssi->conn, "ssi: popen(%s)", cmd);
+	} else {
+		inc->state = SSI_EXEC;
+		do_exec2(ssi, buf, len, n);
+	}
+}
+
+static const struct ssi_cmd {
+	struct vec	vec;
+	void (*func)();
+} known_ssi_commands [] = {
+	{{"include ",	8}, do_include	},
+	{{"if ",	3}, do_if	},
+	{{"elif ",	5}, do_elif	},
+	{{"else",	4}, do_else	},
+	{{"endif",	5}, do_endif	},
+	{{"call ",	5}, do_call	},
+	{{"exec ",	5}, do_exec	},
+	{{NULL,		0}, NULL	}
+};
+
+static void
+do_command(struct ssi *ssi, char *buf, size_t len, int *n)
+{
+	struct ssi_inc		*inc = ssi->incs + ssi->nest;
+	const struct ssi_cmd	*cmd;
+
+	assert(len > 0);
+	assert(inc->nbuf <= len);
+	inc->state = SSI_PASS;
+
+	for (cmd = known_ssi_commands; cmd->func != NULL; cmd++)
+		if (inc->nbuf > (size_t) st.len + cmd->vec.len &&
+		    !memcmp(inc->buf + st.len, cmd->vec.ptr, cmd->vec.len)) {
+			cmd->func(ssi, buf, len, n);
+			break;
+		}
+
+	if (cmd->func == NULL)
+		pass(inc, buf, n);
+
+	inc->nbuf = 0;
+}
+
+static int
+read_ssi(struct stream *stream, void *vbuf, size_t len)
+{
+	struct ssi	*ssi = stream->conn->ssi;
+	struct ssi_inc	*inc = ssi->incs + ssi->nest;
+	char		*buf = vbuf;
+	int		ch = EOF, n = 0;
+
+again:
+
+	if (inc->state == SSI_CALL)
+		do_call2(ssi, buf, len, &n);
+	else if (inc->state == SSI_EXEC)
+		do_exec2(ssi, buf, len, &n);
+
+	while (n + inc->nbuf < len && (ch = fgetc(inc->fp)) != EOF)
+	
+		switch (inc->state) {
+
+		case SSI_PASS:
+			if (ch == '<') {
+				inc->nbuf = 0;
+				inc->buf[inc->nbuf++] = ch;
+				inc->state = SSI_BUF;
+			} else if (inc->cond == SSI_GO) {
+				buf[n++] = ch;
+			}
+			break;
+
+		/*
+		 * We are buffering whole SSI command, until closing "-->".
+		 * That means that when do_command() is called, we can rely
+		 * on that full command with arguments is buffered in and
+		 * there is no need for streaming.
+		 * Restrictions:
+		 *  1. The command must fit in CMDBUFSIZ
+		 *  2. HTML comments inside the command ? Not sure about this.
+		 */
+		case SSI_BUF:
+			if (inc->nbuf >= sizeof(inc->buf) - 1) {
+				pass(inc, buf + n, &n);
+			} else if (ch == '>' &&
+			    !memcmp(inc->buf + inc->nbuf - 2, "--", 2)) {
+				do_command(ssi, buf + n, len - n, &n);
+				inc = ssi->incs + ssi->nest;
+			} else {
+				inc->buf[inc->nbuf++] = ch;
+
+				/* If not SSI tag, pass it */
+				if (inc->nbuf <= (size_t) st.len &&
+				    memcmp(inc->buf, st.ptr, inc->nbuf) != 0)
+					pass(inc, buf + n, &n);
+			}
+			break;
+
+		case SSI_EXEC:
+		case SSI_CALL:
+			break;
+
+		default:
+			/* Never happens */
+			abort();
+			break;
+		}
+
+	if (ssi->nest > 0 && n + inc->nbuf < len && ch == EOF) {
+		(void) fclose(inc->fp);
+		inc->fp = NULL;
+		ssi->nest--;
+		inc--;
+		goto again;
+	}
+	
+	return (n);
+}
+
+static void
+close_ssi(struct stream *stream)
+{
+	struct ssi	*ssi = stream->conn->ssi;
+	size_t		i;
+
+	for (i = 0; i < NELEMS(ssi->incs); i++) {
+		if (ssi->incs[i].fp != NULL)
+			(void) fclose(ssi->incs[i].fp);
+		if (ssi->incs[i].pipe != NULL)
+			(void) pclose(ssi->incs[i].pipe);
+	}
+
+	free(ssi);
+}
+
+void
+_shttpd_do_ssi(struct conn *c)
+{
+	char		date[64];
+	struct ssi	*ssi;
+
+	(void) strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT",
+	    localtime(&_shttpd_current_time));
+
+	c->loc.io.head = c->loc.headers_len = _shttpd_snprintf(c->loc.io.buf,
+	    c->loc.io.size,
+	    "HTTP/1.1 200 OK\r\n"
+	    "Date: %s\r\n"
+	    "Content-Type: text/html\r\n"
+	    "Connection: close\r\n\r\n",
+	    date);
+
+	c->status = 200;
+	c->loc.io_class = &_shttpd_io_ssi;
+	c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
+
+	if (c->method == METHOD_HEAD) {
+		_shttpd_stop_stream(&c->loc);
+	} else if ((ssi = calloc(1, sizeof(struct ssi))) == NULL) {
+		_shttpd_send_server_error(c, 500,
+		    "Cannot allocate SSI descriptor");
+	} else {
+		ssi->incs[0].fp = fdopen(c->loc.chan.fd, "r");
+		ssi->conn = c;
+		c->ssi = ssi;
+	}
+}
+
+const struct io_class	_shttpd_io_ssi =  {
+	"ssi",
+	read_ssi,
+	NULL,
+	close_ssi
+};
+
+#endif /* !NO_SSI */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssl.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssl.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/io_ssl.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,85 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+#if !defined(NO_SSL)
+struct ssl_func	ssl_sw[] = {
+	{"SSL_free",			{0}},
+	{"SSL_accept",			{0}},
+	{"SSL_connect",			{0}},
+	{"SSL_read",			{0}},
+	{"SSL_write",			{0}},
+	{"SSL_get_error",		{0}},
+	{"SSL_set_fd",			{0}},
+	{"SSL_new",			{0}},
+	{"SSL_CTX_new",			{0}},
+	{"SSLv23_server_method",	{0}},
+	{"SSL_library_init",		{0}},
+	{"SSL_CTX_use_PrivateKey_file",	{0}},
+	{"SSL_CTX_use_certificate_file",{0}},
+	{NULL,				{0}}
+};
+
+void
+_shttpd_ssl_handshake(struct stream *stream)
+{
+	int	n;
+
+	if ((n = SSL_accept(stream->chan.ssl.ssl)) == 1) {
+		DBG(("handshake: SSL accepted"));
+		stream->flags |= FLAG_SSL_ACCEPTED;
+	} else {
+		n = SSL_get_error(stream->chan.ssl.ssl, n);
+		if (n != SSL_ERROR_WANT_READ && n != SSL_ERROR_WANT_WRITE)
+			stream->flags |= FLAG_CLOSED;
+		DBG(("SSL_accept error %d", n));
+	}
+}
+
+static int
+read_ssl(struct stream *stream, void *buf, size_t len)
+{
+	int	nread = -1;
+
+	assert(stream->chan.ssl.ssl != NULL);
+
+	if (!(stream->flags & FLAG_SSL_ACCEPTED))
+		_shttpd_ssl_handshake(stream);
+
+	if (stream->flags & FLAG_SSL_ACCEPTED)
+		nread = SSL_read(stream->chan.ssl.ssl, buf, len);
+
+	return (nread);
+}
+
+static int
+write_ssl(struct stream *stream, const void *buf, size_t len)
+{
+	assert(stream->chan.ssl.ssl != NULL);
+	return (SSL_write(stream->chan.ssl.ssl, buf, len));
+}
+
+static void
+close_ssl(struct stream *stream)
+{
+	assert(stream->chan.ssl.sock != -1);
+	assert(stream->chan.ssl.ssl != NULL);
+	(void) closesocket(stream->chan.ssl.sock);
+	SSL_free(stream->chan.ssl.ssl);
+}
+
+const struct io_class	_shttpd_io_ssl =  {
+	"ssl",
+	read_ssl,
+	write_ssl,
+	close_ssl
+};
+#endif /* !NO_SSL */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/llist.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/llist.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/llist.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,59 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#ifndef LLIST_HEADER_INCLUDED
+#define	LLIST_HEADER_INCLUDED
+
+/*
+ * Linked list macros.
+ */
+struct llhead {
+	struct llhead	*prev;
+	struct llhead	*next;
+};
+
+#define	LL_INIT(N)	((N)->next = (N)->prev = (N))
+
+#define LL_HEAD(H)	struct llhead H = { &H, &H }
+
+#define LL_ENTRY(P,T,N) ((T *)((char *)(P) - offsetof(T, N)))
+
+#define	LL_ADD(H, N)							\
+	do {								\
+		((H)->next)->prev = (N);				\
+		(N)->next = ((H)->next);				\
+		(N)->prev = (H);					\
+		(H)->next = (N);					\
+	} while (0)
+
+#define	LL_TAIL(H, N)							\
+	do {								\
+		((H)->prev)->next = (N);				\
+		(N)->prev = ((H)->prev);				\
+		(N)->next = (H);					\
+		(H)->prev = (N);					\
+	} while (0)
+
+#define	LL_DEL(N)							\
+	do {								\
+		((N)->next)->prev = ((N)->prev);			\
+		((N)->prev)->next = ((N)->next);			\
+		LL_INIT(N);						\
+	} while (0)
+
+#define	LL_EMPTY(N)	((N)->next == (N))
+
+#define	LL_FOREACH(H,N)	for (N = (H)->next; N != (H); N = (N)->next)
+
+#define LL_FOREACH_SAFE(H,N,T)						\
+	for (N = (H)->next, T = (N)->next; N != (H);			\
+			N = (T), T = (N)->next)
+
+#endif /* LLIST_HEADER_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/log.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/log.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/log.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,93 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+/*
+ * Log function
+ */
+void
+_shttpd_elog(int flags, struct conn *c, const char *fmt, ...)
+{
+	char	date[64], buf[URI_MAX];
+	int	len;
+	FILE	*fp = c == NULL ? NULL : c->ctx->error_log;
+	va_list	ap;
+
+	/* Print to stderr */
+	if (c == NULL || !IS_TRUE(c->ctx, OPT_INETD)) {
+		va_start(ap, fmt);
+		(void) vfprintf(stderr, fmt, ap);
+		(void) fputc('\n', stderr);
+		va_end(ap);
+	}
+
+	strftime(date, sizeof(date), "%a %b %d %H:%M:%S %Y",
+	    localtime(&_shttpd_current_time));
+
+	len = _shttpd_snprintf(buf, sizeof(buf),
+	    "[%s] [error] [client %s] \"%s\" ",
+	    date, c ? inet_ntoa(c->sa.u.sin.sin_addr) : "-",
+	    c && c->request ? c->request : "-");
+
+	va_start(ap, fmt);
+	(void) vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
+	va_end(ap);
+
+	buf[sizeof(buf) - 1] = '\0';
+
+	if (fp != NULL && (flags & (E_FATAL | E_LOG))) {
+		(void) fprintf(fp, "%s\n", buf);
+		(void) fflush(fp);
+	}
+
+	if (flags & E_FATAL)
+		exit(EXIT_FAILURE);
+}
+
+void
+_shttpd_log_access(FILE *fp, const struct conn *c)
+{
+	static const struct vec	dash = {"-", 1};
+
+	const struct vec	*user = &c->ch.user.v_vec;
+	const struct vec	*referer = &c->ch.referer.v_vec;
+	const struct vec	*user_agent = &c->ch.useragent.v_vec;
+	char			date[64], buf[URI_MAX], *q1 = "\"", *q2 = "\"";
+
+	if (user->len == 0)
+		user = ‐
+
+	if (referer->len == 0) {
+		referer = ‐
+		q1 = "";
+	}
+
+	if (user_agent->len == 0) {
+		user_agent = ‐
+		q2 = "";
+	}
+
+	(void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S",
+			localtime(&c->birth_time));
+
+	(void) _shttpd_snprintf(buf, sizeof(buf),
+	    "%s - %.*s [%s %+05d] \"%s\" %d %lu %s%.*s%s %s%.*s%s",
+	    inet_ntoa(c->sa.u.sin.sin_addr), user->len, user->ptr,
+	    date, _shttpd_tz_offset, c->request ? c->request : "-",
+	    c->status, (unsigned long) c->loc.io.total,
+	    q1, referer->len, referer->ptr, q1,
+	    q2, user_agent->len, user_agent->ptr, q2);
+
+	if (fp != NULL) {
+		(void) fprintf(fp, "%s\n", buf);
+		(void) fflush(fp);
+	}
+}

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,249 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "defs.h"
+
+#ifndef HAVE_MD5
+#if __BYTE_ORDER == 1234
+#define byteReverse(buf, len)	/* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+	uint32_t t;
+	do {
+		t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+			((unsigned) buf[1] << 8 | buf[0]);
+		*(uint32_t *) buf = t;
+		buf += 4;
+	} while (--longs);
+}
+#endif /* __BYTE_ORDER */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(MD5_CTX *ctx)
+{
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
+
+	ctx->bits[0] = 0;
+	ctx->bits[1] = 0;
+}
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+	register uint32_t a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
+{
+	uint32_t t;
+
+	/* Update bitcount */
+
+	t = ctx->bits[0];
+	if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+		ctx->bits[1]++;		/* Carry from low to high */
+	ctx->bits[1] += len >> 29;
+
+	t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+	/* Handle any leading odd-sized chunks */
+
+	if (t) {
+		unsigned char *p = (unsigned char *) ctx->in + t;
+
+		t = 64 - t;
+		if (len < t) {
+			memcpy(p, buf, len);
+			return;
+		}
+		memcpy(p, buf, t);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+		buf += t;
+		len -= t;
+	}
+	/* Process data in 64-byte chunks */
+
+	while (len >= 64) {
+		memcpy(ctx->in, buf, 64);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+
+	memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+	unsigned count;
+	unsigned char *p;
+
+	/* Compute number of bytes mod 64 */
+	count = (ctx->bits[0] >> 3) & 0x3F;
+
+	/* Set the first char of padding to 0x80.  This is safe since there is
+	   always at least one byte free */
+	p = ctx->in + count;
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 64 bytes */
+	count = 64 - 1 - count;
+
+	/* Pad out to 56 mod 64 */
+	if (count < 8) {
+		/* Two lots of padding:  Pad the first block to 64 bytes */
+		memset(p, 0, count);
+		byteReverse(ctx->in, 16);
+		MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+		/* Now fill the next block with 56 bytes */
+		memset(ctx->in, 0, 56);
+	} else {
+		/* Pad block to 56 bytes */
+		memset(p, 0, count - 8);
+	}
+	byteReverse(ctx->in, 14);
+
+	/* Append length in bits and transform */
+	((uint32_t *) ctx->in)[14] = ctx->bits[0];
+	((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+	MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+	byteReverse((unsigned char *) ctx->buf, 4);
+	memcpy(digest, ctx->buf, 16);
+	memset((char *) ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+#endif /* !HAVE_MD5 */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/md5.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,24 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#ifndef MD5_HEADER_INCLUDED
+#define	MD5_HEADER_INCLUDED
+
+typedef struct MD5Context {
+	uint32_t	buf[4];
+	uint32_t	bits[2];
+	unsigned char	in[64];
+} MD5_CTX;
+
+extern void MD5Init(MD5_CTX *ctx);
+extern void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len);
+extern void MD5Final(unsigned char digest[16], MD5_CTX *ctx);
+
+#endif /*MD5_HEADER_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd
==============================================================================
Binary file - no diff available.

Propchange: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.1
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.1 (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.1 Fri Jan 11 10:25:07 2013
@@ -1,0 +1,178 @@
+.\" Process this file with
+.\" groff -man -Tascii shttpd.1
+.\" $Id: shttpd.1,v 1.11 2008/05/31 18:25:49 drozd Exp $
+.Dd Feb 12, 2008
+.Dt SHTTPD 1
+.Sh NAME
+.Nm shttpd
+.Nd lightweight web server
+.Sh SYNOPSIS
+.Nm
+.Op Ar options
+.Op Ar config_file
+.Nm
+.Fl A Ar htpasswd_file domain_name user_name password
+.Sh DESCRIPTION
+.Nm
+is small, fast and easy to use web server with CGI, SSL, Digest Authorization
+support. It can be run as stand-alone server, be managed by
+.Xr inetd 8
+, or be embedded into existing C/C++ application.
+.Pp
+.Nm
+does not detach from terminal, and makes current working directory
+be the web root, unless
+.Fl root
+option is specified.
+.Pp
+Unlike other web servers,
+.Nm
+does not expect CGI scirpts to be put in a special directory. They may be
+anywhere. CGI files are recognized by the file extension.
+.Pp
+SSI files are also recognized by extension. Currently, the only SSI directives
+supported are `<!--#include "url-encoded-path" -->'
+and `<!--#exec "program" -->'. The `url-encoded-path' can be relative to
+.Nm
+working directory, or absolute system path. In the embedded mode, more
+directives are available: #call, #if/#elif/#endif/#else/#endif.
+Unsupported SSI directives are silently ignored.
+.Pp
+It is possible to specify multiple ports to listen on. For example, to
+make
+.Nm
+listen on HTTP port 80 and HTTPS port 443, one should start it as
+.Sq shttpd -ssl_cert cert.pem -ports 80,443s
+.Pp
+.Nm
+can use the configuration file. By default, it is "shttpd.conf", and if it
+is present in the same directory where
+.Nm
+lives, the command line options are read from it. Alternatively, the
+configuration file may be specified as a last argument. The format of the
+configuration file is exactly the same as for the command line options, the
+only difference is that the command line options must be specified on
+separate lines, and leading dashes for option names must be omitted.
+Lines beginning with '#' are regarded as comments and ignored.
+.Pp
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl A Ar htpasswd_file domain_name user_name password
+Add/edit user's password in the passwords file. Deleting users can be done
+with any text editor. Functionality similar to Apache's
+.Ic htdigest
+utility.
+.It Fl access_log Ar file
+Access log file. Default: not set, no logging is done.
+.It Fl acl Ar (+|-)x.x.x.x[/x],...
+Specify access control list (ACL). ACL is a comma separated list
+of IP subnets, each subnet is prepended by '-' or '+' sign. Plus means allow,
+minus means deny. If subnet mask is
+omitted, like "-1.2.3.4", then it means single IP address. Mask may vary
+from 0 to 32 inclusive. Default: not set, allow all.
+.It Fl aliases Ar list
+This options gives an ability to serve the directories outside web root
+by sort of symbolic linking to certain URI. The
+.Ar list
+must be comma-separated list of URI=PATH pairs, like this:
+"/etc/=/my_etc,/tmp=/my_tmp". Default: not set.
+.It Fl auth_PUT Ar file
+PUT and DELETE passwords file. This must be specified if PUT or
+DELETE methods are used. Default: not set.
+.It Fl auth_gpass Ar file
+Location of global passwords file. When set, per-directory .htpasswd files are
+ignored, and all accessed must be authorised against global passwords file.
+Default: not set.
+.It Fl auth_realm Ar domain_name
+Authorization realm. Default: "mydomain.com".
+.It Fl cfg_uri Ar uri
+If set,
+.Nm
+creates special administrative URI where options may be changed at runtime.
+This URI probably wants to be password-protected, look at
+.Fl protect
+option, and in the EXAMPLES section on how to do it. Default: not set.
+.It Fl cgi_env Ar list
+Pass environment variables to the CGI script in addition to standard ones.
+The list must be comma-separated list of X=Y pairs, like this:
+"VARIABLE1=VALUE1,VARIABLE2=VALUE2".  Default: not set.
+.It Fl cgi_ext Ar list
+Comma-separated list of CGI extensions.  All files having these extensions
+are treated as CGI scripts. Default: "cgi,pl,php"
+.It Fl cgi_interp Ar file
+Force
+.Ar file
+to be a CGI interpreter for all CGI scripts. By default this option is not
+set, and
+.Nm
+decides which interpreter to use by looking at the first line of CGI script.
+.It Fl dir_list Ar yes|no
+Enable/disable directory listing. Default: "1" (enabled).
+.It Fl error_log Ar file
+Error log file. Default: not set, no errors are logged.
+.It Fl inetd Ar yes|no
+Enable/disable inetd mode. Default: "0" (disabled).
+.It Fl mime_types Ar list
+Additional to builtin mime types, in form "EXTENSION1=TYPE1,EXTENSION2=TYPE2".
+.It Fl ports Ar port_list
+Comma-separated list of ports to listen on. If the port is SSL, a letter 's'
+must be appeneded, for example, "80,443s" will open port 80 and port 443,
+and connections on port 443 will be SSL-ed. Default: 80
+.It Fl protect Ar list
+Comma separated list of URI=PATH pairs, specifying that given URIs
+must the protected with respected password files. Default: not set.
+.It Fl root Ar directory
+Location of the WWW root directory. Default: working directory from which
+.Nm
+has been started.
+.It Fl ssi_ext Ar list
+Comma separated list of SSI extensions. Default: "shtml,shtm".
+.It Fl ssl_cert Ar pem_file
+Location of SSL certificate file. Default: not set.
+.It Fl systray Ar yes|no
+Hide console and put an icon on system tray (Windows only). Default: no.
+.It Fl threads Ar num_threads
+Number of worker threads. If 1, no threads are spawned, and
+.Nm
+operates as single threaded program. Default: 1.
+.It Fl uid Ar login
+Switch to given user after startup. Default: not set.
+.El
+.Pp
+.Sh EMBEDDING
+.Nm
+can be built as a library to embed web server functionality
+into C/C++ application. The API functions are declared in a header
+file
+.Pa shttpd.h .
+Please refer to the source package for a header file and the examples.
+.Pp
+.Sh EXAMPLES
+.Bl -tag -width indent
+.It Nm Fl root Ar /var/www Fl ports Ar 8080,8043s Fl ssl_cert Ar /etc/cert.pem Fl aliases Ar /aa=/tmp,/bb=/etc
+Start listening on port 8080 for HTTP, and 8043 for HTTPS connections.
+Use /etc/cert.pem as SSL certificate file. Web root is /var/www. In addition,
+map directory /tmp to URI /aa, directory /etc to URI /bb.
+.It Nm Fl acl Ar -0.0.0.0/0,+10.0.0.0/8,+1.2.3.4
+Deny connections from everywhere, allow only IP address 1.2.3.4 and
+all IP addresses from 10.0.0.0/8 subnet to connect.
+.It Nm Fl ports Ar 8080 Fl cfg_uri Ar /ctl Fl protect Ar /ctl=/tmp/passwords.txt
+Start listening on port 8080, create an administrative URI "/ctl" where
+options may be changed at runtime, and protect that URI with authorization.
+.It http stream tcp nowait nobody /bin/shttpd shttpd -inetd 1 -root /var/www
+This line in
+.Pa /etc/inetd.conf
+makes
+.Nm
+run by
+.Xr inetd 8
+daemon.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr inetd 8 .
+.Sh COPYRIGHT
+.Nm
+is licensed under the terms of beerware license.
+.Sh AUTHOR
+.An Sergey Lyubka Aq valenok at gmail.com .

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,1925 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+/*
+ * Small and portable HTTP server, http://shttpd.sourceforge.net
+ * $Id: shttpd.c,v 1.57 2008/08/23 21:00:38 drozd Exp $
+ */
+
+#include "defs.h"
+
+time_t	_shttpd_current_time;	/* Current UTC time		*/
+int	_shttpd_tz_offset;	/* Time zone offset from UTC	*/
+int	_shttpd_exit_flag;	/* Program exit flag		*/
+
+const struct vec _shttpd_known_http_methods[] = {
+	{"GET",		3},
+	{"POST",	4},
+	{"PUT",		3},
+	{"DELETE",	6},
+	{"HEAD",	4},
+	{NULL,		0}
+};
+
+/*
+ * This structure tells how HTTP headers must be parsed.
+ * Used by parse_headers() function.
+ */
+#define	OFFSET(x)	offsetof(struct headers, x)
+static const struct http_header http_headers[] = {
+	{16, HDR_INT,	 OFFSET(cl),		"Content-Length: "	},
+	{14, HDR_STRING, OFFSET(ct),		"Content-Type: "	},
+	{12, HDR_STRING, OFFSET(useragent),	"User-Agent: "		},
+	{19, HDR_DATE,	 OFFSET(ims),		"If-Modified-Since: "	},
+	{15, HDR_STRING, OFFSET(auth),		"Authorization: "	},
+	{9,  HDR_STRING, OFFSET(referer),	"Referer: "		},
+	{8,  HDR_STRING, OFFSET(cookie),	"Cookie: "		},
+	{10, HDR_STRING, OFFSET(location),	"Location: "		},
+	{8,  HDR_INT,	 OFFSET(status),	"Status: "		},
+	{7,  HDR_STRING, OFFSET(range),		"Range: "		},
+	{12, HDR_STRING, OFFSET(connection),	"Connection: "		},
+	{19, HDR_STRING, OFFSET(transenc),	"Transfer-Encoding: "	},
+	{0,  HDR_INT,	 0,			NULL			}
+};
+
+struct shttpd_ctx *init_ctx(const char *config_file, int argc, char *argv[]);
+static void process_connection(struct conn *, int, int);
+
+int
+_shttpd_is_true(const char *str)
+{
+	static const char	*trues[] = {"1", "yes", "true", "jawohl", NULL};
+	const char		**p;
+
+	for (p = trues; *p != NULL; p++)
+		if (str && !strcmp(str, *p))
+			return (TRUE);
+
+	return (FALSE);
+}
+
+static void
+free_list(struct llhead *head, void (*dtor)(struct llhead *))
+{
+	struct llhead	*lp, *tmp;
+
+	LL_FOREACH_SAFE(head, lp, tmp) {
+		LL_DEL(lp);
+		dtor(lp);
+	}
+}
+
+static void
+listener_destructor(struct llhead *lp)
+{
+	struct listener	*listener = LL_ENTRY(lp, struct listener, link);
+
+	(void) closesocket(listener->sock);
+	free(listener);
+}
+
+static void
+registered_uri_destructor(struct llhead *lp)
+{
+	struct registered_uri *ruri = LL_ENTRY(lp, struct registered_uri, link);
+
+	free((void *) ruri->uri);
+	free(ruri);
+}
+
+static void
+acl_destructor(struct llhead *lp)
+{
+	struct acl	*acl = LL_ENTRY(lp, struct acl, link);
+	free(acl);
+}
+
+int
+_shttpd_url_decode(const char *src, int src_len, char *dst, int dst_len)
+{
+	int	i, j, a, b;
+#define	HEXTOI(x)  (isdigit(x) ? x - '0' : x - 'W')
+
+	for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++)
+		switch (src[i]) {
+		case '%':
+			if (isxdigit(((unsigned char *) src)[i + 1]) &&
+			    isxdigit(((unsigned char *) src)[i + 2])) {
+				a = tolower(((unsigned char *)src)[i + 1]);
+				b = tolower(((unsigned char *)src)[i + 2]);
+				dst[j] = (HEXTOI(a) << 4) | HEXTOI(b);
+				i += 2;
+			} else {
+				dst[j] = '%';
+			}
+			break;
+		default:
+			dst[j] = src[i];
+			break;
+		}
+
+	dst[j] = '\0';	/* Null-terminate the destination */
+
+	return (j);
+}
+
+static const char *
+is_alias(struct shttpd_ctx *ctx, const char *uri,
+		struct vec *a_uri, struct vec *a_path)
+{
+	const char	*p, *s = ctx->options[OPT_ALIASES];
+	size_t		len;
+
+	DBG(("is_alias: aliases [%s]", s == NULL ? "" : s));
+
+	FOR_EACH_WORD_IN_LIST(s, len) {
+
+		if ((p = memchr(s, '=', len)) == NULL || p >= s + len || p == s)
+			continue;
+
+		if (memcmp(uri, s, p - s) == 0) {
+			a_uri->ptr = s;
+			a_uri->len = p - s;
+			a_path->ptr = ++p;
+			a_path->len = (s + len) - p;
+			return (s);
+		}
+	}
+
+	return (NULL);
+}
+
+void
+_shttpd_stop_stream(struct stream *stream)
+{
+	if (stream->io_class != NULL && stream->io_class->close != NULL)
+		stream->io_class->close(stream);
+
+	stream->io_class= NULL;
+	stream->flags |= FLAG_CLOSED;
+	stream->flags &= ~(FLAG_R | FLAG_W | FLAG_ALWAYS_READY);
+
+	DBG(("%d %s stopped. %lu of content data, %d now in a buffer",
+	    stream->conn->rem.chan.sock, 
+	    stream->io_class ? stream->io_class->name : "(null)",
+	    (unsigned long) stream->io.total, (int) io_data_len(&stream->io)));
+}
+
+/*
+ * Setup listening socket on given port, return socket
+ */
+static int
+shttpd_open_listening_port(int port)
+{
+	int		sock, on = 1;
+	struct usa	sa;
+
+#ifdef _WIN32
+	{WSADATA data;	WSAStartup(MAKEWORD(2,2), &data);}
+#endif /* _WIN32 */
+
+	sa.len				= sizeof(sa.u.sin);
+	sa.u.sin.sin_family		= AF_INET;
+	sa.u.sin.sin_port		= htons((uint16_t) port);
+	sa.u.sin.sin_addr.s_addr	= htonl(INADDR_ANY);
+
+	if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == -1)
+		goto fail;
+	if (_shttpd_set_non_blocking_mode(sock) != 0)
+		goto fail;
+	if (setsockopt(sock, SOL_SOCKET,
+	    SO_REUSEADDR,(char *) &on, sizeof(on)) != 0)
+		goto fail;
+	if (bind(sock, &sa.u.sa, sa.len) < 0)
+		goto fail;
+	if (listen(sock, 128) != 0)
+		goto fail;
+
+#ifndef _WIN32
+	(void) fcntl(sock, F_SETFD, FD_CLOEXEC);
+#endif /* !_WIN32 */
+
+	return (sock);
+fail:
+	if (sock != -1)
+		(void) closesocket(sock);
+	_shttpd_elog(E_LOG, NULL, "open_listening_port(%d): %s", port, strerror(errno));
+	return (-1);
+}
+
+/*
+ * Check whether full request is buffered Return headers length, or 0
+ */
+int
+_shttpd_get_headers_len(const char *buf, size_t buflen)
+{
+	const char	*s, *e;
+	int		len = 0;
+
+	for (s = buf, e = s + buflen - 1; len == 0 && s < e; s++)
+		/* Control characters are not allowed but >=128 is. */
+		if (!isprint(* (unsigned char *) s) && *s != '\r' &&
+		    *s != '\n' && * (unsigned char *) s < 128)
+			len = -1;
+		else if (s[0] == '\n' && s[1] == '\n')
+			len = s - buf + 2;
+		else if (s[0] == '\n' && &s[1] < e &&
+		    s[1] == '\r' && s[2] == '\n')
+			len = s - buf + 3;
+
+	return (len);
+}
+
+/*
+ * Send error message back to a client.
+ */
+void
+_shttpd_send_server_error(struct conn *c, int status, const char *reason)
+{
+	struct llhead		*lp;
+	struct error_handler	*e;
+
+	LL_FOREACH(&c->ctx->error_handlers, lp) {
+		e = LL_ENTRY(lp, struct error_handler, link);
+
+		if (e->code == status) {
+			if (c->loc.io_class != NULL &&
+			    c->loc.io_class->close != NULL)
+				c->loc.io_class->close(&c->loc);
+			io_clear(&c->loc.io);
+			_shttpd_setup_embedded_stream(c,
+			    e->callback, e->callback_data);
+			return;
+		}
+	}
+
+	io_clear(&c->loc.io);
+	c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
+	    "HTTP/1.1 %d %s\r\n"
+	    "Content-Type: text/plain\r\n"
+	    "Content-Length: 12\r\n"
+	    "\r\n"
+	    "Error: %03d\r\n",
+	    status, reason, status);
+	c->loc.content_len = 10;
+	c->status = status;
+	_shttpd_stop_stream(&c->loc);
+}
+
+/*
+ * Convert month to the month number. Return -1 on error, or month number
+ */
+static int
+montoi(const char *s)
+{
+	static const char *ar[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	size_t	i;
+
+	for (i = 0; i < sizeof(ar) / sizeof(ar[0]); i++)
+		if (!strcmp(s, ar[i]))
+			return (i);
+
+	return (-1);
+}
+
+/*
+ * Parse date-time string, and return the corresponding time_t value
+ */
+static time_t
+date_to_epoch(const char *s)
+{
+	struct tm	tm, *tmp;
+	char		mon[32];
+	int		sec, min, hour, mday, month, year;
+
+	(void) memset(&tm, 0, sizeof(tm));
+	sec = min = hour = mday = month = year = 0;
+
+	if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
+	    &mday, mon, &year, &hour, &min, &sec) == 6) ||
+	    (sscanf(s, "%d %3s %d %d:%d:%d",
+	    &mday, mon, &year, &hour, &min, &sec) == 6) ||
+	    (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
+	    &mday, mon, &year, &hour, &min, &sec) == 6) ||
+	    (sscanf(s, "%d-%3s-%d %d:%d:%d",
+	    &mday, mon, &year, &hour, &min, &sec) == 6)) &&
+	    (month = montoi(mon)) != -1) {
+		tm.tm_mday	= mday;
+		tm.tm_mon	= month;
+		tm.tm_year	= year;
+		tm.tm_hour	= hour;
+		tm.tm_min	= min;
+		tm.tm_sec	= sec;
+	}
+
+	if (tm.tm_year > 1900)
+		tm.tm_year -= 1900;
+	else if (tm.tm_year < 70)
+		tm.tm_year += 100;
+
+	/* Set Daylight Saving Time field */
+	tmp = localtime(&_shttpd_current_time);
+	tm.tm_isdst = tmp->tm_isdst;
+
+	return (mktime(&tm));
+}
+
+static void
+remove_double_dots(char *s)
+{
+	char	*p = s;
+
+	while (*s != '\0') {
+		*p++ = *s++;
+		if (s[-1] == '/' || s[-1] == '\\')
+			while (*s == '.' || *s == '/' || *s == '\\')
+				s++;
+	}
+	*p = '\0';
+}
+
+void
+_shttpd_parse_headers(const char *s, int len, struct headers *parsed)
+{
+	const struct http_header	*h;
+	union variant			*v;
+	const char			*p, *e = s + len;
+
+	DBG(("parsing headers (len %d): [%.*s]", len, len, s));
+
+	/* Loop through all headers in the request */
+	while (s < e) {
+
+		/* Find where this header ends */
+		for (p = s; p < e && *p != '\n'; ) p++;
+
+		/* Is this header known to us ? */
+		for (h = http_headers; h->len != 0; h++)
+			if (e - s > h->len &&
+			    !_shttpd_strncasecmp(s, h->name, h->len))
+				break;
+
+		/* If the header is known to us, store its value */
+		if (h->len != 0) {
+
+			/* Shift to where value starts */
+			s += h->len;
+
+			/* Find place to store the value */
+			v = (union variant *) ((char *) parsed + h->offset);
+
+			/* Fetch header value into the connection structure */
+			if (h->type == HDR_STRING) {
+				v->v_vec.ptr = s;
+				v->v_vec.len = p - s;
+				if (p[-1] == '\r' && v->v_vec.len > 0)
+					v->v_vec.len--;
+			} else if (h->type == HDR_INT) {
+				v->v_big_int = strtoul(s, NULL, 10);
+			} else if (h->type == HDR_DATE) {
+				v->v_time = date_to_epoch(s);
+			}
+		}
+
+		s = p + 1;	/* Shift to the next header */
+	}
+}
+
+static const struct {
+	const char	*extension;
+	int		ext_len;
+	const char	*mime_type;
+} builtin_mime_types[] = {
+	{"html",	4,	"text/html"			},
+	{"htm",		3,	"text/html"			},
+	{"txt",		3,	"text/plain"			},
+	{"css",		3,	"text/css"			},
+	{"ico",		3,	"image/x-icon"			},
+	{"gif",		3,	"image/gif"			},
+	{"jpg",		3,	"image/jpeg"			},
+	{"jpeg",	4,	"image/jpeg"			},
+	{"png",		3,	"image/png"			},
+	{"svg",		3,	"image/svg+xml"			},
+	{"torrent",	7,	"application/x-bittorrent"	},
+	{"wav",		3,	"audio/x-wav"			},
+	{"mp3",		3,	"audio/x-mp3"			},
+	{"mid",		3,	"audio/mid"			},
+	{"m3u",		3,	"audio/x-mpegurl"		},
+	{"ram",		3,	"audio/x-pn-realaudio"		},
+	{"ra",		2,	"audio/x-pn-realaudio"		},
+	{"doc",		3,	"application/msword",		},
+	{"exe",		3,	"application/octet-stream"	},
+	{"zip",		3,	"application/x-zip-compressed"	},
+	{"xls",		3,	"application/excel"		},
+	{"tgz",		3,	"application/x-tar-gz"		},
+	{"tar.gz",	6,	"application/x-tar-gz"		},
+	{"tar",		3,	"application/x-tar"		},
+	{"gz",		2,	"application/x-gunzip"		},
+	{"arj",		3,	"application/x-arj-compressed"	},
+	{"rar",		3,	"application/x-arj-compressed"	},
+	{"rtf",		3,	"application/rtf"		},
+	{"pdf",		3,	"application/pdf"		},
+	{"swf",		3,	"application/x-shockwave-flash"	},
+	{"mpg",		3,	"video/mpeg"			},
+	{"mpeg",	4,	"video/mpeg"			},
+	{"asf",		3,	"video/x-ms-asf"		},
+	{"avi",		3,	"video/x-msvideo"		},
+	{"bmp",		3,	"image/bmp"			},
+	{NULL,		0,	NULL				}
+};
+
+void
+_shttpd_get_mime_type(struct shttpd_ctx *ctx,
+		const char *uri, int len, struct vec *vec)
+{
+	const char	*eq, *p = ctx->options[OPT_MIME_TYPES];
+	int		i, n, ext_len;
+
+	/* Firt, loop through the custom mime types if any */
+	FOR_EACH_WORD_IN_LIST(p, n) {
+		if ((eq = memchr(p, '=', n)) == NULL || eq >= p + n || eq == p)
+			continue;
+		ext_len = eq - p;
+		if (len > ext_len && uri[len - ext_len - 1] == '.' &&
+		    !_shttpd_strncasecmp(p, &uri[len - ext_len], ext_len)) {
+			vec->ptr = eq + 1;
+			vec->len = p + n - vec->ptr;
+			return;
+		}
+	}
+
+	/* If no luck, try built-in mime types */
+	for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
+		ext_len = builtin_mime_types[i].ext_len;
+		if (len > ext_len && uri[len - ext_len - 1] == '.' &&
+		    !_shttpd_strncasecmp(builtin_mime_types[i].extension,
+			    &uri[len - ext_len], ext_len)) {
+			vec->ptr = builtin_mime_types[i].mime_type;
+			vec->len = strlen(vec->ptr);
+			return;
+		}
+	}
+
+	/* Oops. This extension is unknown to us. Fallback to text/plain */
+	vec->ptr = "text/plain";
+	vec->len = strlen(vec->ptr);
+}
+
+/*
+ * For given directory path, substitute it to valid index file.
+ * Return 0 if index file has been found, -1 if not found
+ */
+static int
+find_index_file(struct conn *c, char *path, size_t maxpath, struct stat *stp)
+{
+	char		buf[FILENAME_MAX];
+	const char	*s = c->ctx->options[OPT_INDEX_FILES];
+	size_t		len;
+
+	FOR_EACH_WORD_IN_LIST(s, len) {
+		/* path must end with '/' character */
+		_shttpd_snprintf(buf, sizeof(buf), "%s%.*s", path, len, s);
+		if (_shttpd_stat(buf, stp) == 0) {
+			_shttpd_strlcpy(path, buf, maxpath);
+			_shttpd_get_mime_type(c->ctx, s, len, &c->mime_type);
+			return (0);
+		}
+	}
+
+	return (-1);
+}
+
+/*
+ * Try to open requested file, return 0 if OK, -1 if error.
+ * If the file is given arguments using PATH_INFO mechanism,
+ * initialize pathinfo pointer.
+ */
+static int
+get_path_info(struct conn *c, char *path, struct stat *stp)
+{
+	char	*p, *e;
+
+	if (_shttpd_stat(path, stp) == 0)
+		return (0);
+
+	p = path + strlen(path);
+	e = path + strlen(c->ctx->options[OPT_ROOT]) + 2;
+	
+	/* Strip directory parts of the path one by one */
+	for (; p > e; p--)
+		if (*p == '/') {
+			*p = '\0';
+			if (!_shttpd_stat(path, stp) && !S_ISDIR(stp->st_mode)) {
+				c->path_info = p + 1;
+				return (0);
+			} else {
+				*p = '/';
+			}
+		}
+
+	return (-1);
+}
+
+static void
+decide_what_to_do(struct conn *c)
+{
+	char		path[URI_MAX], buf[1024], *root;
+	struct vec	alias_uri, alias_path;
+	struct stat	st;
+	int		rc;
+	struct registered_uri	*ruri;
+
+	DBG(("decide_what_to_do: [%s]", c->uri));
+
+	if ((c->query = strchr(c->uri, '?')) != NULL)
+		*c->query++ = '\0';
+
+	_shttpd_url_decode(c->uri, strlen(c->uri), c->uri, strlen(c->uri) + 1);
+	remove_double_dots(c->uri);
+	
+	root = c->ctx->options[OPT_ROOT];
+	if (strlen(c->uri) + strlen(root) >= sizeof(path)) {
+		_shttpd_send_server_error(c, 400, "URI is too long");
+		return;
+	}
+
+	(void) _shttpd_snprintf(path, sizeof(path), "%s%s", root, c->uri);
+
+	/* User may use the aliases - check URI for mount point */
+	if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL) {
+		(void) _shttpd_snprintf(path, sizeof(path), "%.*s%s",
+		    alias_path.len, alias_path.ptr, c->uri + alias_uri.len);
+		DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr,
+		    alias_path.len, alias_path.ptr));
+	}
+
+#if !defined(NO_AUTH)
+	if (_shttpd_check_authorization(c, path) != 1) {
+		_shttpd_send_authorization_request(c);
+	} else
+#endif /* NO_AUTH */
+	if ((ruri = _shttpd_is_registered_uri(c->ctx, c->uri)) != NULL) {
+		_shttpd_setup_embedded_stream(c,
+		    ruri->callback, ruri->callback_data);
+	} else
+	if (strstr(path, HTPASSWD)) {
+		/* Do not allow to view passwords files */
+		_shttpd_send_server_error(c, 403, "Forbidden");
+	} else
+#if !defined(NO_AUTH)
+	if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) &&
+	    (c->ctx->options[OPT_AUTH_PUT] == NULL ||
+	     !_shttpd_is_authorized_for_put(c))) {
+		_shttpd_send_authorization_request(c);
+	} else
+#endif /* NO_AUTH */
+	if (c->method == METHOD_PUT) {
+		c->status = _shttpd_stat(path, &st) == 0 ? 200 : 201;
+
+		if (c->ch.range.v_vec.len > 0) {
+			_shttpd_send_server_error(c, 501,
+			    "PUT Range Not Implemented");
+		} else if ((rc = _shttpd_put_dir(path)) == 0) {
+			_shttpd_send_server_error(c, 200, "OK");
+		} else if (rc == -1) {
+			_shttpd_send_server_error(c, 500, "PUT Directory Error");
+		} else if (c->rem.content_len == 0) {
+			_shttpd_send_server_error(c, 411, "Length Required");
+		} else if ((c->loc.chan.fd = _shttpd_open(path, O_WRONLY | O_BINARY |
+		    O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1) {
+			_shttpd_send_server_error(c, 500, "PUT Error");
+		} else {
+			DBG(("PUT file [%s]", c->uri));
+			c->loc.io_class = &_shttpd_io_file;
+			c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ;
+		}
+	} else if (c->method == METHOD_DELETE) {
+		DBG(("DELETE [%s]", c->uri));
+		if (_shttpd_remove(path) == 0)
+			_shttpd_send_server_error(c, 200, "OK");
+		else
+			_shttpd_send_server_error(c, 500, "DELETE Error");
+	} else if (get_path_info(c, path, &st) != 0) {
+		_shttpd_send_server_error(c, 404, "Not Found");
+	} else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') {
+		(void) _shttpd_snprintf(buf, sizeof(buf),
+			"Moved Permanently\r\nLocation: %s/", c->uri);
+		_shttpd_send_server_error(c, 301, buf);
+	} else if (S_ISDIR(st.st_mode) &&
+	    find_index_file(c, path, sizeof(path) - 1, &st) == -1 &&
+	    !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
+		_shttpd_send_server_error(c, 403, "Directory Listing Denied");
+	} else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST)) {
+		if ((c->loc.chan.dir.path = _shttpd_strdup(path)) != NULL)
+			_shttpd_get_dir(c);
+		else
+			_shttpd_send_server_error(c, 500, "GET Directory Error");
+	} else if (S_ISDIR(st.st_mode) && !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
+		_shttpd_send_server_error(c, 403, "Directory listing denied");
+#if !defined(NO_CGI)
+	} else if (_shttpd_match_extension(path,
+	    c->ctx->options[OPT_CGI_EXTENSIONS])) {
+		if (c->method != METHOD_POST && c->method != METHOD_GET) {
+			_shttpd_send_server_error(c, 501, "Bad method ");
+		} else if ((_shttpd_run_cgi(c, path)) == -1) {
+			_shttpd_send_server_error(c, 500, "Cannot exec CGI");
+		} else {
+			_shttpd_do_cgi(c);
+		}
+#endif /* NO_CGI */
+#if !defined(NO_SSI)
+	} else if (_shttpd_match_extension(path,
+	    c->ctx->options[OPT_SSI_EXTENSIONS])) {
+		if ((c->loc.chan.fd = _shttpd_open(path,
+		    O_RDONLY | O_BINARY, 0644)) == -1) {
+			_shttpd_send_server_error(c, 500, "SSI open error");
+		} else {
+			_shttpd_do_ssi(c);
+		}
+#endif /* NO_CGI */
+	} else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time) {
+		_shttpd_send_server_error(c, 304, "Not Modified");
+	} else if ((c->loc.chan.fd = _shttpd_open(path,
+	    O_RDONLY | O_BINARY, 0644)) != -1) {
+		_shttpd_get_file(c, &st);
+	} else {
+		_shttpd_send_server_error(c, 500, "Internal Error");
+	}
+}
+
+static int
+set_request_method(struct conn *c)
+{
+	const struct vec	*v;
+
+	/* Set the request method */
+	for (v = _shttpd_known_http_methods; v->ptr != NULL; v++)
+		if (!memcmp(c->rem.io.buf, v->ptr, v->len)) {
+			c->method = v - _shttpd_known_http_methods;
+			break;
+		}
+
+	return (v->ptr == NULL);
+}
+
+static void
+parse_http_request(struct conn *c)
+{
+	char	*s, *e, *p, *start;
+	int	uri_len, req_len, n;
+
+	s = io_data(&c->rem.io);;
+	req_len = c->rem.headers_len =
+	    _shttpd_get_headers_len(s, io_data_len(&c->rem.io));
+
+	if (req_len == 0 && io_space_len(&c->rem.io) == 0) {
+		io_clear(&c->rem.io);
+		_shttpd_send_server_error(c, 400, "Request is too big");
+	}
+
+	if (req_len == 0) {
+		return;
+	} else if (req_len < 16) {	/* Minimal: "GET / HTTP/1.0\n\n" */
+		_shttpd_send_server_error(c, 400, "Bad request");
+	} else if (set_request_method(c)) {
+		_shttpd_send_server_error(c, 501, "Method Not Implemented");
+	} else if ((c->request = _shttpd_strndup(s, req_len)) == NULL) {
+		_shttpd_send_server_error(c, 500, "Cannot allocate request");
+	}
+
+	if (c->loc.flags & FLAG_CLOSED)
+		return;
+
+	io_inc_tail(&c->rem.io, req_len);
+
+	DBG(("Conn %d: parsing request: [%.*s]", c->rem.chan.sock, req_len, s));
+	c->rem.flags |= FLAG_HEADERS_PARSED;
+
+	/* Set headers pointer. Headers follow the request line */
+	c->headers = memchr(c->request, '\n', req_len);
+	assert(c->headers != NULL);
+	assert(c->headers < c->request + req_len);
+	if (c->headers > c->request && c->headers[-1] == '\r')
+		c->headers[-1] = '\0';
+	*c->headers++ = '\0';
+
+	/*
+	 * Now make a copy of the URI, because it will be URL-decoded,
+	 * and we need a copy of unmodified URI for the access log.
+	 * First, we skip the REQUEST_METHOD and shift to the URI.
+	 */
+	for (p = c->request, e = p + req_len; *p != ' ' && p < e; p++);
+	while (p < e && *p == ' ')
+		p++;
+
+	/* Now remember where URI starts, and shift to the end of URI */
+	for (start = p; p < e && !isspace((unsigned char)*p); ) p++;
+	uri_len = p - start;
+
+	/* Skip space following the URI */
+	while (p < e && *p == ' ')
+		p++;
+
+	/* Now comes the HTTP-Version in the form HTTP/<major>.<minor> */
+	if (sscanf(p, "HTTP/%lu.%lu%n",
+	    &c->major_version, &c->minor_version, &n) != 2 || p[n] != '\0') {
+		_shttpd_send_server_error(c, 400, "Bad HTTP version");
+	} else if (c->major_version > 1 ||
+	    (c->major_version == 1 && c->minor_version > 1)) {
+		_shttpd_send_server_error(c, 505, "HTTP version not supported");
+	} else if (uri_len <= 0) {
+		_shttpd_send_server_error(c, 400, "Bad URI");
+	} else if ((c->uri = malloc(uri_len + 1)) == NULL) {
+		_shttpd_send_server_error(c, 500, "Cannot allocate URI");
+	} else {
+		_shttpd_strlcpy(c->uri, (char *) start, uri_len + 1);
+		_shttpd_parse_headers(c->headers,
+		    (c->request + req_len) - c->headers, &c->ch);
+
+		/* Remove the length of request from total, count only data */
+		assert(c->rem.io.total >= (big_int_t) req_len);
+		c->rem.io.total -= req_len;
+		c->rem.content_len = c->ch.cl.v_big_int;
+		decide_what_to_do(c);
+	}
+}
+
+static void
+add_socket(struct worker *worker, int sock, int is_ssl)
+{
+	struct shttpd_ctx	*ctx = worker->ctx;
+	struct conn		*c;
+	struct usa		sa;
+	int			l = IS_TRUE(ctx, OPT_INETD) ? E_FATAL : E_LOG;
+#if !defined(NO_SSL)
+	SSL		*ssl = NULL;
+#else
+	is_ssl = is_ssl;	/* supress warnings */
+#endif /* NO_SSL */
+
+	sa.len = sizeof(sa.u.sin);
+	(void) _shttpd_set_non_blocking_mode(sock);
+
+	if (getpeername(sock, &sa.u.sa, &sa.len)) {
+		_shttpd_elog(l, NULL, "add_socket: %s", strerror(errno));
+#if !defined(NO_SSL)
+	} else if (is_ssl && (ssl = SSL_new(ctx->ssl_ctx)) == NULL) {
+		_shttpd_elog(l, NULL, "add_socket: SSL_new: %s", strerror(ERRNO));
+		(void) closesocket(sock);
+	} else if (is_ssl && SSL_set_fd(ssl, sock) == 0) {
+		_shttpd_elog(l, NULL, "add_socket: SSL_set_fd: %s", strerror(ERRNO));
+		(void) closesocket(sock);
+		SSL_free(ssl);
+#endif /* NO_SSL */
+	} else if ((c = calloc(1, sizeof(*c) + 2 * URI_MAX)) == NULL) {
+#if !defined(NO_SSL)
+		if (ssl)
+			SSL_free(ssl);
+#endif /* NO_SSL */
+		(void) closesocket(sock);
+		_shttpd_elog(l, NULL, "add_socket: calloc: %s", strerror(ERRNO));
+	} else {
+		c->rem.conn	= c->loc.conn = c;
+		c->ctx		= ctx;
+		c->worker	= worker;
+		c->sa		= sa;
+		c->birth_time	= _shttpd_current_time;
+		c->expire_time	= _shttpd_current_time + EXPIRE_TIME;
+
+		(void) getsockname(sock, &sa.u.sa, &sa.len);
+		c->loc_port = sa.u.sin.sin_port;
+
+		_shttpd_set_close_on_exec(sock);
+
+		c->loc.io_class	= NULL;
+	
+		c->rem.io_class	= &_shttpd_io_socket;
+		c->rem.chan.sock = sock;
+
+		/* Set IO buffers */
+		c->loc.io.buf	= (char *) (c + 1);
+		c->rem.io.buf	= c->loc.io.buf + URI_MAX;
+		c->loc.io.size	= c->rem.io.size = URI_MAX;
+
+#if !defined(NO_SSL)
+		if (is_ssl) {
+			c->rem.io_class	= &_shttpd_io_ssl;
+			c->rem.chan.ssl.sock = sock;
+			c->rem.chan.ssl.ssl = ssl;
+			_shttpd_ssl_handshake(&c->rem);
+		}
+#endif /* NO_SSL */
+
+		LL_TAIL(&worker->connections, &c->link);
+		worker->num_conns++;
+		
+		DBG(("%s:%hu connected (socket %d)",
+		    inet_ntoa(* (struct in_addr *) &sa.u.sin.sin_addr.s_addr),
+		    ntohs(sa.u.sin.sin_port), sock));
+	}
+}
+
+static struct worker *
+first_worker(struct shttpd_ctx *ctx)
+{
+	return (LL_ENTRY(ctx->workers.next, struct worker, link));
+}
+
+static void
+pass_socket(struct shttpd_ctx *ctx, int sock, int is_ssl)
+{
+	struct llhead	*lp;
+	struct worker	*worker, *lazy;
+	int		buf[3];
+
+	lazy = first_worker(ctx);
+
+	/* Find least busy worker */
+	LL_FOREACH(&ctx->workers, lp) {
+		worker = LL_ENTRY(lp, struct worker, link);
+		if (worker->num_conns < lazy->num_conns)
+			lazy = worker;
+	}
+
+	buf[0] = CTL_PASS_SOCKET;
+	buf[1] = sock;
+	buf[2] = is_ssl;
+
+	(void) send(lazy->ctl[1], (void *) buf, sizeof(buf), 0);
+}
+
+static int
+set_ports(struct shttpd_ctx *ctx, const char *p)
+{
+	int		sock, len, is_ssl, port;
+	struct listener	*l;
+
+
+	free_list(&ctx->listeners, &listener_destructor);
+
+	FOR_EACH_WORD_IN_LIST(p, len) {
+
+		is_ssl	= p[len - 1] == 's' ? 1 : 0;
+		port	= atoi(p);
+
+		if ((sock = shttpd_open_listening_port(port)) == -1) {
+			_shttpd_elog(E_LOG, NULL, "cannot open port %d", port);
+			goto fail;
+		} else if (is_ssl && ctx->ssl_ctx == NULL) {
+			(void) closesocket(sock);
+			_shttpd_elog(E_LOG, NULL, "cannot add SSL socket, "
+			    "please specify certificate file");
+			goto fail;
+		} else if ((l = calloc(1, sizeof(*l))) == NULL) {
+			(void) closesocket(sock);
+			_shttpd_elog(E_LOG, NULL, "cannot allocate listener");
+			goto fail;
+		} else {
+			l->is_ssl = is_ssl;
+			l->sock	= sock;
+			l->ctx	= ctx;
+			LL_TAIL(&ctx->listeners, &l->link);
+			DBG(("shttpd_listen: added socket %d", sock));
+		}
+	}
+
+	return (TRUE);
+fail:
+	free_list(&ctx->listeners, &listener_destructor);
+	return (FALSE);
+}
+
+static void
+read_stream(struct stream *stream)
+{
+	int	n, len;
+
+	len = io_space_len(&stream->io);
+	assert(len > 0);
+
+	/* Do not read more that needed */
+	if (stream->content_len > 0 &&
+	    stream->io.total + len > stream->content_len)
+		len = stream->content_len - stream->io.total;
+
+	/* Read from underlying channel */
+	assert(stream->io_class != NULL);
+	n = stream->io_class->read(stream, io_space(&stream->io), len);
+
+	if (n > 0)
+		io_inc_head(&stream->io, n);
+	else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
+		n = n;	/* Ignore EINTR and EAGAIN */
+	else if (!(stream->flags & FLAG_DONT_CLOSE))
+		_shttpd_stop_stream(stream);
+
+	DBG(("read_stream (%d %s): read %d/%d/%lu bytes (errno %d)",
+	    stream->conn->rem.chan.sock,
+	    stream->io_class ? stream->io_class->name : "(null)",
+	    n, len, (unsigned long) stream->io.total, ERRNO));
+
+	/*
+	 * Close the local stream if everything was read
+	 * XXX We do not close the remote stream though! It may be
+	 * a POST data completed transfer, we do not want the socket
+	 * to be closed.
+	 */
+	if (stream->content_len > 0 && stream == &stream->conn->loc) {
+		assert(stream->io.total <= stream->content_len);
+		if (stream->io.total == stream->content_len)
+			_shttpd_stop_stream(stream);
+	}
+
+	stream->conn->expire_time = _shttpd_current_time + EXPIRE_TIME;
+}
+
+static void
+write_stream(struct stream *from, struct stream *to)
+{
+	int	n, len;
+
+	len = io_data_len(&from->io);
+	assert(len > 0);
+
+	/* TODO: should be assert on CAN_WRITE flag */
+	n = to->io_class->write(to, io_data(&from->io), len);
+	to->conn->expire_time = _shttpd_current_time + EXPIRE_TIME;
+	DBG(("write_stream (%d %s): written %d/%d bytes (errno %d)",
+	    to->conn->rem.chan.sock,
+	    to->io_class ? to->io_class->name : "(null)", n, len, ERRNO));
+
+	if (n > 0)
+		io_inc_tail(&from->io, n);
+	else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
+		n = n;	/* Ignore EINTR and EAGAIN */
+	else if (!(to->flags & FLAG_DONT_CLOSE))
+		_shttpd_stop_stream(to);
+}
+
+
+static void
+connection_desctructor(struct llhead *lp)
+{
+	struct conn		*c = LL_ENTRY(lp, struct conn, link);
+	static const struct vec	vec = {"close", 5};
+	int			do_close;
+
+	DBG(("Disconnecting %d (%.*s)", c->rem.chan.sock,
+	    c->ch.connection.v_vec.len, c->ch.connection.v_vec.ptr));
+
+	if (c->request != NULL && c->ctx->access_log != NULL)
+		_shttpd_log_access(c->ctx->access_log, c);
+
+	/* In inetd mode, exit if request is finished. */
+	if (IS_TRUE(c->ctx, OPT_INETD))
+		exit(0);
+
+	if (c->loc.io_class != NULL && c->loc.io_class->close != NULL)
+		c->loc.io_class->close(&c->loc);
+
+	/*
+	 * Check the "Connection: " header before we free c->request
+	 * If it its 'keep-alive', then do not close the connection
+	 */
+	do_close = (c->ch.connection.v_vec.len >= vec.len &&
+	    !_shttpd_strncasecmp(vec.ptr,c->ch.connection.v_vec.ptr,vec.len)) ||
+	    (c->major_version < 1 ||
+	    (c->major_version >= 1 && c->minor_version < 1));
+
+	if (c->request)
+		free(c->request);
+	if (c->uri)
+		free(c->uri);
+
+	/* Keep the connection open only if we have Content-Length set */
+	if (!do_close && c->loc.content_len > 0) {
+		c->loc.io_class = NULL;
+		c->loc.flags = 0;
+		c->loc.content_len = 0;
+		c->rem.flags = FLAG_W | FLAG_R | FLAG_SSL_ACCEPTED;
+		c->query = c->request = c->uri = c->path_info = NULL;
+		c->mime_type.len = 0;
+		(void) memset(&c->ch, 0, sizeof(c->ch));
+		io_clear(&c->loc.io);
+		c->birth_time = _shttpd_current_time;
+		if (io_data_len(&c->rem.io) > 0)
+			process_connection(c, 0, 0);
+	} else {
+		if (c->rem.io_class != NULL)
+			c->rem.io_class->close(&c->rem);
+
+		LL_DEL(&c->link);
+		c->worker->num_conns--;
+		assert(c->worker->num_conns >= 0);
+
+		free(c);
+	}
+}
+
+static void
+worker_destructor(struct llhead *lp)
+{
+	struct worker	*worker = LL_ENTRY(lp, struct worker, link);
+
+	free_list(&worker->connections, connection_desctructor);
+	free(worker);
+}
+
+static int
+is_allowed(const struct shttpd_ctx *ctx, const struct usa *usa)
+{
+	const struct acl	*acl;
+	const struct llhead	*lp;
+	int			allowed = '+';
+	uint32_t		ip;
+
+	LL_FOREACH(&ctx->acl, lp) {
+		acl = LL_ENTRY(lp, struct acl, link);
+		(void) memcpy(&ip, &usa->u.sin.sin_addr, sizeof(ip));
+		if (acl->ip == (ntohl(ip) & acl->mask))
+			allowed = acl->flag;
+	}
+
+	return (allowed == '+');
+}
+
+static void
+add_to_set(int fd, fd_set *set, int *max_fd)
+{
+	FD_SET(fd, set);
+	if (fd > *max_fd)
+		*max_fd = fd;
+}
+
+static void
+process_connection(struct conn *c, int remote_ready, int local_ready)
+{
+	/* Read from remote end if it is ready */
+	if (remote_ready && io_space_len(&c->rem.io))
+		read_stream(&c->rem);
+
+	/* If the request is not parsed yet, do so */
+	if (!(c->rem.flags & FLAG_HEADERS_PARSED))
+		parse_http_request(c);
+
+	DBG(("loc: %d [%.*s]", (int) io_data_len(&c->loc.io),
+	    (int) io_data_len(&c->loc.io), io_data(&c->loc.io)));
+	DBG(("rem: %d [%.*s]", (int) io_data_len(&c->rem.io),
+	    (int) io_data_len(&c->rem.io), io_data(&c->rem.io)));
+
+	/* Read from the local end if it is ready */
+	if (local_ready && io_space_len(&c->loc.io))
+		read_stream(&c->loc);
+
+	if (io_data_len(&c->rem.io) > 0 && (c->loc.flags & FLAG_W) &&
+	    c->loc.io_class != NULL && c->loc.io_class->write != NULL)
+		write_stream(&c->rem, &c->loc);
+
+	if (io_data_len(&c->loc.io) > 0 && c->rem.io_class != NULL)
+		write_stream(&c->loc, &c->rem); 
+
+	/* Check whether we should close this connection */
+	if ((_shttpd_current_time > c->expire_time) ||
+	    (c->rem.flags & FLAG_CLOSED) ||
+	    ((c->loc.flags & FLAG_CLOSED) && !io_data_len(&c->loc.io)))
+		connection_desctructor(&c->link);
+}
+
+static int
+num_workers(const struct shttpd_ctx *ctx)
+{
+	char	*p = ctx->options[OPT_THREADS];
+	return (p ? atoi(p) : 1);
+}
+
+static void
+handle_connected_socket(struct shttpd_ctx *ctx,
+		struct usa *sap, int sock, int is_ssl)
+{
+#if !defined(_WIN32)
+	if (sock >= (int) FD_SETSIZE) {
+		_shttpd_elog(E_LOG, NULL, "ctx %p: discarding "
+		    "socket %d, too busy", ctx, sock);
+		(void) closesocket(sock);
+	} else
+#endif /* !_WIN32 */
+		if (!is_allowed(ctx, sap)) {
+		_shttpd_elog(E_LOG, NULL, "%s is not allowed to connect",
+		    inet_ntoa(sap->u.sin.sin_addr));
+		(void) closesocket(sock);
+	} else if (num_workers(ctx) > 1) {
+		pass_socket(ctx, sock, is_ssl);
+	} else {
+		add_socket(first_worker(ctx), sock, is_ssl);
+	}
+}
+
+static int
+do_select(int max_fd, fd_set *read_set, fd_set *write_set, int milliseconds)
+{
+	struct timeval	tv;
+	int		n;
+
+	tv.tv_sec = milliseconds / 1000;
+	tv.tv_usec = (milliseconds % 1000) * 1000;
+
+	/* Check IO readiness */
+	if ((n = select(max_fd + 1, read_set, write_set, NULL, &tv)) < 0) {
+#ifdef _WIN32
+		/*
+		 * On windows, if read_set and write_set are empty,
+		 * select() returns "Invalid parameter" error
+		 * (at least on my Windows XP Pro). So in this case,
+		 * we sleep here.
+		 */
+		Sleep(milliseconds);
+#endif /* _WIN32 */
+		DBG(("select: %d", ERRNO));
+	}
+
+	return (n);
+}
+
+static int
+multiplex_worker_sockets(const struct worker *worker, int *max_fd,
+		fd_set *read_set, fd_set *write_set)
+{
+	struct llhead	*lp;
+	struct conn	*c;
+	int		nowait = FALSE;
+
+	/* Add control socket */
+	add_to_set(worker->ctl[0], read_set, max_fd);
+
+	/* Multiplex streams */
+	LL_FOREACH(&worker->connections, lp) {
+		c = LL_ENTRY(lp, struct conn, link);
+		
+		/* If there is a space in remote IO, check remote socket */
+		if (io_space_len(&c->rem.io))
+			add_to_set(c->rem.chan.fd, read_set, max_fd);
+
+#if !defined(NO_CGI)
+		/*
+		 * If there is a space in local IO, and local endpoint is
+		 * CGI, check local socket for read availability
+		 */
+		if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
+		    c->loc.io_class == &_shttpd_io_cgi)
+			add_to_set(c->loc.chan.fd, read_set, max_fd);
+
+		/*
+		 * If there is some data read from remote socket, and
+		 * local endpoint is CGI, check local for write availability
+		 */
+		if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
+		    c->loc.io_class == &_shttpd_io_cgi)
+			add_to_set(c->loc.chan.fd, write_set, max_fd);
+#endif /* NO_CGI */
+
+		/*
+		 * If there is some data read from local endpoint, check the
+		 * remote socket for write availability
+		 */
+		if (io_data_len(&c->loc.io) && !(c->loc.flags & FLAG_SUSPEND))
+			add_to_set(c->rem.chan.fd, write_set, max_fd);
+
+		/*
+		 * Set select wait interval to zero if FLAG_ALWAYS_READY set
+		 */
+		if (io_space_len(&c->loc.io) && (c->loc.flags & FLAG_R) &&
+		    (c->loc.flags & FLAG_ALWAYS_READY))
+			nowait = TRUE;
+		
+		if (io_data_len(&c->rem.io) && (c->loc.flags & FLAG_W) &&
+		    (c->loc.flags & FLAG_ALWAYS_READY))
+			nowait = TRUE;
+	}
+
+	return (nowait);
+}
+
+int
+shttpd_join(struct shttpd_ctx *ctx,
+		fd_set *read_set, fd_set *write_set, int *max_fd)
+{
+	struct llhead	*lp;
+	struct listener	*l;
+	int		nowait = FALSE;
+
+	/* Add listening sockets to the read set */
+	LL_FOREACH(&ctx->listeners, lp) {
+		l = LL_ENTRY(lp, struct listener, link);
+		add_to_set(l->sock, read_set, max_fd);
+		DBG(("FD_SET(%d) (listening)", l->sock));
+	}
+
+	if (num_workers(ctx) == 1)
+		nowait = multiplex_worker_sockets(first_worker(ctx), max_fd,
+		    read_set, write_set);
+
+	return (nowait);
+}
+
+
+static void
+process_worker_sockets(struct worker *worker, fd_set *read_set)
+{
+	struct llhead	*lp, *tmp;
+	int		cmd, skt[2], sock = worker->ctl[0];
+	struct conn	*c;
+
+	/* Check if new socket is passed to us over the control socket */
+	if (FD_ISSET(worker->ctl[0], read_set))
+		while (recv(sock, (void *) &cmd, sizeof(cmd), 0) == sizeof(cmd))
+			switch (cmd) {
+			case CTL_PASS_SOCKET:
+				(void)recv(sock, (void *) &skt, sizeof(skt), 0);
+				add_socket(worker, skt[0], skt[1]);
+				break;
+			case CTL_WAKEUP:
+				(void)recv(sock, (void *) &c, sizeof(c), 0);
+				c->loc.flags &= FLAG_SUSPEND;
+				break;
+			default:
+				_shttpd_elog(E_FATAL, NULL, "ctx %p: ctl cmd %d",
+				    worker->ctx, cmd);
+				break;
+			}
+
+	/* Process all connections */
+	LL_FOREACH_SAFE(&worker->connections, lp, tmp) {
+		c = LL_ENTRY(lp, struct conn, link);
+		process_connection(c, FD_ISSET(c->rem.chan.sock, read_set),
+		    c->loc.io_class != NULL &&
+		    ((c->loc.flags & FLAG_ALWAYS_READY)
+#if !defined(NO_CGI)
+		    || (c->loc.io_class == &_shttpd_io_cgi &&
+		     FD_ISSET(c->loc.chan.fd, read_set))
+#endif /* NO_CGI */
+		    ));
+	}
+}
+
+/*
+ * One iteration of server loop. This is the core of the data exchange.
+ */
+void
+shttpd_poll(struct shttpd_ctx *ctx, int milliseconds)
+{
+	struct llhead	*lp;
+	struct listener	*l;
+	fd_set		read_set, write_set;
+	int		sock, max_fd = -1;
+	struct usa	sa;
+
+	_shttpd_current_time = time(0);
+	FD_ZERO(&read_set);
+	FD_ZERO(&write_set);
+
+	if (shttpd_join(ctx, &read_set, &write_set, &max_fd))
+		milliseconds = 0;
+
+	if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
+		return;;
+
+	/* Check for incoming connections on listener sockets */
+	LL_FOREACH(&ctx->listeners, lp) {
+		l = LL_ENTRY(lp, struct listener, link);
+		if (!FD_ISSET(l->sock, &read_set))
+			continue;
+		do {
+			sa.len = sizeof(sa.u.sin);
+			if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1)
+				handle_connected_socket(ctx,&sa,sock,l->is_ssl);
+		} while (sock != -1);
+	}
+
+	if (num_workers(ctx) == 1)
+		process_worker_sockets(first_worker(ctx), &read_set);
+}
+
+/*
+ * Deallocate shttpd object, free up the resources
+ */
+void
+shttpd_fini(struct shttpd_ctx *ctx)
+{
+	size_t	i;
+
+	free_list(&ctx->workers, worker_destructor);
+	free_list(&ctx->registered_uris, registered_uri_destructor);
+	free_list(&ctx->acl, acl_destructor);
+	free_list(&ctx->listeners, listener_destructor);
+#if !defined(NO_SSI)
+	free_list(&ctx->ssi_funcs, _shttpd_ssi_func_destructor);
+#endif /* !NO_SSI */
+
+	for (i = 0; i < NELEMS(ctx->options); i++)
+		if (ctx->options[i] != NULL)
+			free(ctx->options[i]);
+
+	if (ctx->access_log)		(void) fclose(ctx->access_log);
+	if (ctx->error_log)		(void) fclose(ctx->error_log);
+
+	/* TODO: free SSL context */
+
+	free(ctx);
+}
+
+/*
+ * UNIX socketpair() implementation. Why? Because Windows does not have it.
+ * Return 0 on success, -1 on error.
+ */
+int
+shttpd_socketpair(int sp[2])
+{
+	struct sockaddr_in	sa;
+	int			sock, ret = -1;
+	socklen_t		len = sizeof(sa);
+
+	sp[0] = sp[1] = -1;
+
+	(void) memset(&sa, 0, sizeof(sa));
+	sa.sin_family 		= AF_INET;
+	sa.sin_port		= htons(0);
+	sa.sin_addr.s_addr	= htonl(INADDR_LOOPBACK);
+
+	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1 &&
+	    !bind(sock, (struct sockaddr *) &sa, len) &&
+	    !listen(sock, 1) &&
+	    !getsockname(sock, (struct sockaddr *) &sa, &len) &&
+	    (sp[0] = socket(AF_INET, SOCK_STREAM, 6)) != -1 &&
+	    !connect(sp[0], (struct sockaddr *) &sa, len) &&
+	    (sp[1] = accept(sock,(struct sockaddr *) &sa, &len)) != -1) {
+
+		/* Success */
+		ret = 0;
+	} else {
+
+		/* Failure, close descriptors */
+		if (sp[0] != -1)
+			(void) closesocket(sp[0]);
+		if (sp[1] != -1)
+			(void) closesocket(sp[1]);
+	}
+
+	(void) closesocket(sock);
+	(void) _shttpd_set_non_blocking_mode(sp[0]);
+	(void) _shttpd_set_non_blocking_mode(sp[1]);
+
+#ifndef _WIN32
+	(void) fcntl(sp[0], F_SETFD, FD_CLOEXEC);
+	(void) fcntl(sp[1], F_SETFD, FD_CLOEXEC);
+#endif /* _WIN32*/
+
+	return (ret);
+}
+
+static int isbyte(int n) { return (n >= 0 && n <= 255); }
+
+static int
+set_inetd(struct shttpd_ctx *ctx, const char *flag)
+{
+	ctx = NULL; /* Unused */
+
+	if (_shttpd_is_true(flag)) {
+		shttpd_set_option(ctx, "ports", NULL);
+		(void) freopen("/dev/null", "a", stderr);
+		add_socket(first_worker(ctx), 0, 0);
+	}
+
+	return (TRUE);
+}
+
+static int
+set_uid(struct shttpd_ctx *ctx, const char *uid)
+{
+	struct passwd	*pw;
+
+	ctx = NULL; /* Unused */
+
+#if !defined(_WIN32)
+	if ((pw = getpwnam(uid)) == NULL)
+		_shttpd_elog(E_FATAL, 0, "%s: unknown user [%s]", __func__, uid);
+	else if (setgid(pw->pw_gid) == -1)
+		_shttpd_elog(E_FATAL, NULL, "%s: setgid(%s): %s",
+		    __func__, uid, strerror(errno));
+	else if (setuid(pw->pw_uid) == -1)
+		_shttpd_elog(E_FATAL, NULL, "%s: setuid(%s): %s",
+		    __func__, uid, strerror(errno));
+#endif /* !_WIN32 */
+	return (TRUE);
+}
+
+static int
+set_acl(struct shttpd_ctx *ctx, const char *s)
+{
+	struct acl	*acl = NULL;
+	char		flag;
+	int		len, a, b, c, d, n, mask;
+
+	/* Delete the old ACLs if any */
+	free_list(&ctx->acl, acl_destructor);
+
+	FOR_EACH_WORD_IN_LIST(s, len) {
+
+		mask = 32;
+
+		if (sscanf(s, "%c%d.%d.%d.%d%n",&flag,&a,&b,&c,&d,&n) != 5) {
+			_shttpd_elog(E_FATAL, NULL, "[%s]: subnet must be "
+			    "[+|-]x.x.x.x[/x]", s);
+		} else if (flag != '+' && flag != '-') {
+			_shttpd_elog(E_FATAL, NULL, "flag must be + or -: [%s]", s);
+		} else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
+			_shttpd_elog(E_FATAL, NULL, "bad ip address: [%s]", s);
+		} else	if ((acl = malloc(sizeof(*acl))) == NULL) {
+			_shttpd_elog(E_FATAL, NULL, "%s", "cannot malloc subnet");
+		} else if (sscanf(s + n, "/%d", &mask) == 0) { 
+			/* Do nothing, no mask specified */
+		} else if (mask < 0 || mask > 32) {
+			_shttpd_elog(E_FATAL, NULL, "bad subnet mask: %d [%s]", n, s);
+		}
+
+		acl->ip = (a << 24) | (b << 16) | (c << 8) | d;
+		acl->mask = mask ? 0xffffffffU << (32 - mask) : 0;
+		acl->flag = flag;
+		LL_TAIL(&ctx->acl, &acl->link);
+	}
+
+	return (TRUE);
+}
+
+#ifndef NO_SSL
+/*
+ * Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
+ */
+static int
+set_ssl(struct shttpd_ctx *ctx, const char *pem)
+{
+	SSL_CTX		*CTX;
+	void		*lib;
+	struct ssl_func	*fp;
+	int		retval = FALSE;
+
+	/* Load SSL library dynamically */
+	if ((lib = dlopen(SSL_LIB, RTLD_LAZY)) == NULL) {
+		_shttpd_elog(E_LOG, NULL, "set_ssl: cannot load %s", SSL_LIB);
+		return (FALSE);
+	}
+
+	for (fp = ssl_sw; fp->name != NULL; fp++)
+		if ((fp->ptr.v_void = dlsym(lib, fp->name)) == NULL) {
+			_shttpd_elog(E_LOG, NULL,"set_ssl: cannot find %s", fp->name);
+			return (FALSE);
+		}
+
+	/* Initialize SSL crap */
+	SSL_library_init();
+
+	if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL)
+		_shttpd_elog(E_LOG, NULL, "SSL_CTX_new error");
+	else if (SSL_CTX_use_certificate_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
+		_shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
+	else if (SSL_CTX_use_PrivateKey_file(CTX, pem, SSL_FILETYPE_PEM) == 0)
+		_shttpd_elog(E_LOG, NULL, "cannot open %s", pem);
+	else
+		retval = TRUE;
+
+	ctx->ssl_ctx = CTX;
+
+	return (retval);
+}
+#endif /* NO_SSL */
+
+static int
+open_log_file(FILE **fpp, const char *path)
+{
+	int	retval = TRUE;
+
+	if (*fpp != NULL)
+		(void) fclose(*fpp);
+
+	if (path == NULL) {
+		*fpp = NULL;
+	} else if ((*fpp = fopen(path, "a")) == NULL) {
+		_shttpd_elog(E_LOG, NULL, "cannot open log file %s: %s",
+		    path, strerror(errno));
+		retval = FALSE;
+	}
+
+	return (retval);
+}
+
+static int set_alog(struct shttpd_ctx *ctx, const char *path) {
+	return (open_log_file(&ctx->access_log, path));
+}
+
+static int set_elog(struct shttpd_ctx *ctx, const char *path) {
+	return (open_log_file(&ctx->error_log, path));
+}
+
+static void show_cfg_page(struct shttpd_arg *arg);
+
+static int
+set_cfg_uri(struct shttpd_ctx *ctx, const char *uri)
+{
+	free_list(&ctx->registered_uris, &registered_uri_destructor);
+
+	if (uri != NULL)
+		shttpd_register_uri(ctx, uri, &show_cfg_page, ctx);
+
+	return (TRUE);
+}
+
+static struct worker *
+add_worker(struct shttpd_ctx *ctx)
+{
+	struct worker	*worker;
+
+	if ((worker = calloc(1, sizeof(*worker))) == NULL)
+		_shttpd_elog(E_FATAL, NULL, "Cannot allocate worker");
+	LL_INIT(&worker->connections);
+	worker->ctx = ctx;
+	(void) shttpd_socketpair(worker->ctl);
+	LL_TAIL(&ctx->workers, &worker->link);
+
+	return (worker);
+}
+
+#if !defined(NO_THREADS)
+static void
+poll_worker(struct worker *worker, int milliseconds)
+{
+	fd_set		read_set, write_set;
+	int		max_fd = -1;
+
+	FD_ZERO(&read_set);
+	FD_ZERO(&write_set);
+
+	if (multiplex_worker_sockets(worker, &max_fd, &read_set, &write_set))
+		milliseconds = 0;
+
+	if (do_select(max_fd, &read_set, &write_set, milliseconds) < 0)
+		return;;
+
+	process_worker_sockets(worker, &read_set);
+}
+
+static void
+worker_function(void *param)
+{
+	struct worker *worker = param;
+
+	while (worker->exit_flag == 0)
+		poll_worker(worker, 1000 * 10);
+
+	free_list(&worker->connections, connection_desctructor);
+	free(worker);
+}
+
+static int
+set_workers(struct shttpd_ctx *ctx, const char *value)
+{
+	int		new_num, old_num;
+	struct llhead	*lp, *tmp;
+	struct worker	*worker;
+
+       	new_num = atoi(value);
+	old_num = 0;
+	LL_FOREACH(&ctx->workers, lp)
+		old_num++;
+
+	if (new_num == 1) {
+		if (old_num > 1)
+			/* Stop old threads */
+			LL_FOREACH_SAFE(&ctx->workers, lp, tmp) {
+				worker = LL_ENTRY(lp, struct worker, link);
+				LL_DEL(&worker->link);
+				worker = LL_ENTRY(lp, struct worker, link);
+				worker->exit_flag = 1;
+			}
+		(void) add_worker(ctx);
+	} else {
+		/* FIXME: we cannot here reduce the number of threads */
+		while (new_num > 1 && new_num > old_num) {
+			worker = add_worker(ctx);
+			_beginthread(worker_function, 0, worker);
+			old_num++;
+		}
+	}
+
+	return (TRUE);
+}
+#endif /* NO_THREADS */
+
+static const struct opt {
+	int		index;		/* Index in shttpd_ctx		*/
+	const char	*name;		/* Option name in config file	*/
+	const char	*description;	/* Description			*/
+	const char	*default_value;	/* Default option value		*/
+	int (*setter)(struct shttpd_ctx *, const char *);
+} known_options[] = {
+	{OPT_ROOT, "root", "\tWeb root directory", ".", NULL},
+	{OPT_INDEX_FILES, "index_files", "Index files", INDEX_FILES, NULL},
+#ifndef NO_SSL
+	{OPT_SSL_CERTIFICATE, "ssl_cert", "SSL certificate file", NULL,set_ssl},
+#endif /* NO_SSL */
+	{OPT_PORTS, "ports", "Listening ports", LISTENING_PORTS, set_ports},
+	{OPT_DIR_LIST, "dir_list", "Directory listing", "yes", NULL},
+	{OPT_CFG_URI, "cfg_uri", "Config uri", NULL, set_cfg_uri},
+	{OPT_PROTECT, "protect", "URI to htpasswd mapping", NULL, NULL},
+#ifndef NO_CGI
+	{OPT_CGI_EXTENSIONS, "cgi_ext", "CGI extensions", CGI_EXT, NULL},
+	{OPT_CGI_INTERPRETER, "cgi_interp", "CGI interpreter", NULL, NULL},
+	{OPT_CGI_ENVIRONMENT, "cgi_env", "Additional CGI env vars", NULL, NULL},
+#endif /* NO_CGI */
+	{OPT_SSI_EXTENSIONS, "ssi_ext",	"SSI extensions", SSI_EXT, NULL},
+#ifndef NO_AUTH
+	{OPT_AUTH_REALM, "auth_realm", "Authentication domain name",REALM,NULL},
+	{OPT_AUTH_GPASSWD, "auth_gpass", "Global passwords file", NULL, NULL},
+	{OPT_AUTH_PUT, "auth_PUT", "PUT,DELETE auth file", NULL, NULL},
+#endif /* !NO_AUTH */
+#ifdef _WIN32
+	{OPT_SERVICE, "service", "Manage WinNNT service (install"
+	    "|uninstall)", NULL, _shttpd_set_nt_service},
+	{OPT_HIDE, "systray", "Hide console, show icon on systray",
+		"no", _shttpd_set_systray},
+#else
+	{OPT_INETD, "inetd", "Inetd mode", "no", set_inetd},
+	{OPT_UID, "uid", "\tRun as user", NULL, set_uid},
+#endif /* _WIN32 */
+	{OPT_ACCESS_LOG, "access_log", "Access log file", NULL, set_alog},
+	{OPT_ERROR_LOG, "error_log", "Error log file", NULL, set_elog},
+	{OPT_MIME_TYPES, "mime_types", "Additional mime types list", NULL,NULL},
+	{OPT_ALIASES, "aliases", "Path=URI mappings", NULL, NULL},
+	{OPT_ACL, "acl", "\tAllow/deny IP addresses/subnets", NULL, set_acl},
+#if !defined(NO_THREADS)
+	{OPT_THREADS, "threads", "Number of worker threads", "1", set_workers},
+#endif /* !NO_THREADS */
+	{-1, NULL, NULL, NULL, NULL}
+};
+
+static const struct opt *
+find_opt(const char *opt_name)
+{
+	int	i;
+
+	for (i = 0; known_options[i].name != NULL; i++)
+		if (!strcmp(opt_name, known_options[i].name))
+			return (known_options + i);
+
+	_shttpd_elog(E_FATAL, NULL, "no such option: [%s]", opt_name);
+
+	/* UNREACHABLE */
+	return (NULL);
+}
+
+int
+shttpd_set_option(struct shttpd_ctx *ctx, const char *opt, const char *val)
+{
+	const struct opt	*o = find_opt(opt);
+	int			retval = TRUE;
+
+	/* Call option setter first, so it can use both new and old values */
+	if (o->setter != NULL)
+		retval = o->setter(ctx, val);
+
+	/* Free old value if any */
+	if (ctx->options[o->index] != NULL)
+		free(ctx->options[o->index]);
+	
+	/* Set new option value */
+	ctx->options[o->index] = val ? _shttpd_strdup(val) : NULL;
+
+	return (retval);
+}
+
+
+//@@	Add	************************************************
+const char *
+shttpd_get_option(struct shttpd_ctx *ctx, const char *opt)
+{
+	const struct opt	*o = find_opt(opt);
+
+	return ctx->options[o->index];
+}
+//@@	Add	************************************************
+
+
+
+
+
+
+
+
+
+
+
+
+static void
+show_cfg_page(struct shttpd_arg *arg)
+{
+	struct shttpd_ctx	*ctx = arg->user_data;
+	char			opt_name[20], value[BUFSIZ];
+	const struct opt	*o;
+
+	opt_name[0] = value[0] = '\0';
+
+	if (!strcmp(shttpd_get_env(arg, "REQUEST_METHOD"), "POST")) {
+		if (arg->flags & SHTTPD_MORE_POST_DATA)
+			return;
+		(void) shttpd_get_var("o", arg->in.buf, arg->in.len,
+		    opt_name, sizeof(opt_name));
+		(void) shttpd_get_var("v", arg->in.buf, arg->in.len,
+		    value, sizeof(value));
+		shttpd_set_option(ctx, opt_name, value[0] ? value : NULL);
+	}
+
+	shttpd_printf(arg, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
+	    "<html><body><h1>SHTTPD v. %s</h1>", shttpd_version());
+
+	shttpd_printf(arg, "%s", "<table border=1"
+	    "<tr><th>Option</th><th>Description</th>"
+	    "<th colspan=2>Value</th></tr>");
+
+	if (opt_name[0] != '\0' && value[0] != '\0')
+		shttpd_printf(arg, "<p style='color: green'>Saved: %s=%s</p>",
+		    opt_name, value[0] ? value : "NULL");
+
+
+	for (o = known_options; o->name != NULL; o++) {
+		shttpd_printf(arg,
+		    "<form method=post><tr><td>%s</td><td>%s</td>"
+		    "<input type=hidden name=o value='%s'>"
+		    "<td><input type=text name=v value='%s'></td>"
+		    "<td><input type=submit value=save></td></form></tr>",
+		    o->name, o->description, o->name,
+		    ctx->options[o->index] ? ctx->options[o->index] : "");
+	}
+
+	shttpd_printf(arg, "%s", "</table></body></html>");
+	arg->flags |= SHTTPD_END_OF_OUTPUT;
+}
+
+/*
+ * Show usage string and exit.
+ */
+void
+_shttpd_usage(const char *prog)
+{
+	const struct opt	*o;
+
+	(void) fprintf(stderr,
+	    "SHTTPD version %s (c) Sergey Lyubka\n"
+	    "usage: %s [options] [config_file]\n", VERSION, prog);
+
+#if !defined(NO_AUTH)
+	fprintf(stderr, "  -A <htpasswd_file> <realm> <user> <passwd>\n");
+#endif /* NO_AUTH */
+
+	for (o = known_options; o->name != NULL; o++) {
+		(void) fprintf(stderr, "  -%s\t%s", o->name, o->description);
+		if (o->default_value != NULL)
+			fprintf(stderr, " (default: %s)", o->default_value);
+		fputc('\n', stderr);
+	}
+
+	exit(EXIT_FAILURE);
+}
+
+static void
+set_opt(struct shttpd_ctx *ctx, const char *opt, const char *value)
+{
+	const struct opt	*o;
+
+	o = find_opt(opt);
+	if (ctx->options[o->index] != NULL)
+		free(ctx->options[o->index]);
+	ctx->options[o->index] = _shttpd_strdup(value);
+}
+
+static void
+process_command_line_arguments(struct shttpd_ctx *ctx, char *argv[])
+{
+	const char		*config_file = CONFIG_FILE;
+	char			line[BUFSIZ], opt[BUFSIZ],
+				val[BUFSIZ], path[FILENAME_MAX], *p;
+	FILE			*fp;
+	size_t			i, line_no = 0;
+
+	/* First find out, which config file to open */
+	for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
+		if (argv[i + 1] == NULL)
+			_shttpd_usage(argv[0]);
+
+	if (argv[i] != NULL && argv[i + 1] != NULL) {
+		/* More than one non-option arguments are given w*/
+		_shttpd_usage(argv[0]);
+	} else if (argv[i] != NULL) {
+		/* Just one non-option argument is given, this is config file */
+		config_file = argv[i];
+	} else {
+		/* No config file specified. Look for one where shttpd lives */
+		if ((p = strrchr(argv[0], DIRSEP)) != 0) {
+			_shttpd_snprintf(path, sizeof(path), "%.*s%s",
+			    p - argv[0] + 1, argv[0], config_file);
+			config_file = path;
+		}
+	}
+
+	fp = fopen(config_file, "r");
+
+	/* If config file was set in command line and open failed, exit */
+	if (fp == NULL && argv[i] != NULL)
+		_shttpd_elog(E_FATAL, NULL, "cannot open config file %s: %s",
+		    config_file, strerror(errno));
+
+	if (fp != NULL) {
+
+		_shttpd_elog(E_LOG, NULL, "Loading config file %s", config_file);
+
+		/* Loop over the lines in config file */
+		while (fgets(line, sizeof(line), fp) != NULL) {
+
+			line_no++;
+
+			/* Ignore empty lines and comments */
+			if (line[0] == '#' || line[0] == '\n')
+				continue;
+
+			if (sscanf(line, "%s %[^\n#]", opt, val) != 2)
+				_shttpd_elog(E_FATAL, NULL, "line %d in %s is invalid",
+				    line_no, config_file);
+
+			set_opt(ctx, opt, val);
+		}
+
+		(void) fclose(fp);
+	}
+
+	/* Now pass through the command line options */
+	for (i = 1; argv[i] != NULL && argv[i][0] == '-'; i += 2)
+		set_opt(ctx, &argv[i][1], argv[i + 1]);
+}
+
+struct shttpd_ctx *
+shttpd_init(int argc, char *argv[])
+{
+	struct shttpd_ctx	*ctx;
+	struct tm		*tm;
+	const struct opt	*o;
+
+	if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+		_shttpd_elog(E_FATAL, NULL, "cannot allocate shttpd context");
+
+	LL_INIT(&ctx->registered_uris);
+	LL_INIT(&ctx->error_handlers);
+	LL_INIT(&ctx->acl);
+	LL_INIT(&ctx->ssi_funcs);
+	LL_INIT(&ctx->listeners);
+	LL_INIT(&ctx->workers);
+
+	/* Initialize options. First pass: set default option values */
+	for (o = known_options; o->name != NULL; o++)
+		ctx->options[o->index] = o->default_value ?
+			_shttpd_strdup(o->default_value) : NULL;
+
+	/* Second and third passes: config file and argv */
+	if (argc > 0 && argv != NULL)
+		process_command_line_arguments(ctx, argv);
+
+	/* Call setter functions */
+	for (o = known_options; o->name != NULL; o++)
+		if (o->setter && ctx->options[o->index] != NULL)
+			if (o->setter(ctx, ctx->options[o->index]) == FALSE) {
+				shttpd_fini(ctx);
+				return (NULL);
+			}
+
+	_shttpd_current_time = time(NULL);
+	tm = localtime(&_shttpd_current_time);
+	_shttpd_tz_offset = 0;
+
+	if (num_workers(ctx) == 1)
+		(void) add_worker(ctx);
+#if 0
+	tm->tm_gmtoff - 3600 * (tm->tm_isdst > 0 ? 1 : 0);
+#endif
+
+#ifdef _WIN32
+	{WSADATA data;	WSAStartup(MAKEWORD(2,2), &data);}
+#endif /* _WIN32 */
+
+	return (ctx);
+}

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/shttpd.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,113 @@
+/*
+ * Copyright (c) 2004-2008 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ *
+ * $Id: shttpd.h,v 1.18 2008/08/23 08:34:50 drozd Exp $
+ */
+
+#ifndef SHTTPD_HEADER_INCLUDED
+#define	SHTTPD_HEADER_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct ubuf {
+	char		*buf;		/* Buffer pointer		*/
+	int		len;		/* Size of a buffer		*/
+	int		num_bytes;	/* Bytes processed by callback	*/
+};
+
+/*
+ * This structure is passed to the user callback function
+ */
+struct shttpd_arg {
+	void		*priv;		/* Private! Do not touch!	*/
+	void		*state;		/* User state			*/
+	void		*user_data;	/* Data from register_uri()	*/
+	struct ubuf	in;		/* Input is here, POST data	*/
+	struct ubuf	out;		/* Output goes here		*/
+
+	unsigned int	flags;
+#define	SHTTPD_END_OF_OUTPUT	1	/* No more data do send		*/
+#define	SHTTPD_CONNECTION_ERROR	2	/* Server closed the connection	*/
+#define	SHTTPD_MORE_POST_DATA	4	/* arg->in has incomplete data	*/
+#define	SHTTPD_POST_BUFFER_FULL	8	/* arg->in has max data		*/
+#define	SHTTPD_SSI_EVAL_TRUE	16	/* SSI eval callback must set it*/
+#define	SHTTPD_SUSPEND		32	/* User wants to suspend output	*/
+};
+
+/*
+ * User callback function. Called when certain registered URLs have been
+ * requested. These are the requirements to the callback function:
+ *
+ * 1. It must copy data into 'out.buf' buffer, not more than 'out.len' bytes,
+ *	and record how many bytes are copied, into 'out.num_bytes'
+ * 2. It must not call any blocking functions
+ * 3. It must set SHTTPD_END_OF_OUTPUT flag when there is no more data to send
+ * 4. For POST requests, it must process the incoming data (in.buf) of length
+ *	'in.len', and set 'in.num_bytes', which is how many bytes of POST
+ *	data was processed and can be discarded by SHTTPD.
+ * 5. If callback allocates arg->state, to keep state, it must deallocate it
+ *    at the end of coonection SHTTPD_CONNECTION_ERROR or SHTTPD_END_OF_OUTPUT
+ * 6. If callback function wants to suspend until some event, it must store
+ *	arg->priv pointer elsewhere, set SHTTPD_SUSPEND flag and return. When
+ *	the event happens, user code should call shttpd_wakeup(priv).
+ *	It is safe to call shttpd_wakeup() from any thread. User code must
+ *	not call shttpd_wakeup once the connection is closed.
+ */
+typedef void (*shttpd_callback_t)(struct shttpd_arg *);
+
+/*
+ * shttpd_init		Initialize shttpd context
+ * shttpd_fini		Dealocate the context, close all connections
+ * shttpd_set_option	Set new value for option
+ * shttpd_register_uri	Setup the callback function for specified URL
+ * shttpd_poll		Do connections processing
+ * shttpd_version	return string with SHTTPD version
+ * shttpd_get_var	Fetch POST/GET variable value by name. Return value len
+ * shttpd_get_header	return value of the specified HTTP header
+ * shttpd_get_env	return values for the following	pseudo-variables:
+ 			"REQUEST_METHOD", "REQUEST_URI",
+ *			"REMOTE_USER" and "REMOTE_ADDR"
+ * shttpd_printf	helper function to output data
+ * shttpd_handle_error	register custom HTTP error handler
+ * shttpd_wakeup	clear SHTTPD_SUSPEND state for the connection
+ */
+
+struct shttpd_ctx;
+
+struct shttpd_ctx *shttpd_init(int argc, char *argv[]);
+int shttpd_set_option(struct shttpd_ctx *, const char *opt, const char *val);
+const char *shttpd_get_option(struct shttpd_ctx *ctx, const char *opt);			//@@	Add
+void shttpd_fini(struct shttpd_ctx *);
+void shttpd_register_uri(struct shttpd_ctx *ctx, const char *uri,
+		shttpd_callback_t callback, void *const user_data);
+int shttpd_unregister_uri(struct shttpd_ctx *ctx, const char *uri);			//@@	Add
+void shttpd_poll(struct shttpd_ctx *, int milliseconds);
+const char *shttpd_version(void);
+int shttpd_get_var(const char *var, const char *buf, int buf_len,
+		char *value, int value_len);
+const char *shttpd_get_header(struct shttpd_arg *, const char *header_name);
+const char *shttpd_get_env(struct shttpd_arg *, const char *name);
+void shttpd_get_http_version(struct shttpd_arg *,
+		unsigned long *major, unsigned long *minor);
+size_t shttpd_printf(struct shttpd_arg *, const char *fmt, ...);
+void shttpd_handle_error(struct shttpd_ctx *ctx, int status,
+		shttpd_callback_t func, void *const data);
+void shttpd_register_ssi_func(struct shttpd_ctx *ctx, const char *name,
+		shttpd_callback_t func, void *const user_data);
+void shttpd_wakeup(const void *priv);
+int shttpd_join(struct shttpd_ctx *, fd_set *, fd_set *, int *max_fd);
+int  shttpd_socketpair(int sp[2]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SHTTPD_HEADER_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/ssl.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/ssl.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/ssl.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,52 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+/*
+ * Snatched from OpenSSL includes. I put the prototypes here to be independent
+ * from the OpenSSL source installation. Having this, shttpd + SSL can be
+ * built on any system with binary SSL libraries installed.
+ */
+
+typedef struct ssl_st SSL;
+typedef struct ssl_method_st SSL_METHOD;
+typedef struct ssl_ctx_st SSL_CTX;
+
+#define	SSL_ERROR_WANT_READ	2
+#define	SSL_ERROR_WANT_WRITE	3
+#define SSL_FILETYPE_PEM	1
+
+/*
+ * Dynamically loaded SSL functionality
+ */
+struct ssl_func {
+	const char	*name;		/* SSL function name	*/
+	union variant	ptr;		/* Function pointer	*/
+};
+
+extern struct ssl_func	ssl_sw[];
+
+#define	FUNC(x)	ssl_sw[x].ptr.v_func
+
+#define	SSL_free(x)	(* (void (*)(SSL *)) FUNC(0))(x)
+#define	SSL_accept(x)	(* (int (*)(SSL *)) FUNC(1))(x)
+#define	SSL_connect(x)	(* (int (*)(SSL *)) FUNC(2))(x)
+#define	SSL_read(x,y,z)	(* (int (*)(SSL *, void *, int)) FUNC(3))((x),(y),(z))
+#define	SSL_write(x,y,z) \
+	(* (int (*)(SSL *, const void *,int)) FUNC(4))((x), (y), (z))
+#define	SSL_get_error(x,y)(* (int (*)(SSL *, int)) FUNC(5))((x), (y))
+#define	SSL_set_fd(x,y)	(* (int (*)(SSL *, int)) FUNC(6))((x), (y))
+#define	SSL_new(x)	(* (SSL * (*)(SSL_CTX *)) FUNC(7))(x)
+#define	SSL_CTX_new(x)	(* (SSL_CTX * (*)(SSL_METHOD *)) FUNC(8))(x)
+#define	SSLv23_server_method()	(* (SSL_METHOD * (*)(void)) FUNC(9))()
+#define	SSL_library_init() (* (int (*)(void)) FUNC(10))()
+#define	SSL_CTX_use_PrivateKey_file(x,y,z)	(* (int (*)(SSL_CTX *, \
+		const char *, int)) FUNC(11))((x), (y), (z))
+#define	SSL_CTX_use_certificate_file(x,y,z)	(* (int (*)(SSL_CTX *, \
+		const char *, int)) FUNC(12))((x), (y), (z))

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/standalone.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/standalone.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/standalone.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,72 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+static int	exit_flag;	/* Program termination flag	*/
+
+static void
+signal_handler(int sig_num)
+{
+	switch (sig_num) {
+#ifndef _WIN32
+	case SIGCHLD:
+		while (waitpid(-1, &sig_num, WNOHANG) > 0) ;
+		break;
+#endif /* !_WIN32 */
+	default:
+		exit_flag = sig_num;
+		break;
+	}
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct shttpd_ctx	*ctx;
+
+#if !defined(NO_AUTH)
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
+		if (argc != 6)
+			_shttpd_usage(argv[0]);
+		exit(_shttpd_edit_passwords(argv[2],argv[3],argv[4],argv[5]));
+	}
+#endif /* NO_AUTH */
+
+	if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
+		_shttpd_usage(argv[0]);
+
+#if defined(_WIN32)
+	try_to_run_as_nt_service();
+#endif /* _WIN32 */
+
+#ifndef _WIN32
+	(void) signal(SIGCHLD, signal_handler);
+	(void) signal(SIGPIPE, SIG_IGN);
+#endif /* _WIN32 */
+
+	(void) signal(SIGTERM, signal_handler);
+	(void) signal(SIGINT, signal_handler);
+
+	if ((ctx = shttpd_init(argc, argv)) == NULL)
+		_shttpd_elog(E_FATAL, NULL, "%s",
+		    "Cannot initialize SHTTPD context");
+
+	_shttpd_elog(E_LOG, NULL, "shttpd %s started on port(s) %s, serving %s",
+	    VERSION, ctx->options[OPT_PORTS], ctx->options[OPT_ROOT]);
+
+	while (exit_flag == 0)
+		shttpd_poll(ctx, 10 * 1000);
+
+	_shttpd_elog(E_LOG, NULL, "Exit on signal %d", exit_flag);
+	shttpd_fini(ctx);
+
+	return (EXIT_SUCCESS);
+}

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/std_includes.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/std_includes.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/std_includes.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,40 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#ifndef STD_HEADERS_INCLUDED
+#define	STD_HEADERS_INCLUDED
+
+#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#endif /* _WIN32_WCE */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(_WIN32)		/* Windows specific	*/
+#include "compat_win32.h"
+#elif defined(__rtems__)	/* RTEMS specific	*/
+#include "compat_rtems.h"
+#else				/* UNIX  specific	*/
+#include "compat_unix.h"
+#endif /* _WIN32 */
+
+#endif /* STD_HEADERS_INCLUDED */

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/string.c
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/string.c (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/shttpd/src/string.c Fri Jan 11 10:25:07 2013
@@ -1,0 +1,95 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok at gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include "defs.h"
+
+void
+_shttpd_strlcpy(register char *dst, register const char *src, size_t n)
+{
+	for (; *src != '\0' && n > 1; n--)
+		*dst++ = *src++;
+	*dst = '\0';
+}
+
+int
+_shttpd_strncasecmp(const char *str1, const char *str2, size_t len)
+{
+	register const unsigned char	*s1 = (unsigned char *) str1,
+		 			*s2 = (unsigned char *) str2, *e;
+	int				ret;
+
+	for (e = s1 + len - 1; s1 < e && *s1 != '\0' && *s2 != '\0' &&
+	    tolower(*s1) == tolower(*s2); s1++, s2++) ;
+	ret = tolower(*s1) - tolower(*s2);
+
+	return (ret);
+}
+
+char *
+_shttpd_strndup(const char *ptr, size_t len)
+{
+	char	*p;
+
+	if ((p = malloc(len + 1)) != NULL)
+		_shttpd_strlcpy(p, ptr, len + 1);
+
+	return (p);
+
+}
+
+char *
+_shttpd_strdup(const char *str)
+{
+	return (_shttpd_strndup(str, strlen(str)));
+}
+
+/*
+ * Sane snprintf(). Acts like snprintf(), but never return -1 or the
+ * value bigger than supplied buffer.
+ * Thanks Adam Zeldis to pointing snprintf()-caused vulnerability
+ * in his audit report.
+ */
+int
+_shttpd_snprintf(char *buf, size_t buflen, const char *fmt, ...)
+{
+	va_list		ap;
+	int		n;
+
+	if (buflen == 0)
+		return (0);
+
+	va_start(ap, fmt);
+	n = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+
+	if (n < 0 || (size_t) n >= buflen)
+		n = buflen - 1;
+	buf[n] = '\0';
+
+	return (n);
+}
+
+/*
+ * Verify that given file has certain extension
+ */
+int
+_shttpd_match_extension(const char *path, const char *ext_list)
+{
+	size_t		len, path_len;
+	
+	path_len = strlen(path);
+
+	FOR_EACH_WORD_IN_LIST(ext_list, len)
+		if (len < path_len && path[path_len - len - 1] == '.' &&
+		    !_shttpd_strncasecmp(path + path_len - len, ext_list, len))
+			return (TRUE);
+
+	return (FALSE);
+}

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile Fri Jan 11 10:25:07 2013
@@ -1,0 +1,21 @@
+# Static library libtinyxml.a
+
+SRCS=		tinystr.cpp tinyxml.cpp tinyxmlerror.cpp tinyxmlparser.cpp
+
+HDRS=		../include/tinystr.h ../include/tinyxml.h
+OBJS=		$(SRCS:%.cpp=%.o) 
+PROG=		tinyxml
+CFLAGS= -c
+
+.cpp.o:
+	$(CC) $(CFLAGS) $< -o $@ -I../include
+
+
+
+lib$(PROG).a: $(OBJS) 
+	$(AR) -r lib$(PROG).a $(OBJS) 
+	@echo "Static library libtinyxml.a created."	
+
+
+clean:
+	rm -rf *.o *.core $(PROG) lib$(PROG).a *.lib *.obj

Modified: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile.cross
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile.cross (original)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/Makefile.cross Fri Jan 11 10:25:07 2013
@@ -2,22 +2,19 @@
 
 CXXFLAGS += -DTIXML_USE_STL 
 
-SRC_DIR = src
-INCLUDE_DIR = include
-
 #SRC = tinystr.cpp  tinyxml.cpp  tinyxmlerror.cpp  tinyxmlparser.cpp
 
-#TARGETS = $(SRC_DIR)libtinyxml.a
+#TARGETS = libtinyxml.a
 
 all:
-	$(MAKE) -C src
+	$(MAKE) -C .
 
 libtinyxml.a: $(SRC)/tinystr.o  tinyxml.o  tinyxmlerror.o  tinyxmlparser.o 
 	@echo AR $@
 	@$(AR) r $@ $?
 
 clean:
-	$(MAKE) -C src clean
+	$(MAKE) clean
 	rm -f *~
 
 distclean: clean
@@ -27,9 +24,9 @@
 
 install:
 	mkdir -p $(PREFIX_TMP)/lib
-	install -m 644 $(INCLUDE_DIR)/tinyxml.h $(PREFIX_TMP)/include
-	install -m 644 $(INCLUDE_DIR)/tinystr.h $(PREFIX_TMP)/include
-	install -m 644 $(SRC_DIR)/libtinyxml.a $(PREFIX_TMP)/lib
+	install -m 644 tinyxml.h $(PREFIX_TMP)/include
+	install -m 644 tinystr.h $(PREFIX_TMP)/include
+	install -m 644 libtinyxml.a $(PREFIX_TMP)/lib
 
 uninstall:
 	rm -f $(PREFIX_TMP)/lib/libtinyxml.a

Added: projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/tinyxml.h
==============================================================================
--- projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/tinyxml.h (added)
+++ projects/zb4osgi/sandbox/telecomItalia/initialContribution/GAL/tinyxml/tinyxml.h Fri Jan 11 10:25:07 2013
@@ -1,0 +1,1804 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+
+#ifndef TINYXML_INCLUDED
+#define TINYXML_INCLUDED
+
+#define TIXML_USE_STL
+
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4530 )
+#pragma warning( disable : 4786 )
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// Help out windows:
+#if defined( _DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+#ifdef TIXML_USE_STL
+	#include <string>
+ 	#include <iostream>
+	#include <sstream>
+	#define TIXML_STRING		std::string
+#else
+	#include "tinystr.h"
+	#define TIXML_STRING		TiXmlString
+#endif
+
+// Deprecated library function hell. Compilers want to use the
+// new safe versions. This probably doesn't fully address the problem,
+// but it gets closer. There are too many compilers for me to fully
+// test. If you get compilation troubles, undefine TIXML_SAFE
+#define TIXML_SAFE
+
+#ifdef TIXML_SAFE
+	#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+		// Microsoft visual studio, version 2005 and higher.
+		#define TIXML_SNPRINTF _snprintf_s
+		#define TIXML_SNSCANF  _snscanf_s
+		#define TIXML_SSCANF   sscanf_s
+	#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
+		// Microsoft visual studio, version 6 and higher.
+		//#pragma message( "Using _sn* functions." )
+		#define TIXML_SNPRINTF _snprintf
+		#define TIXML_SNSCANF  _snscanf
+		#define TIXML_SSCANF   sscanf
+	#elif defined(__GNUC__) && (__GNUC__ >= 3 )
+		// GCC version 3 and higher.s
+		//#warning( "Using sn* functions." )
+		#define TIXML_SNPRINTF snprintf
+		#define TIXML_SNSCANF  snscanf
+		#define TIXML_SSCANF   sscanf
+	#else
+		#define TIXML_SSCANF   sscanf
+	#endif
+#endif	
+
+class TiXmlDocument;
+class TiXmlElement;
+class TiXmlComment;
+class TiXmlUnknown;
+class TiXmlAttribute;
+class TiXmlText;
+class TiXmlDeclaration;
+class TiXmlParsingData;
+
+const int TIXML_MAJOR_VERSION = 2;
+const int TIXML_MINOR_VERSION = 5;
+const int TIXML_PATCH_VERSION = 3;
+
+/*	Internal structure for tracking location of items 
+	in the XML file.
+*/
+struct TiXmlCursor
+{
+	TiXmlCursor()		{ Clear(); }
+	void Clear()		{ row = col = -1; }
+
+	int row;	// 0 based.
+	int col;	// 0 based.
+};
+
+
+/**
+	If you call the Accept() method, it requires being passed a TiXmlVisitor
+	class to handle callbacks. For nodes that contain other nodes (Document, Element)
+	you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
+	are simple called with Visit().
+
+	If you return 'true' from a Visit method, recursive parsing will continue. If you return
+	false, <b>no children of this node or its sibilings</b> will be Visited.
+
+	All flavors of Visit methods have a default implementation that returns 'true' (continue 
+	visiting). You need to only override methods that are interesting to you.
+
+	Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
+
+	You should never change the document from a callback.
+
+	@sa TiXmlNode::Accept()
+*/
+class TiXmlVisitor
+{
+public:
+	virtual ~TiXmlVisitor() {}
+
+	/// Visit a document.
+	virtual bool VisitEnter( const TiXmlDocument& /*doc*/ )			{ return true; }
+	/// Visit a document.
+	virtual bool VisitExit( const TiXmlDocument& /*doc*/ )			{ return true; }
+
+	/// Visit an element.
+	virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ )	{ return true; }
+	/// Visit an element.
+	virtual bool VisitExit( const TiXmlElement& /*element*/ )		{ return true; }
+
+	/// Visit a declaration
+	virtual bool Visit( const TiXmlDeclaration& /*declaration*/ )	{ return true; }
+	/// Visit a text node
+	virtual bool Visit( const TiXmlText& /*text*/ )					{ return true; }
+	/// Visit a comment node
+	virtual bool Visit( const TiXmlComment& /*comment*/ )			{ return true; }
+	/// Visit an unknow node
+	virtual bool Visit( const TiXmlUnknown& /*unknown*/ )			{ return true; }
+};
+
+// Only used by Attribute::Query functions
+enum 
+{ 
+	TIXML_SUCCESS,
+	TIXML_NO_ATTRIBUTE,
+	TIXML_WRONG_TYPE
+};
+
+
+// Used by the parsing routines.
+enum TiXmlEncoding
+{
+	TIXML_ENCODING_UNKNOWN,
+	TIXML_ENCODING_UTF8,
+	TIXML_ENCODING_LEGACY
+};
+
+const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
+
+/** TiXmlBase is a base class for every class in TinyXml.
+	It does little except to establish that TinyXml classes
+	can be printed and provide some utility functions.
+
+	In XML, the document and elements can contain
+	other elements and other types of nodes.
+
+	@verbatim
+	A Document can contain:	Element	(container or leaf)
+							Comment (leaf)
+							Unknown (leaf)
+							Declaration( leaf )
+
+	An Element can contain:	Element (container or leaf)
+							Text	(leaf)
+							Attributes (not on tree)
+							Comment (leaf)
+							Unknown (leaf)
+
+	A Decleration contains: Attributes (not on tree)
+	@endverbatim
+*/
+class TiXmlBase
+{
+	friend class TiXmlNode;
+	friend class TiXmlElement;
+	friend class TiXmlDocument;
+
+public:
+	TiXmlBase()	:	userData(0)		{}
+	virtual ~TiXmlBase()			{}
+
+	/**	All TinyXml classes can print themselves to a filestream
+		or the string class (TiXmlString in non-STL mode, std::string
+		in STL mode.) Either or both cfile and str can be null.
+		
+		This is a formatted print, and will insert 
+		tabs and newlines.
+		
+		(For an unformatted stream, use the << operator.)
+	*/
+	virtual void Print( FILE* cfile, int depth ) const = 0;
+
+	/**	The world does not agree on whether white space should be kept or
+		not. In order to make everyone happy, these global, static functions
+		are provided to set whether or not TinyXml will condense all white space
+		into a single space or not. The default is to condense. Note changing this
+		value is not thread safe.
+	*/
+	static void SetCondenseWhiteSpace( bool condense )		{ condenseWhiteSpace = condense; }
+
+	/// Return the current white space setting.
+	static bool IsWhiteSpaceCondensed()						{ return condenseWhiteSpace; }
+
+	/** Return the position, in the original source file, of this node or attribute.
+		The row and column are 1-based. (That is the first row and first column is
+		1,1). If the returns values are 0 or less, then the parser does not have
+		a row and column value.
+
+		Generally, the row and column value will be set when the TiXmlDocument::Load(),
+		TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
+		when the DOM was created from operator>>.
+
+		The values reflect the initial load. Once the DOM is modified programmatically
+		(by adding or changing nodes and attributes) the new values will NOT update to
+		reflect changes in the document.
+
+		There is a minor performance cost to computing the row and column. Computation
+		can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
+
+		@sa TiXmlDocument::SetTabSize()
+	*/
+	int Row() const			{ return location.row + 1; }
+	int Column() const		{ return location.col + 1; }	///< See Row()
+
+	void  SetUserData( void* user )			{ userData = user; }	///< Set a pointer to arbitrary user data.
+	void* GetUserData()						{ return userData; }	///< Get a pointer to arbitrary user data.
+	const void* GetUserData() const 		{ return userData; }	///< Get a pointer to arbitrary user data.
+
+	// Table that returs, for a given lead byte, the total number of bytes
+	// in the UTF-8 sequence.
+	static const int utf8ByteTable[256];
+
+	virtual const char* Parse(	const char* p, 
+								TiXmlParsingData* data, 
+								TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
+
+	/** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, 
+		or they will be transformed into entities!
+	*/
+	static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
+
+	enum
+	{
+		TIXML_NO_ERROR = 0,
+		TIXML_ERROR,
+		TIXML_ERROR_OPENING_FILE,
+		TIXML_ERROR_OUT_OF_MEMORY,
+		TIXML_ERROR_PARSING_ELEMENT,
+		TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
+		TIXML_ERROR_READING_ELEMENT_VALUE,
+		TIXML_ERROR_READING_ATTRIBUTES,
+		TIXML_ERROR_PARSING_EMPTY,
+		TIXML_ERROR_READING_END_TAG,
+		TIXML_ERROR_PARSING_UNKNOWN,
+		TIXML_ERROR_PARSING_COMMENT,
+		TIXML_ERROR_PARSING_DECLARATION,
+		TIXML_ERROR_DOCUMENT_EMPTY,
+		TIXML_ERROR_EMBEDDED_NULL,
+		TIXML_ERROR_PARSING_CDATA,
+		TIXML_ERROR_DOCUMENT_TOP_ONLY,
+
+		TIXML_ERROR_STRING_COUNT
+	};
+
+protected:
+
+	static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
+	inline static bool IsWhiteSpace( char c )		
+	{ 
+		return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); 
+	}
+	inline static bool IsWhiteSpace( int c )
+	{
+		if ( c < 256 )
+			return IsWhiteSpace( (char) c );
+		return false;	// Again, only truly correct for English/Latin...but usually works.
+	}
+
+	#ifdef TIXML_USE_STL
+	static bool	StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
+	static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
+	#endif
+
+	/*	Reads an XML name into the string provided. Returns
+		a pointer just past the last character of the name,
+		or 0 if the function has an error.
+	*/
+	static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
+
+	/*	Reads text. Returns a pointer past the given end tag.
+		Wickedly complex options, but it keeps the (sensitive) code in one place.
+	*/
+	static const char* ReadText(	const char* in,				// where to start
+									TIXML_STRING* text,			// the string read
+									bool ignoreWhiteSpace,		// whether to keep the white space
+									const char* endTag,			// what ends this text
+									bool ignoreCase,			// whether to ignore case in the end tag
+									TiXmlEncoding encoding );	// the current encoding
+
+	// If an entity has been found, transform it into a character.
+	static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
+
+	// Get a character, while interpreting entities.
+	// The length can be from 0 to 4 bytes.
+	inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
+	{
+		assert( p );
+		if ( encoding == TIXML_ENCODING_UTF8 )
+		{
+			*length = utf8ByteTable[ *((const unsigned char*)p) ];
+			assert( *length >= 0 && *length < 5 );
+		}
+		else
+		{
+			*length = 1;
+		}
+
+		if ( *length == 1 )
+		{
+			if ( *p == '&' )
+				return GetEntity( p, _value, length, encoding );
+			*_value = *p;
+			return p+1;
+		}
+		else if ( *length )
+		{
+			//strncpy( _value, p, *length );	// lots of compilers don't like this function (unsafe),
+												// and the null terminator isn't needed
+			for( int i=0; p[i] && i<*length; ++i ) {
+				_value[i] = p[i];
+			}
+			return p + (*length);
+		}
+		else
+		{
+			// Not valid text.
+			return 0;
+		}
+	}
+
+	// Return true if the next characters in the stream are any of the endTag sequences.
+	// Ignore case only works for english, and should only be relied on when comparing
+	// to English words: StringEqual( p, "version", true ) is fine.
+	static bool StringEqual(	const char* p,
+								const char* endTag,
+								bool ignoreCase,
+								TiXmlEncoding encoding );
+
+	static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
+
+	TiXmlCursor location;
+
+    /// Field containing a generic user pointer
+	void*			userData;
+	
+	// None of these methods are reliable for any language except English.
+	// Good for approximation, not great for accuracy.
+	static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
+	static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+	inline static int ToLower( int v, TiXmlEncoding encoding )
+	{
+		if ( encoding == TIXML_ENCODING_UTF8 )
+		{
+			if ( v < 128 ) return tolower( v );
+			return v;
+		}
+		else
+		{
+			return tolower( v );
+		}
+	}
+	static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+private:
+	TiXmlBase( const TiXmlBase& );				// not implemented.
+	void operator=( const TiXmlBase& base );	// not allowed.
+
+	struct Entity
+	{
+		const char*     str;
+		unsigned int	strLength;
+		char		    chr;
+	};
+	enum
+	{
+		NUM_ENTITY = 5,
+		MAX_ENTITY_LENGTH = 6
+
+	};
+	static Entity entity[ NUM_ENTITY ];
+	static bool condenseWhiteSpace;
+};
+
+
+/** The parent class for everything in the Document Object Model.
+	(Except for attributes).
+	Nodes have siblings, a parent, and children. A node can be
+	in a document, or stand on its own. The type of a TiXmlNode
+	can be queried, and it can be cast to its more defined type.
+*/
+class TiXmlNode : public TiXmlBase
+{
+	friend class TiXmlDocument;
+	friend class TiXmlElement;
+
+public:
+	#ifdef TIXML_USE_STL	
+
+	    /** An input stream operator, for every class. Tolerant of newlines and
+		    formatting, but doesn't expect them.
+	    */
+	    friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
+
+	    /** An output stream operator, for every class. Note that this outputs
+		    without any newlines or formatting, as opposed to Print(), which
+		    includes tabs and new lines.
+
+		    The operator<< and operator>> are not completely symmetric. Writing
+		    a node to a stream is very well defined. You'll get a nice stream
+		    of output, without any extra whitespace or newlines.
+		    
+		    But reading is not as well defined. (As it always is.) If you create
+		    a TiXmlElement (for example) and read that from an input stream,
+		    the text needs to define an element or junk will result. This is
+		    true of all input streams, but it's worth keeping in mind.
+
+		    A TiXmlDocument will read nodes until it reads a root element, and
+			all the children of that root element.
+	    */	
+	    friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
+
+		/// Appends the XML node or attribute to a std::string.
+		friend std::string& operator<< (std::string& out, const TiXmlNode& base );
+
+	#endif
+
+	/** The types of XML nodes supported by TinyXml. (All the
+			unsupported types are picked up by UNKNOWN.)
+	*/
+	enum NodeType
+	{
+		DOCUMENT,
+		ELEMENT,
+		COMMENT,
+		UNKNOWN,
+		TEXT,
+		DECLARATION,
+		TYPECOUNT
+	};
+
+	virtual ~TiXmlNode();
+
+	/** The meaning of 'value' changes for the specific type of
+		TiXmlNode.
+		@verbatim
+		Document:	filename of the xml file
+		Element:	name of the element
+		Comment:	the comment text
+		Unknown:	the tag contents
+		Text:		the text string
+		@endverbatim
+
+		The subclasses will wrap this function.
+	*/
+	const char *Value() const { return value.c_str (); }
+
+    #ifdef TIXML_USE_STL
+	/** Return Value() as a std::string. If you only use STL,
+	    this is more efficient than calling Value().
+		Only available in STL mode.
+	*/
+	const std::string& ValueStr() const { return value; }
+	#endif
+
+	const TIXML_STRING& ValueTStr() const { return value; }
+
+	/** Changes the value of the node. Defined as:
+		@verbatim
+		Document:	filename of the xml file
+		Element:	name of the element
+		Comment:	the comment text
+		Unknown:	the tag contents
+		Text:		the text string
+		@endverbatim
+	*/
+	void SetValue(const char * _value) { value = _value;}
+
+    #ifdef TIXML_USE_STL
+	/// STL std::string form.
+	void SetValue( const std::string& _value )	{ value = _value; }
+	#endif
+
+	/// Delete all the children of this node. Does not affect 'this'.
+	void Clear();
+
+	/// One step up the DOM.
+	TiXmlNode* Parent()							{ return parent; }
+	const TiXmlNode* Parent() const				{ return parent; }
+
+	const TiXmlNode* FirstChild()	const		{ return firstChild; }	///< The first child of this node. Will be null if there are no children.
+	TiXmlNode* FirstChild()						{ return firstChild; }
+	const TiXmlNode* FirstChild( const char * value ) const;			///< The first child of this node with the matching 'value'. Will be null if none found.
+	/// The first child of this node with the matching 'value'. Will be null if none found.
+	TiXmlNode* FirstChild( const char * _value ) {
+		// Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
+		// call the method, cast the return back to non-const.
+		return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
+	}
+	const TiXmlNode* LastChild() const	{ return lastChild; }		/// The last child of this node. Will be null if there are no children.
+	TiXmlNode* LastChild()	{ return lastChild; }
+	
+	const TiXmlNode* LastChild( const char * value ) const;			/// The last child of this node matching 'value'. Will be null if there are no children.
+	TiXmlNode* LastChild( const char * _value ) {
+		return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlNode* FirstChild( const std::string& _value ) const	{	return FirstChild (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* FirstChild( const std::string& _value )				{	return FirstChild (_value.c_str ());	}	///< STL std::string form.
+	const TiXmlNode* LastChild( const std::string& _value ) const	{	return LastChild (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* LastChild( const std::string& _value )				{	return LastChild (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/** An alternate way to walk the children of a node.
+		One way to iterate over nodes is:
+		@verbatim
+			for( child = parent->FirstChild(); child; child = child->NextSibling() )
+		@endverbatim
+
+		IterateChildren does the same thing with the syntax:
+		@verbatim
+			child = 0;
+			while( child = parent->IterateChildren( child ) )
+		@endverbatim
+
+		IterateChildren takes the previous child as input and finds
+		the next one. If the previous child is null, it returns the
+		first. IterateChildren will return null when done.
+	*/
+	const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
+	TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
+	}
+
+	/// This flavor of IterateChildren searches for children with a particular 'value'
+	const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
+	TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const	{	return IterateChildren (_value.c_str (), previous);	}	///< STL std::string form.
+	TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) {	return IterateChildren (_value.c_str (), previous);	}	///< STL std::string form.
+	#endif
+
+	/** Add a new node related to this. Adds a child past the LastChild.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
+
+
+	/** Add a new node related to this. Adds a child past the LastChild.
+
+		NOTE: the node to be added is passed by pointer, and will be
+		henceforth owned (and deleted) by tinyXml. This method is efficient
+		and avoids an extra copy, but should be used with care as it
+		uses a different memory model than the other insert functions.
+
+		@sa InsertEndChild
+	*/
+	TiXmlNode* LinkEndChild( TiXmlNode* addThis );
+
+	/** Add a new node related to this. Adds a child before the specified child.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
+
+	/** Add a new node related to this. Adds a child after the specified child.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* InsertAfterChild(  TiXmlNode* afterThis, const TiXmlNode& addThis );
+
+	/** Replace a child of this node.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
+
+	/// Delete a child of this node.
+	bool RemoveChild( TiXmlNode* removeThis );
+
+	/// Navigate to a sibling node.
+	const TiXmlNode* PreviousSibling() const			{ return prev; }
+	TiXmlNode* PreviousSibling()						{ return prev; }
+
+	/// Navigate to a sibling node.
+	const TiXmlNode* PreviousSibling( const char * ) const;
+	TiXmlNode* PreviousSibling( const char *_prev ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlNode* PreviousSibling( const std::string& _value ) const	{	return PreviousSibling (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* PreviousSibling( const std::string& _value ) 			{	return PreviousSibling (_value.c_str ());	}	///< STL std::string form.
+	const TiXmlNode* NextSibling( const std::string& _value) const		{	return NextSibling (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* NextSibling( const std::string& _value) 					{	return NextSibling (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/// Navigate to a sibling node.
+	const TiXmlNode* NextSibling() const				{ return next; }
+	TiXmlNode* NextSibling()							{ return next; }
+
+	/// Navigate to a sibling node with the given 'value'.
+	const TiXmlNode* NextSibling( const char * ) const;
+	TiXmlNode* NextSibling( const char* _next ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
+	}
+
+	/** Convenience function to get through elements.
+		Calls NextSibling and ToElement. Will skip all non-Element
+		nodes. Returns 0 if there is not another element.
+	*/
+	const TiXmlElement* NextSiblingElement() const;
+	TiXmlElement* NextSiblingElement() {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
+	}
+
+	/** Convenience function to get through elements.
+		Calls NextSibling and ToElement. Will skip all non-Element
+		nodes. Returns 0 if there is not another element.
+	*/
+	const TiXmlElement* NextSiblingElement( const char * ) const;
+	TiXmlElement* NextSiblingElement( const char *_next ) {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlElement* NextSiblingElement( const std::string& _value) const	{	return NextSiblingElement (_value.c_str ());	}	///< STL std::string form.
+	TiXmlElement* NextSiblingElement( const std::string& _value)				{	return NextSiblingElement (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/// Convenience function to get through elements.
+	const TiXmlElement* FirstChildElement()	const;
+	TiXmlElement* FirstChildElement() {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
+	}
+
+	/// Convenience function to get through elements.
+	const TiXmlElement* FirstChildElement( const char * _value ) const;
+	TiXmlElement* FirstChildElement( const char * _value ) {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlElement* FirstChildElement( const std::string& _value ) const	{	return FirstChildElement (_value.c_str ());	}	///< STL std::string form.
+	TiXmlElement* FirstChildElement( const std::string& _value )				{	return FirstChildElement (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/** Query the type (as an enumerated value, above) of this node.
+		The possible types are: DOCUMENT, ELEMENT, COMMENT,
+								UNKNOWN, TEXT, and DECLARATION.
+	*/
+	int Type() const	{ return type; }
+
+	/** Return a pointer to the Document this node lives in.
+		Returns null if not in a document.
+	*/
+	const TiXmlDocument* GetDocument() const;
+	TiXmlDocument* GetDocument() {
+		return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
+	}
+
+	/// Returns true if this node has no children.
+	bool NoChildren() const						{ return !firstChild; }
+
+	virtual const TiXmlDocument*    ToDocument()    const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlElement*     ToElement()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlComment*     ToComment()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlUnknown*     ToUnknown()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlText*        ToText()        const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+	virtual TiXmlDocument*          ToDocument()    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlElement*           ToElement()	    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlComment*           ToComment()     { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlUnknown*           ToUnknown()	    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlText*	            ToText()        { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlDeclaration*       ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+	/** Create an exact duplicate of this node and return it. The memory must be deleted
+		by the caller. 
+	*/
+	virtual TiXmlNode* Clone() const = 0;
+
+	/** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the 
+		XML tree will be conditionally visited and the host will be called back
+		via the TiXmlVisitor interface.
+
+		This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
+		the XML for the callbacks, so the performance of TinyXML is unchanged by using this
+		interface versus any other.)
+
+		The interface has been based on ideas from:
+
+		- http://www.saxproject.org/
+		- http://c2.com/cgi/wiki?HierarchicalVisitorPattern 
+
+		Which are both good references for "visiting".
+
+		An example of using Accept():
+		@verbatim
+		TiXmlPrinter printer;
+		tinyxmlDoc.Accept( &printer );
+		const char* xmlcstr = printer.CStr();
+		@endverbatim
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const = 0;
+
+protected:
+	TiXmlNode( NodeType _type );
+
+	// Copy to the allocated object. Shared functionality between Clone, Copy constructor,
+	// and the assignment operator.
+	void CopyTo( TiXmlNode* target ) const;
+
+	#ifdef TIXML_USE_STL
+	    // The real work of the input operator.
+	virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
+	#endif
+
+	// Figure out what is at *p, and parse it. Returns null if it is not an xml node.
+	TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+
+	TiXmlNode*		parent;
+	NodeType		type;
+
+	TiXmlNode*		firstChild;
+	TiXmlNode*		lastChild;
+
+	TIXML_STRING	value;
+
+	TiXmlNode*		prev;
+	TiXmlNode*		next;
+
+private:
+	TiXmlNode( const TiXmlNode& );				// not implemented.
+	void operator=( const TiXmlNode& base );	// not allowed.
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+	number of attributes, each with a unique name.
+
+	@note The attributes are not TiXmlNodes, since they are not
+		  part of the tinyXML document object model. There are other
+		  suggested ways to look at this problem.
+*/
+class TiXmlAttribute : public TiXmlBase
+{
+	friend class TiXmlAttributeSet;
+
+public:
+	/// Construct an empty attribute.
+	TiXmlAttribute() : TiXmlBase()
+	{
+		document = 0;
+		prev = next = 0;
+	}
+
+	#ifdef TIXML_USE_STL
+	/// std::string constructor.
+	TiXmlAttribute( const std::string& _name, const std::string& _value )
+	{
+		name = _name;
+		value = _value;
+		document = 0;
+		prev = next = 0;
+	}
+	#endif
+
+	/// Construct an attribute with a name and value.
+	TiXmlAttribute( const char * _name, const char * _value )
+	{
+		name = _name;
+		value = _value;
+		document = 0;
+		prev = next = 0;
+	}
+
+	const char*		Name()  const		{ return name.c_str(); }		///< Return the name of this attribute.
+	const char*		Value() const		{ return value.c_str(); }		///< Return the value of this attribute.
+	#ifdef TIXML_USE_STL
+	const std::string& ValueStr() const	{ return value; }				///< Return the value of this attribute.
+	#endif
+	int				IntValue() const;									///< Return the value of this attribute, converted to an integer.
+	double			DoubleValue() const;								///< Return the value of this attribute, converted to a double.
+
+	// Get the tinyxml string representation
+	const TIXML_STRING& NameTStr() const { return name; }
+
+	/** QueryIntValue examines the value string. It is an alternative to the
+		IntValue() method with richer error checking.
+		If the value is an integer, it is stored in 'value' and 
+		the call returns TIXML_SUCCESS. If it is not
+		an integer, it returns TIXML_WRONG_TYPE.
+
+		A specialized but useful call. Note that for success it returns 0,
+		which is the opposite of almost all other TinyXml calls.
+	*/
+	int QueryIntValue( int* _value ) const;
+	/// QueryDoubleValue examines the value string. See QueryIntValue().
+	int QueryDoubleValue( double* _value ) const;
+
+	void SetName( const char* _name )	{ name = _name; }				///< Set the name of this attribute.
+	void SetValue( const char* _value )	{ value = _value; }				///< Set the value.
+
+	void SetIntValue( int _value );										///< Set the value from an integer.
+	void SetDoubleValue( double _value );								///< Set the value from a double.
+
+    #ifdef TIXML_USE_STL
+	/// STL std::string form.
+	void SetName( const std::string& _name )	{ name = _name; }	
+	/// STL std::string form.	
+	void SetValue( const std::string& _value )	{ value = _value; }
+	#endif
+
+	/// Get the next sibling attribute in the DOM. Returns null at end.
+	const TiXmlAttribute* Next() const;
+	TiXmlAttribute* Next() {
+		return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); 
+	}
+
+	/// Get the previous sibling attribute in the DOM. Returns null at beginning.
+	const TiXmlAttribute* Previous() const;
+	TiXmlAttribute* Previous() {
+		return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); 
+	}
+
+	bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
+	bool operator<( const TiXmlAttribute& rhs )	 const { return name < rhs.name; }
+	bool operator>( const TiXmlAttribute& rhs )  const { return name > rhs.name; }
+
+	/*	Attribute parsing starts: first letter of the name
+						 returns: the next char after the value end quote
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	// Prints this Attribute to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const {
+		Print( cfile, depth, 0 );
+	}
+	void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+
+	// [internal use]
+	// Set the document pointer so the attribute can report errors.
+	void SetDocument( TiXmlDocument* doc )	{ document = doc; }
+
+private:
+	TiXmlAttribute( const TiXmlAttribute& );				// not implemented.
+	void operator=( const TiXmlAttribute& base );	// not allowed.
+
+	TiXmlDocument*	document;	// A pointer back to a document, for error reporting.
+	TIXML_STRING name;
+	TIXML_STRING value;
+	TiXmlAttribute*	prev;
+	TiXmlAttribute*	next;
+};
+
+
+/*	A class used to manage a group of attributes.
+	It is only used internally, both by the ELEMENT and the DECLARATION.
+	
+	The set can be changed transparent to the Element and Declaration
+	classes that use it, but NOT transparent to the Attribute
+	which has to implement a next() and previous() method. Which makes
+	it a bit problematic and prevents the use of STL.
+
+	This version is implemented with circular lists because:
+		- I like circular lists
+		- it demonstrates some independence from the (typical) doubly linked list.
+*/
+class TiXmlAttributeSet
+{
+public:
+	TiXmlAttributeSet();
+	~TiXmlAttributeSet();
+
+	void Add( TiXmlAttribute* attribute );
+	void Remove( TiXmlAttribute* attribute );
+
+	const TiXmlAttribute* First()	const	{ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+	TiXmlAttribute* First()					{ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+	const TiXmlAttribute* Last() const		{ return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+	TiXmlAttribute* Last()					{ return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+
+	const TiXmlAttribute*	Find( const char* _name ) const;
+	TiXmlAttribute*	Find( const char* _name ) {
+		return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
+	}
+	#ifdef TIXML_USE_STL
+	const TiXmlAttribute*	Find( const std::string& _name ) const;
+	TiXmlAttribute*	Find( const std::string& _name ) {
+		return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
+	}
+
+	#endif
+
+private:
+	//*ME:	Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
+	//*ME:	this class must be also use a hidden/disabled copy-constructor !!!
+	TiXmlAttributeSet( const TiXmlAttributeSet& );	// not allowed
+	void operator=( const TiXmlAttributeSet& );	// not allowed (as TiXmlAttribute)
+
+	TiXmlAttribute sentinel;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+	and can contain other elements, text, comments, and unknowns.
+	Elements also contain an arbitrary number of attributes.
+*/
+class TiXmlElement : public TiXmlNode
+{
+public:
+	/// Construct an element.
+	TiXmlElement (const char * in_value);
+
+	#ifdef TIXML_USE_STL
+	/// std::string constructor.
+	TiXmlElement( const std::string& _value );
+	#endif
+
+	TiXmlElement( const TiXmlElement& );
+
+	void operator=( const TiXmlElement& base );
+
+	virtual ~TiXmlElement();
+
+	/** Given an attribute name, Attribute() returns the value
+		for the attribute of that name, or null if none exists.
+	*/
+	const char* Attribute( const char* name ) const;
+
+	/** Given an attribute name, Attribute() returns the value
+		for the attribute of that name, or null if none exists.
+		If the attribute exists and can be converted to an integer,
+		the integer value will be put in the return 'i', if 'i'
+		is non-null.
+	*/
+	const char* Attribute( const char* name, int* i ) const;
+
+	/** Given an attribute name, Attribute() returns the value
+		for the attribute of that name, or null if none exists.
+		If the attribute exists and can be converted to an double,
+		the double value will be put in the return 'd', if 'd'
+		is non-null.
+	*/
+	const char* Attribute( const char* name, double* d ) const;
+
+	/** QueryIntAttribute examines the attribute - it is an alternative to the
+		Attribute() method with richer error checking.
+		If the attribute is an integer, it is stored in 'value' and 
+		the call returns TIXML_SUCCESS. If it is not
+		an integer, it returns TIXML_WRONG_TYPE. If the attribute
+		does not exist, then TIXML_NO_ATTRIBUTE is returned.
+	*/	
+	int QueryIntAttribute( const char* name, int* _value ) const;
+	/// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
+	int QueryDoubleAttribute( const char* name, double* _value ) const;
+	/// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
+	int QueryFloatAttribute( const char* name, float* _value ) const {
+		double d;
+		int result = QueryDoubleAttribute( name, &d );
+		if ( result == TIXML_SUCCESS ) {
+			*_value = (float)d;
+		}
+		return result;
+	}
+
+    #ifdef TIXML_USE_STL
+	/** Template form of the attribute query which will try to read the
+		attribute into the specified type. Very easy, very powerful, but
+		be careful to make sure to call this with the correct type.
+		
+		NOTE: This method doesn't work correctly for 'string' types.
+
+		@return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
+	*/
+	template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
+	{
+		const TiXmlAttribute* node = attributeSet.Find( name );
+		if ( !node )
+			return TIXML_NO_ATTRIBUTE;
+
+		std::stringstream sstream( node->ValueStr() );
+		sstream >> *outValue;
+		if ( !sstream.fail() )
+			return TIXML_SUCCESS;
+		return TIXML_WRONG_TYPE;
+	}
+	/*
+	 This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string"
+	 but template specialization is hard to get working cross-compiler. Leaving the bug for now.
+	 
+	// The above will fail for std::string because the space character is used as a seperator.
+	// Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string
+	template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const
+	{
+		const TiXmlAttribute* node = attributeSet.Find( name );
+		if ( !node )
+			return TIXML_NO_ATTRIBUTE;
+		*outValue = node->ValueStr();
+		return TIXML_SUCCESS;
+	}
+	*/
+	#endif
+
+	/** Sets an attribute of name to a given value. The attribute
+		will be created if it does not exist, or changed if it does.
+	*/
+	void SetAttribute( const char* name, const char * _value );
+
+    #ifdef TIXML_USE_STL
+	const std::string* Attribute( const std::string& name ) const;
+	const std::string* Attribute( const std::string& name, int* i ) const;
+	const std::string* Attribute( const std::string& name, double* d ) const;
+	int QueryIntAttribute( const std::string& name, int* _value ) const;
+	int QueryDoubleAttribute( const std::string& name, double* _value ) const;
+
+	/// STL std::string form.
+	void SetAttribute( const std::string& name, const std::string& _value );
+	///< STL std::string form.
+	void SetAttribute( const std::string& name, int _value );
+	#endif
+
+	/** Sets an attribute of name to a given value. The attribute
+		will be created if it does not exist, or changed if it does.
+	*/
+	void SetAttribute( const char * name, int value );
+
+	/** Sets an attribute of name to a given value. The attribute
+		will be created if it does not exist, or changed if it does.
+	*/
+	void SetDoubleAttribute( const char * name, double value );
+
+	/** Deletes an attribute with the given name.
+	*/
+	void RemoveAttribute( const char * name );
+    #ifdef TIXML_USE_STL
+	void RemoveAttribute( const std::string& name )	{	RemoveAttribute (name.c_str ());	}	///< STL std::string form.
+	#endif
+
+	const TiXmlAttribute* FirstAttribute() const	{ return attributeSet.First(); }		///< Access the first attribute in this element.
+	TiXmlAttribute* FirstAttribute() 				{ return attributeSet.First(); }
+	const TiXmlAttribute* LastAttribute()	const 	{ return attributeSet.Last(); }		///< Access the last attribute in this element.
+	TiXmlAttribute* LastAttribute()					{ return attributeSet.Last(); }
+
+	/** Convenience function for easy access to the text inside an element. Although easy
+		and concise, GetText() is limited compared to getting the TiXmlText child
+		and accessing it directly.
+	
+		If the first child of 'this' is a TiXmlText, the GetText()
+		returns the character string of the Text node, else null is returned.
+
+		This is a convenient method for getting the text of simple contained text:
+		@verbatim
+		<foo>This is text</foo>
+		const char* str = fooElement->GetText();
+		@endverbatim
+
+		'str' will be a pointer to "This is text". 
+		
+		Note that this function can be misleading. If the element foo was created from
+		this XML:
+		@verbatim
+		<foo><b>This is text</b></foo> 
+		@endverbatim
+
+		then the value of str would be null. The first child node isn't a text node, it is
+		another element. From this XML:
+		@verbatim
+		<foo>This is <b>text</b></foo> 
+		@endverbatim
+		GetText() will return "This is ".
+
+		WARNING: GetText() accesses a child node - don't become confused with the 
+				 similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are 
+				 safe type casts on the referenced node.
+	*/
+	const char* GetText() const;
+
+	/// Creates a new Element and returns it - the returned element is a copy.
+	virtual TiXmlNode* Clone() const;
+	// Print the Element to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	/*	Attribtue parsing starts: next char past '<'
+						 returns: next char past '>'
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlElement*     ToElement()     const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlElement*           ToElement()	          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+
+	void CopyTo( TiXmlElement* target ) const;
+	void ClearThis();	// like clear, but initializes 'this' object as well
+
+	// Used to be public [internal use]
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+	/*	[internal use]
+		Reads the "value" of the element -- another element, or text.
+		This should terminate with the current end tag.
+	*/
+	const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+private:
+
+	TiXmlAttributeSet attributeSet;
+};
+
+
+/**	An XML comment.
+*/
+class TiXmlComment : public TiXmlNode
+{
+public:
+	/// Constructs an empty comment.
+	TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {}
+	/// Construct a comment from text.
+	TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) {
+		SetValue( _value );
+	}
+	TiXmlComment( const TiXmlComment& );
+	void operator=( const TiXmlComment& base );
+
+	virtual ~TiXmlComment()	{}
+
+	/// Returns a copy of this Comment.
+	virtual TiXmlNode* Clone() const;
+	// Write this Comment to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	/*	Attribtue parsing starts: at the ! of the !--
+						 returns: next char past '>'
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlComment*  ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlComment*  ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+	void CopyTo( TiXmlComment* target ) const;
+
+	// used to be public
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+//	virtual void StreamOut( TIXML_OSTREAM * out ) const;
+
+private:
+
+};
+
+
+/** XML text. A text node can have 2 ways to output the next. "normal" output 
+	and CDATA. It will default to the mode it was parsed from the XML file and
+	you generally want to leave it alone, but you can change the output mode with 
+	SetCDATA() and query it with CDATA().
+*/
+class TiXmlText : public TiXmlNode
+{
+	friend class TiXmlElement;
+public:
+	/** Constructor for text element. By default, it is treated as 
+		normal, encoded text. If you want it be output as a CDATA text
+		element, set the parameter _cdata to 'true'
+	*/
+	TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT)
+	{
+		SetValue( initValue );
+		cdata = false;
+	}
+	virtual ~TiXmlText() {}
+
+	#ifdef TIXML_USE_STL
+	/// Constructor.
+	TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT)
+	{
+		SetValue( initValue );
+		cdata = false;
+	}
+	#endif
+
+	TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT )	{ copy.CopyTo( this ); }
+	void operator=( const TiXmlText& base )							 	{ base.CopyTo( this ); }
+
+	// Write this text object to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	/// Queries whether this represents text using a CDATA section.
+	bool CDATA() const				{ return cdata; }
+	/// Turns on or off a CDATA representation of text.
+	void SetCDATA( bool _cdata )	{ cdata = _cdata; }
+
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlText*       ToText()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+	///  [internal use] Creates a new Element and returns it.
+	virtual TiXmlNode* Clone() const;
+	void CopyTo( TiXmlText* target ) const;
+
+	bool Blank() const;	// returns true if all white space and new lines
+	// [internal use]
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+	bool cdata;			// true if this should be input and output as a CDATA style text element
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+	@verbatim
+		<?xml version="1.0" standalone="yes"?>
+	@endverbatim
+
+	TinyXml will happily read or write files without a declaration,
+	however. There are 3 possible attributes to the declaration:
+	version, encoding, and standalone.
+
+	Note: In this version of the code, the attributes are
+	handled as special cases, not generic attributes, simply
+	because there can only be at most 3 and they are always the same.
+*/
+class TiXmlDeclaration : public TiXmlNode
+{
+public:
+	/// Construct an empty declaration.
+	TiXmlDeclaration()   : TiXmlNode( TiXmlNode::DECLARATION ) {}
+
+#ifdef TIXML_USE_STL
+	/// Constructor.
+	TiXmlDeclaration(	const std::string& _version,
+						const std::string& _encoding,
+						const std::string& _standalone );
+#endif
+
+	/// Construct.
+	TiXmlDeclaration(	const char* _version,
+						const char* _encoding,
+						const char* _standalone );
+
+	TiXmlDeclaration( const TiXmlDeclaration& copy );
+	void operator=( const TiXmlDeclaration& copy );
+
+	virtual ~TiXmlDeclaration()	{}
+
+	/// Version. Will return an empty string if none was found.
+	const char *Version() const			{ return version.c_str (); }
+	/// Encoding. Will return an empty string if none was found.
+	const char *Encoding() const		{ return encoding.c_str (); }
+	/// Is this a standalone document?
+	const char *Standalone() const		{ return standalone.c_str (); }
+
+	/// Creates a copy of this Declaration and returns it.
+	virtual TiXmlNode* Clone() const;
+	// Print this declaration to a FILE stream.
+	virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+	virtual void Print( FILE* cfile, int depth ) const {
+		Print( cfile, depth, 0 );
+	}
+
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlDeclaration*       ToDeclaration()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+	void CopyTo( TiXmlDeclaration* target ) const;
+	// used to be public
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+
+	TIXML_STRING version;
+	TIXML_STRING encoding;
+	TIXML_STRING standalone;
+};
+
+
+/** Any tag that tinyXml doesn't recognize is saved as an
+	unknown. It is a tag of text, but should not be modified.
+	It will be written back to the XML, unchanged, when the file
+	is saved.
+
+	DTD tags get thrown into TiXmlUnknowns.
+*/
+class TiXmlUnknown : public TiXmlNode
+{
+public:
+	TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN )	{}
+	virtual ~TiXmlUnknown() {}
+
+	TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN )		{ copy.CopyTo( this ); }
+	void operator=( const TiXmlUnknown& copy )										{ copy.CopyTo( this ); }
+
+	/// Creates a copy of this Unknown and returns it.
+	virtual TiXmlNode* Clone() const;
+	// Print this Unknown to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlUnknown*     ToUnknown()     const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlUnknown*           ToUnknown()	    { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected:
+	void CopyTo( TiXmlUnknown* target ) const;
+
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+
+};
+
+
+/** Always the top level node. A document binds together all the
+	XML pieces. It can be saved, loaded, and printed to the screen.
+	The 'value' of a document node is the xml file name.
+*/
+class TiXmlDocument : public TiXmlNode
+{
+public:
+	/// Create an empty document, that has no name.
+	TiXmlDocument();
+	/// Create a document with a name. The name of the document is also the filename of the xml.
+	TiXmlDocument( const char * documentName );
+
+	#ifdef TIXML_USE_STL
+	/// Constructor.
+	TiXmlDocument( const std::string& documentName );
+	#endif
+
+	TiXmlDocument( const TiXmlDocument& copy );
+	void operator=( const TiXmlDocument& copy );
+
+	virtual ~TiXmlDocument() {}
+
+	/** Load a file using the current document value.
+		Returns true if successful. Will delete any existing
+		document data before loading.
+	*/
+	bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	/// Save a file using the current document value. Returns true if successful.
+	bool SaveFile() const;
+	/// Load a file using the given filename. Returns true if successful.
+	bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	/// Save a file using the given filename. Returns true if successful.
+	bool SaveFile( const char * filename ) const;
+	/** Load a file using the given FILE*. Returns true if successful. Note that this method
+		doesn't stream - the entire object pointed at by the FILE*
+		will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
+		file location. Streaming may be added in the future.
+	*/
+	bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	/// Save a file using the given FILE*. Returns true if successful.
+	bool SaveFile( FILE* ) const;
+
+	#ifdef TIXML_USE_STL
+	bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING )			///< STL std::string version.
+	{
+//		StringToBuffer f( filename );
+//		return ( f.buffer && LoadFile( f.buffer, encoding ));
+		return LoadFile( filename.c_str(), encoding );
+	}
+	bool SaveFile( const std::string& filename ) const		///< STL std::string version.
+	{
+//		StringToBuffer f( filename );
+//		return ( f.buffer && SaveFile( f.buffer ));
+		return SaveFile( filename.c_str() );
+	}
+	#endif
+
+	/** Parse the given null terminated block of xml data. Passing in an encoding to this
+		method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
+		to use that encoding, regardless of what TinyXml might otherwise try to detect.
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+
+	/** Get the root element -- the only top level element -- of the document.
+		In well formed XML, there should only be one. TinyXml is tolerant of
+		multiple elements at the document level.
+	*/
+	const TiXmlElement* RootElement() const		{ return FirstChildElement(); }
+	TiXmlElement* RootElement()					{ return FirstChildElement(); }
+
+	/** If an error occurs, Error will be set to true. Also,
+		- The ErrorId() will contain the integer identifier of the error (not generally useful)
+		- The ErrorDesc() method will return the name of the error. (very useful)
+		- The ErrorRow() and ErrorCol() will return the location of the error (if known)
+	*/	
+	bool Error() const						{ return error; }
+
+	/// Contains a textual (english) description of the error if one occurs.
+	const char * ErrorDesc() const	{ return errorDesc.c_str (); }
+
+	/** Generally, you probably want the error string ( ErrorDesc() ). But if you
+		prefer the ErrorId, this function will fetch it.
+	*/
+	int ErrorId()	const				{ return errorId; }
+
+	/** Returns the location (if known) of the error. The first column is column 1, 
+		and the first row is row 1. A value of 0 means the row and column wasn't applicable
+		(memory errors, for example, have no row/column) or the parser lost the error. (An
+		error in the error reporting, in that case.)
+
+		@sa SetTabSize, Row, Column
+	*/
+	int ErrorRow() const	{ return errorLocation.row+1; }
+	int ErrorCol() const	{ return errorLocation.col+1; }	///< The column where the error occured. See ErrorRow()
+
+	/** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
+		to report the correct values for row and column. It does not change the output
+		or input in any way.
+		
+		By calling this method, with a tab size
+		greater than 0, the row and column of each node and attribute is stored
+		when the file is loaded. Very useful for tracking the DOM back in to
+		the source file.
+
+		The tab size is required for calculating the location of nodes. If not
+		set, the default of 4 is used. The tabsize is set per document. Setting
+		the tabsize to 0 disables row/column tracking.
+
+		Note that row and column tracking is not supported when using operator>>.
+
+		The tab size needs to be enabled before the parse or load. Correct usage:
+		@verbatim
+		TiXmlDocument doc;
+		doc.SetTabSize( 8 );
+		doc.Load( "myfile.xml" );
+		@endverbatim
+
+		@sa Row, Column
+	*/
+	void SetTabSize( int _tabsize )		{ tabsize = _tabsize; }
+
+	int TabSize() const	{ return tabsize; }
+
+	/** If you have handled the error, it can be reset with this call. The error
+		state is automatically cleared if you Parse a new XML block.
+	*/
+	void ClearError()						{	error = false; 
+												errorId = 0; 
+												errorDesc = ""; 
+												errorLocation.row = errorLocation.col = 0; 
+												//errorLocation.last = 0; 
+											}
+
+	/** Write the document to standard out using formatted printing ("pretty print"). */
+	void Print() const						{ Print( stdout, 0 ); }
+
+	/* Write the document to a string using formatted printing ("pretty print"). This
+		will allocate a character array (new char[]) and return it as a pointer. The
+		calling code pust call delete[] on the return char* to avoid a memory leak.
+	*/
+	//char* PrintToMemory() const; 
+
+	/// Print this Document to a FILE stream.
+	virtual void Print( FILE* cfile, int depth = 0 ) const;
+	// [internal use]
+	void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+	virtual const TiXmlDocument*    ToDocument()    const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlDocument*          ToDocument()          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+	// [internal use]
+	virtual TiXmlNode* Clone() const;
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+	void CopyTo( TiXmlDocument* target ) const;
+
+	bool error;
+	int  errorId;
+	TIXML_STRING errorDesc;
+	int tabsize;
+	TiXmlCursor errorLocation;
+	bool useMicrosoftBOM;		// the UTF-8 BOM were found when read. Note this, and try to write.
+};
+
+
+/**
+	A TiXmlHandle is a class that wraps a node pointer with null checks; this is
+	an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
+	DOM structure. It is a separate utility class.
+
+	Take an example:
+	@verbatim
+	<Document>
+		<Element attributeA = "valueA">
+			<Child attributeB = "value1" />
+			<Child attributeB = "value2" />
+		</Element>
+	<Document>
+	@endverbatim
+
+	Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very 
+	easy to write a *lot* of code that looks like:
+
+	@verbatim
+	TiXmlElement* root = document.FirstChildElement( "Document" );
+	if ( root )
+	{
+		TiXmlElement* element = root->FirstChildElement( "Element" );
+		if ( element )
+		{
+			TiXmlElement* child = element->FirstChildElement( "Child" );
+			if ( child )
+			{
+				TiXmlElement* child2 = child->NextSiblingElement( "Child" );
+				if ( child2 )
+				{
+					// Finally do something useful.
+	@endverbatim
+
+	And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
+	of such code. A TiXmlHandle checks for null	pointers so it is perfectly safe 
+	and correct to use:
+
+	@verbatim
+	TiXmlHandle docHandle( &document );
+	TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
+	if ( child2 )
+	{
+		// do something useful
+	@endverbatim
+
+	Which is MUCH more concise and useful.
+
+	It is also safe to copy handles - internally they are nothing more than node pointers.
+	@verbatim
+	TiXmlHandle handleCopy = handle;
+	@endverbatim
+
+	What they should not be used for is iteration:
+
+	@verbatim
+	int i=0; 
+	while ( true )
+	{
+		TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
+		if ( !child )
+			break;
+		// do something
+		++i;
+	}
+	@endverbatim
+
+	It seems reasonable, but it is in fact two embedded while loops. The Child method is 
+	a linear walk to find the element, so this code would iterate much more than it needs 
+	to. Instead, prefer:
+
+	@verbatim
+	TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
+
+	for( child; child; child=child->NextSiblingElement() )
+	{
+		// do something
+	}
+	@endverbatim
+*/
+class TiXmlHandle
+{
+public:
+	/// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+	TiXmlHandle( TiXmlNode* _node )					{ this->node = _node; }
+	/// Copy constructor
+	TiXmlHandle( const TiXmlHandle& ref )			{ this->node = ref.node; }
+	TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; }
+
+	/// Return a handle to the first child node.
+	TiXmlHandle FirstChild() const;
+	/// Return a handle to the first child node with the given name.
+	TiXmlHandle FirstChild( const char * value ) const;
+	/// Return a handle to the first child element.
+	TiXmlHandle FirstChildElement() const;
+	/// Return a handle to the first child element with the given name.
+	TiXmlHandle FirstChildElement( const char * value ) const;
+
+	/** Return a handle to the "index" child with the given name. 
+		The first child is 0, the second 1, etc.
+	*/
+	TiXmlHandle Child( const char* value, int index ) const;
+	/** Return a handle to the "index" child. 
+		The first child is 0, the second 1, etc.
+	*/
+	TiXmlHandle Child( int index ) const;
+	/** Return a handle to the "index" child element with the given name. 
+		The first child element is 0, the second 1, etc. Note that only TiXmlElements
+		are indexed: other types are not counted.
+	*/
+	TiXmlHandle ChildElement( const char* value, int index ) const;
+	/** Return a handle to the "index" child element. 
+		The first child element is 0, the second 1, etc. Note that only TiXmlElements
+		are indexed: other types are not counted.
+	*/
+	TiXmlHandle ChildElement( int index ) const;
+
+	#ifdef TIXML_USE_STL
+	TiXmlHandle FirstChild( const std::string& _value ) const				{ return FirstChild( _value.c_str() ); }
+	TiXmlHandle FirstChildElement( const std::string& _value ) const		{ return FirstChildElement( _value.c_str() ); }
+
+	TiXmlHandle Child( const std::string& _value, int index ) const			{ return Child( _value.c_str(), index ); }
+	TiXmlHandle ChildElement( const std::string& _value, int index ) const	{ return ChildElement( _value.c_str(), index ); }
+	#endif
+
+	/** Return the handle as a TiXmlNode. This may return null.
+	*/
+	TiXmlNode* ToNode() const			{ return node; } 
+	/** Return the handle as a TiXmlElement. This may return null.
+	*/
+	TiXmlElement* ToElement() const		{ return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+	/**	Return the handle as a TiXmlText. This may return null.
+	*/
+	TiXmlText* ToText() const			{ return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+	/** Return the handle as a TiXmlUnknown. This may return null.
+	*/
+	TiXmlUnknown* ToUnknown() const		{ return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+
+	/** @deprecated use ToNode. 
+		Return the handle as a TiXmlNode. This may return null.
+	*/
+	TiXmlNode* Node() const			{ return ToNode(); } 
+	/** @deprecated use ToElement. 
+		Return the handle as a TiXmlElement. This may return null.
+	*/
+	TiXmlElement* Element() const	{ return ToElement(); }
+	/**	@deprecated use ToText()
+		Return the handle as a TiXmlText. This may return null.
+	*/
+	TiXmlText* Text() const			{ return ToText(); }
+	/** @deprecated use ToUnknown()
+		Return the handle as a TiXmlUnknown. This may return null.
+	*/
+	TiXmlUnknown* Unknown() const	{ return ToUnknown(); }
+
+private:
+	TiXmlNode* node;
+};
+
+
+/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
+
+	-# Print to memory (especially in non-STL mode)
+	-# Control formatting (line endings, etc.)
+
+	When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
+	Before calling Accept() you can call methods to control the printing
+	of the XML document. After TiXmlNode::Accept() is called, the printed document can
+	be accessed via the CStr(), Str(), and Size() methods.
+
+	TiXmlPrinter uses the Visitor API.
+	@verbatim
+	TiXmlPrinter printer;
+	printer.SetIndent( "\t" );
+
+	doc.Accept( &printer );
+	fprintf( stdout, "%s", printer.CStr() );
+	@endverbatim
+*/
+class TiXmlPrinter : public TiXmlVisitor
+{
+public:
+	TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
+					 buffer(), indent( "    " ), lineBreak( "\n" ) {}
+
+	virtual bool VisitEnter( const TiXmlDocument& doc );
+	virtual bool VisitExit( const TiXmlDocument& doc );
+
+	virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
+	virtual bool VisitExit( const TiXmlElement& element );
+
+	virtual bool Visit( const TiXmlDeclaration& declaration );
+	virtual bool Visit( const TiXmlText& text );
+	virtual bool Visit( const TiXmlComment& comment );
+	virtual bool Visit( const TiXmlUnknown& unknown );
+
+	/** Set the indent characters for printing. By default 4 spaces
+		but tab (\t) is also useful, or null/empty string for no indentation.
+	*/
+	void SetIndent( const char* _indent )			{ indent = _indent ? _indent : "" ; }
+	/// Query the indention string.
+	const char* Indent()							{ return indent.c_str(); }
+	/** Set the line breaking string. By default set to newline (\n). 
+		Some operating systems prefer other characters, or can be
+		set to the null/empty string for no indenation.
+	*/
+	void SetLineBreak( const char* _lineBreak )		{ lineBreak = _lineBreak ? _lineBreak : ""; }
+	/// Query the current line breaking string.
+	const char* LineBreak()							{ return lineBreak.c_str(); }
+
+	/** Switch over to "stream printing" which is the most dense formatting without 
+		linebreaks. Common when the XML is needed for network transmission.
+	*/
+	void SetStreamPrinting()						{ indent = "";
+													  lineBreak = "";
+													}	
+	/// Return the result.
+	const char* CStr()								{ return buffer.c_str(); }
+	/// Return the length of the result string.
+	size_t Size()									{ return buffer.size(); }
+
+	#ifdef TIXML_USE_STL
+	/// Return the result.
+	const std::string& Str()						{ return buffer; }
+	#endif
+
+private:
+	void DoIndent()	{
+		for( int i=0; i<depth; ++i )
+			buffer += indent;
+	}
+	void DoLineBreak() {
+		buffer += lineBreak;
+	}
+
+	int depth;
+	bool simpleTextPrint;
+	TIXML_STRING buffer;
+	TIXML_STRING indent;
+	TIXML_STRING lineBreak;
+};
+
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif
+




More information about the Commit mailing list