Selaa lähdekoodia

Merge branch 'master' of https://github.com/sunsetbrew/civetweb

Conflicts:
	CREDITS.md
	LICENSE.md
	Makefile.deprecated
	RELEASE_NOTES.md
	VS2012/civetweb_lua/civetweb_lua.vcxproj
	VS2012/lua_lib/lua_lib.vcxproj
	VS2012/lua_lib/lua_lib.vcxproj.filters
	docs/Embedding.md
	include/civetweb.h
	resources/Makefile.in-lua
	src/civetweb.c
	src/main.c
	src/mod_lua.inl
	src/third_party/lsqlite3.c
William Greathouse 11 vuotta sitten
vanhempi
commit
03f35958e8

+ 9 - 0
CREDITS.md

@@ -1,5 +1,10 @@
 # Civitweb Contributors
 
+<<<<<<< HEAD
+=======
+* apkbox
+* bel2125
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 * Daniel Oaks
 * F-Secure Corporation
 * grenclave
@@ -7,6 +12,10 @@
 * Kimmo Mustonen
 * Morgan McGuire
 * No Face Press
+<<<<<<< HEAD
+=======
+* Paul Sokolovsky
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 * Thomas Davis
 * William Greathouse
 

+ 18 - 0
LICENSE.md

@@ -96,3 +96,21 @@ lsqlite3 License
 > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     
 > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                
 
+<<<<<<< HEAD
+=======
+Lua File System License
+------
+
+### Included only if built with Lua support.
+
+http://keplerproject.github.io/luafilesystem/license.html
+
+> Copyright © 2003 Kepler Project.
+>
+> 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.
+
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3

+ 12 - 0
Makefile.deprecated

@@ -42,11 +42,19 @@ endif
 
 LIB_SOURCES = src/civetweb.c
 
+<<<<<<< HEAD
 ALL_SOURCES = src/main.c $(LIB_SOURCES) src/third_party/sqlite3.c src/third_party/lsqlite3.c \
               $(LUA_SOURCES) $(YASSL_SOURCES)
 
 SQLITE_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
 CIVETWEB_FLAGS = -DUSE_LUA -DUSE_LUA_SQLITE3 $(COPT)
+=======
+ALL_SOURCES = src/main.c $(LIB_SOURCES) src/third_party/sqlite3.c src/third_party/lsqlite3.c src/third_party/lfs.c \
+              $(LUA_SOURCES) $(YASSL_SOURCES)
+
+SQLITE_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
+CIVETWEB_FLAGS = -DUSE_LUA -DUSE_LUA_SQLITE3 -DUSE_LUA_FILE_SYSTEM $(COPT)
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 FLAGS = $(CIVETWEB_FLAGS) $(SQLITE_FLAGS) $(LUA_FLAGS)
 
 
@@ -147,7 +155,11 @@ $(PROG).lib: $(ALL_WINOBJS)
 # security unlock ~/Library/Keychains/login.keychain
 # See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html
 Civetweb: $(LIB_SOURCES) src/main.c
+<<<<<<< HEAD
 	$(CC) $(LIB_SOURCES) src/main.c src/third_party/lsqlite3.c src/third_party/sqlite3.c \
+=======
+	$(CC) $(LIB_SOURCES) src/main.c src/third_party/lsqlite3.c src/third_party/sqlite3.c src/third_party/lfs.c \
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
           -DUSE_COCOA $(CFLAGS) $(FLAGS) -mmacosx-version-min=10.4 \
           $(YASSL_SOURCES) $(LUA_SOURCES) \
           -framework Cocoa -ObjC -arch i386 -arch x86_64 -o Civetweb

+ 12 - 0
RELEASE_NOTES.md

@@ -6,6 +6,18 @@ In planning.
 Changes
 -------
 
+<<<<<<< HEAD
+=======
+- Fixes page violation in mod_lua.inl (apkbox)
+- Use C style comments to enable compiling most of civetweb with -ansi. (F-Secure Corporation)
+- Allow directories with non ASCII characters in Windows in UTF-8 encoded (bel2125)
+- Added Lua File System support (bel2125)
+- Added mongoose history back in repository thanks to (Paul Sokolovsky)
+- Fixed keep alive (bel2125)
+- Updated of MIME types (bel2125)
+- Updated lsqlite (bel2125)
+- Fixed master thread priority (bel2125)
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 - Fixed IPV6 defines under Windowe (grenclave)
 - Fixed potential dead lock in connection_close() (Morgan McGuire)
 - Added WebSocket example using asynchronous server messages (William Greathouse)

+ 22 - 0
VS2012/civetweb_lua/civetweb_lua.vcxproj

@@ -27,7 +27,10 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
+<<<<<<< HEAD
     <PlatformToolset>v110</PlatformToolset>
+=======
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -39,7 +42,10 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
+<<<<<<< HEAD
     <PlatformToolset>v110</PlatformToolset>
+=======
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
@@ -88,7 +94,11 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
+<<<<<<< HEAD
       <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+=======
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -102,7 +112,11 @@
       </PrecompiledHeader>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
+<<<<<<< HEAD
       <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+=======
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -118,7 +132,11 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
+<<<<<<< HEAD
       <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+=======
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
@@ -136,7 +154,11 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
+<<<<<<< HEAD
       <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+=======
+      <PreprocessorDefinitions>LUA_COMPAT_ALL;USE_LUA;USE_LUA_SQLITE3;USE_LUA_FILE_SYSTEM;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
       <AdditionalIncludeDirectories>$(ProjectDir)..\..\include;$(ProjectDir)..\..\src\third_party\lua-5.2.2\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>

+ 14 - 0
VS2012/lua_lib/lua_lib.vcxproj

@@ -27,7 +27,10 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
+<<<<<<< HEAD
     <PlatformToolset>v110</PlatformToolset>
+=======
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -39,7 +42,10 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
+<<<<<<< HEAD
     <PlatformToolset>v110</PlatformToolset>
+=======
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
@@ -143,6 +149,10 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+<<<<<<< HEAD
+=======
+    <ClCompile Include="..\..\src\third_party\lfs.c" />
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lapi.c" />
     <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lauxlib.c" />
     <ClCompile Include="..\..\src\third_party\lua-5.2.2\src\lbaselib.c" />
@@ -179,6 +189,10 @@
     <ClCompile Include="..\..\src\third_party\sqlite3.c" />
   </ItemGroup>
   <ItemGroup>
+<<<<<<< HEAD
+=======
+    <ClInclude Include="..\..\src\third_party\lfs.h" />
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     <ClInclude Include="..\..\src\third_party\sqlite3.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 12 - 0
VS2012/lua_lib/lua_lib.vcxproj.filters

@@ -117,10 +117,22 @@
     <ClCompile Include="..\..\src\third_party\sqlite3.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+<<<<<<< HEAD
+=======
+    <ClCompile Include="..\..\src\third_party\lfs.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\third_party\sqlite3.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+<<<<<<< HEAD
+=======
+    <ClInclude Include="..\..\src\third_party\lfs.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
   </ItemGroup>
 </Project>

+ 9 - 0
docs/Embedding.md

@@ -59,6 +59,10 @@ Lua is a server side include functionality.  Files ending in .la will be process
   - -DLUA_COMPAT_ALL
   - -DUSE_LUA
   - -DUSE_LUA_SQLITE3
+<<<<<<< HEAD
+=======
+  - -DUSE_LUA_FILE_SYSTEM
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 ##### Add the following sources
 
@@ -99,6 +103,11 @@ Lua is a server side include functionality.  Files ending in .la will be process
   - src/third_party/sqlite3.c
   - src/third_party/sqlite3.h
   - src/third_party/lsqlite3.c
+<<<<<<< HEAD
+=======
+  - src/third_party/lfs.c
+  - src/third_party/lfs.h
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 
 Civetweb internals

+ 15 - 0
examples/ws_server/docroot/index.html

@@ -223,6 +223,7 @@
 
 <script language="javascript" type="text/javascript">
     var connection; // websocket connection
+    var count=1;
 
     function writeToScreen (message) {
         var div = document.createElement('div');
@@ -232,6 +233,14 @@
         output.scrollTop = output.scrollHeight;
     }
 
+    function send_counter() {
+        if (connection.bufferedAmount == 0)
+        {
+            connection.send('counter ' + count);
+            count = count+1;
+        }
+    }
+
     function ws_connect() {
         // check for websocket support
         // for Internet Explorer < 10 there are options for websocket support that
@@ -252,6 +261,7 @@
             };
 
             connection.onclose = function(ev) {
+                clearInterval(counterid);
                 document.getElementById("update").disabled=true;
                 document.getElementById("update").innerHTML = "Enable Update";
                 document.getElementById("connection").innerHTML = "WebSocket Connect";
@@ -268,13 +278,18 @@
                     meter.style.width = percent+"%";
                 }
                 else
+                {
                     writeToScreen('RECEIVED: ' + ev.data);
+                }
+                send_counter();
             };
 
             connection.onerror = function(ev) {
                 alert("WebSocket error");
             };
 
+            counterid = setInterval(send_counter, 10);
+
         } else {
             alert("WebSocket is not available!!!\n" +
                   "Demo will not function.");

+ 53 - 2
examples/ws_server/ws_server.c

@@ -15,6 +15,7 @@ struct ws_connection {
     struct mg_connection    *conn;
     int     update;
     int     closing;
+    long    counter;
 };
 
 // time base and structure periodic updates to client for demo
@@ -30,6 +31,28 @@ struct progress {
 #define CONNECTIONS 16
 static struct ws_connection ws_conn[CONNECTIONS];
 
+#define PING_ACTIVE
+
+#define PING_THREAD
+
+#if defined(PING_ACTIVE) && defined(PING_THREAD)
+// ws_ping_thread()
+// Send periodic PING to assure websocket remains connected, except if we are closing
+static void *ws_ping_thread(void *parm)
+{
+    int wsd = (long)parm;
+    struct mg_connection    *conn = ws_conn[wsd].conn;
+
+    while(!ws_conn[wsd].closing)
+    {
+        usleep(8000);   /* 8 ms */
+        if (!ws_conn[wsd].closing)
+            mg_websocket_write(conn, WEBSOCKET_OPCODE_PING, NULL, 0);
+    }
+    fprintf(stderr, "ws_ping_thread %d exiting\n", wsd);
+}
+#endif
+
 
 // ws_server_thread()
 // Simple demo server thread. Sends periodic updates to connected clients
@@ -64,9 +87,13 @@ static void *ws_server_thread(void *parm)
         mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, tstr, strlen(tstr));
     }
 
+#if defined(PING_ACTIVE) && defined(PING_THREAD)
+    mg_start_thread(ws_ping_thread, (void *)(long)wsd);
+#endif
+
     /* While the connection is open, send periodic updates */
     while(!ws_conn[wsd].closing) {
-        usleep(100000); /* 0.1 second */
+        usleep(10000); /* 0.01 second */
         timer++;
 
         /* Send meter updates */
@@ -89,9 +116,11 @@ static void *ws_server_thread(void *parm)
             }
         }
 
+#if defined(PING_ACTIVE) && !defined(PING_THREAD)
         /* Send periodic PING to assure websocket remains connected, except if we are closing */
         if (timer%100 == 0 && !ws_conn[wsd].closing)
             mg_websocket_write(conn, WEBSOCKET_OPCODE_PING, NULL, 0);
+#endif
     }
 
     fprintf(stderr, "ws_server_thread %d exiting\n", wsd);
@@ -120,6 +149,7 @@ static int websocket_connect_handler(const struct mg_connection *conn)
             ws_conn[i].conn = (struct mg_connection *)conn;
             ws_conn[i].closing = 0;
             ws_conn[i].update = 0;
+            ws_conn[i].counter = -1;
             break;
         }
     }
@@ -192,19 +222,40 @@ static int websocket_data_handler(struct mg_connection *conn, int flags,
             fprintf(stderr, "CONTINUATION...\n");
             break;
         case WEBSOCKET_OPCODE_TEXT:
-            fprintf(stderr, "TEXT: %-.*s\n", (int)data_len, data);
+            //fprintf(stderr, "TEXT: %-.*s\n", (int)data_len, data);
             /*** interpret data as commands here ***/
             if (strncmp("update on", data, data_len)== 0) {
+                fprintf(stderr, "TEXT: %-.*s\n", (int)data_len, data);
                 /* turn on updates */
                 ws_conn[wsd].update = 1;
                 /* echo back */
                 mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
             } else if (strncmp("update off", data, data_len)== 0) {
+                fprintf(stderr, "TEXT: %-.*s\n", (int)data_len, data);
                 /* turn off updates */
                 ws_conn[wsd].update = 0;
                 /* echo back */
                 mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
+            } else if (strncmp("counter ", data, 8)== 0) {
+                char buffer[16];
+                long newval;
+                strncpy(buffer, &data[8], data_len-8);
+                buffer[data_len-8] = '\0';
+                newval = strtol(buffer, NULL, 0);
+                if (ws_conn[wsd].counter == -1)
+                    ws_conn[wsd].counter = newval;
+                else
+                    ws_conn[wsd].counter++;
+                if (ws_conn[wsd].counter != newval)
+                {
+                    fprintf(stderr, "Counter: %ld, received %ld\n", ws_conn[wsd].counter, newval);
+                    ws_conn[wsd].counter = newval;
+                }
+                if (ws_conn[wsd].counter % 3000 == 0)
+                    fprintf(stderr, "Counter: %ld\n", ws_conn[wsd].counter);
             }
+            else
+                fprintf(stderr, "TEXT: %-.*s\n", (int)data_len, data);
             break;
         case WEBSOCKET_OPCODE_BINARY:
             fprintf(stderr, "BINARY...\n");

+ 447 - 0
include/civetweb.h

@@ -1,3 +1,4 @@
+<<<<<<< HEAD
 // Copyright (c) 2004-2012 Sergey Lyubka
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -17,6 +18,28 @@
 // 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.
+=======
+/* Copyright (c) 2004-2013 Sergey Lyubka
+ *
+ * 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.
+ */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 #ifndef CIVETWEB_HEADER_INCLUDED
 #define CIVETWEB_HEADER_INCLUDED
@@ -26,6 +49,7 @@
 
 #ifdef __cplusplus
 extern "C" {
+<<<<<<< HEAD
 #endif // __cplusplus
 
 struct mg_context;     // Handle for the HTTP service itself
@@ -156,11 +180,148 @@ struct mg_callbacks {
 //
 // Return:
 //   web server context, or NULL on error.
+=======
+#endif /* __cplusplus */
+
+struct mg_context;     /* Handle for the HTTP service itself */
+struct mg_connection;  /* Handle for the individual connection */
+
+
+/* This structure contains information about the HTTP request. */
+struct mg_request_info {
+    const char *request_method; /* "GET", "POST", etc */
+    const char *uri;            /* URL-decoded URI */
+    const char *http_version;   /* E.g. "1.0", "1.1" */
+    const char *query_string;   /* URL part after '?', not including '?', or
+                                   NULL */
+    const char *remote_user;    /* Authenticated user, or NULL if no auth
+                                   used */
+    long remote_ip;             /* Client's IP address */
+    int remote_port;            /* Client's port */
+    int is_ssl;                 /* 1 if SSL-ed, 0 if not */
+    void *user_data;            /* User data pointer passed to mg_start() */
+    void *conn_data;            /* Connection-specific user data */
+
+    int num_headers;            /* Number of HTTP headers */
+    struct mg_header {
+        const char *name;       /* HTTP header name */
+        const char *value;      /* HTTP header value */
+    } http_headers[64];         /* Maximum 64 headers */
+};
+
+
+/* This structure needs to be passed to mg_start(), to let civetweb know
+   which callbacks to invoke. For detailed description, see
+   https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md */
+struct mg_callbacks {
+    /* Called when civetweb has received new HTTP request.
+       If callback returns non-zero,
+       callback must process the request by sending valid HTTP headers and
+       body, and civetweb will not do any further processing.
+       If callback returns 0, civetweb processes the request itself. In this
+       case, callback must not send any data to the client. */
+    int  (*begin_request)(struct mg_connection *);
+
+    /* Called when civetweb has finished processing request. */
+    void (*end_request)(const struct mg_connection *, int reply_status_code);
+
+    /* Called when civetweb is about to log a message. If callback returns
+       non-zero, civetweb does not log anything. */
+    int  (*log_message)(const struct mg_connection *, const char *message);
+
+    /* Called when civetweb initializes SSL library. */
+    int  (*init_ssl)(void *ssl_context, void *user_data);
+
+    /* Called when websocket request is received, before websocket handshake.
+       If callback returns 0, civetweb proceeds with handshake, otherwise
+       cinnection is closed immediately. */
+    int (*websocket_connect)(const struct mg_connection *);
+
+    /* Called when websocket handshake is successfully completed, and
+       connection is ready for data exchange. */
+    void (*websocket_ready)(struct mg_connection *);
+
+    /* Called when data frame has been received from the client.
+       Parameters:
+          bits: first byte of the websocket frame, see websocket RFC at
+                http://tools.ietf.org/html/rfc6455, section 5.2
+          data, data_len: payload, with mask (if any) already applied.
+       Return value:
+          non-0: keep this websocket connection opened.
+          0:     close this websocket connection. */
+    int  (*websocket_data)(struct mg_connection *, int bits,
+                           char *data, size_t data_len);
+
+    /* Called when civetweb is closing a connection.  The per-context mutex is
+       locked when this is invoked.  This is primarily useful for noting when
+       a websocket is closing and removing it from any application-maintained
+       list of clients. */
+    void (*connection_close)(struct mg_connection *);
+
+    /* Called when civetweb tries to open a file. Used to intercept file open
+       calls, and serve file data from memory instead.
+       Parameters:
+          path:     Full path to the file to open.
+          data_len: Placeholder for the file size, if file is served from
+                    memory.
+       Return value:
+          NULL: do not serve file from memory, proceed with normal file open.
+          non-NULL: pointer to the file contents in memory. data_len must be
+          initilized with the size of the memory block. */
+    const char * (*open_file)(const struct mg_connection *,
+                              const char *path, size_t *data_len);
+
+    /* Called when civetweb is about to serve Lua server page (.lp file), if
+       Lua support is enabled.
+       Parameters:
+         lua_context: "lua_State *" pointer. */
+    void (*init_lua)(struct mg_connection *, void *lua_context);
+
+    /* Called when civetweb has uploaded a file to a temporary directory as a
+       result of mg_upload() call.
+       Parameters:
+          file_file: full path name to the uploaded file. */
+    void (*upload)(struct mg_connection *, const char *file_name);
+
+    /* Called when civetweb is about to send HTTP error to the client.
+       Implementing this callback allows to create custom error pages.
+       Parameters:
+         status: HTTP error status code. */
+    int  (*http_error)(struct mg_connection *, int status);
+};
+
+/* Start web server.
+
+   Parameters:
+     callbacks: mg_callbacks structure with user-defined callbacks.
+     options: NULL terminated list of option_name, option_value pairs that
+              specify Civetweb configuration parameters.
+
+   Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
+      processing is required for these, signal handlers must be set up
+      after calling mg_start().
+
+
+   Example:
+     const char *options[] = {
+       "document_root", "/var/www",
+       "listening_ports", "80,443s",
+       NULL
+     };
+     struct mg_context *ctx = mg_start(&my_func, NULL, options);
+
+   Refer to https://github.com/sunsetbrew/civetweb/blob/master/docs/UserManual.md
+   for the list of valid option and their possible values.
+
+   Return:
+     web server context, or NULL on error. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 struct mg_context *mg_start(const struct mg_callbacks *callbacks,
                             void *user_data,
                             const char **configuration_options);
 
 
+<<<<<<< HEAD
 // Stop the web server.
 //
 // Must be called last, when an application wants to stop the web server and
@@ -228,12 +389,82 @@ const char **mg_get_valid_option_names(void);
 //
 // Return:
 //   1 on success, 0 on error.
+=======
+/* Stop the web server.
+
+   Must be called last, when an application wants to stop the web server and
+   release all associated resources. This function blocks until all Civetweb
+   threads are stopped. Context pointer becomes invalid. */
+void mg_stop(struct mg_context *);
+
+/* mg_request_handler
+
+   Called when a new request comes in.  This callback is URI based
+   and configured with mg_set_request_handler().
+
+   Parameters:
+      conn: current connection information.
+      cbdata: the callback data configured with mg_set_request_handler().
+   Returns:
+      0: the handler could not handle the request, so fall through.
+      1: the handler processed the request. */
+typedef int (* mg_request_handler)(struct mg_connection *conn, void *cbdata);
+
+/* mg_set_request_handler
+
+   Sets or removes a URI mapping for a request handler.
+
+   URI's are ordered and prefixed URI's are supported. For example,
+   consider two URIs: /a/b and /a
+           /a   matches /a
+           /a/b matches /a/b
+           /a/c matches /a
+
+   Parameters:
+      ctx: server context
+      uri: the URI to configure
+      handler: the callback handler to use when the URI is requested.
+               If NULL, the URI will be removed.
+      cbdata: the callback data to give to the handler when it s requested. */
+void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata);
+
+
+/* Get the value of particular configuration parameter.
+   The value returned is read-only. Civetweb does not allow changing
+   configuration at run time.
+   If given parameter name is not valid, NULL is returned. For valid
+   names, return value is guaranteed to be non-NULL. If parameter is not
+   set, zero-length string is returned. */
+const char *mg_get_option(const struct mg_context *ctx, const char *name);
+
+
+/* Return array of strings that represent valid configuration options.
+   For each option, option name and default value is returned, i.e. the
+   number of entries in the array equals to number_of_options x 2.
+   Array is NULL terminated. */
+const char **mg_get_valid_option_names(void);
+
+
+/* Add, edit or delete the entry in the passwords file.
+
+   This function allows an application to manipulate .htpasswd files on the
+   fly by adding, deleting and changing user records. This is one of the
+   several ways of implementing authentication on the server side. For another,
+   cookie-based way please refer to the examples/chat in the source tree.
+
+   If password is not NULL, entry is added (or modified if already exists).
+   If password is NULL, entry is deleted.
+
+   Return:
+     1 on success, 0 on error. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 int mg_modify_passwords_file(const char *passwords_file_name,
                              const char *domain,
                              const char *user,
                              const char *password);
 
 
+<<<<<<< HEAD
 // Return information associated with the request.
 struct mg_request_info *mg_get_request_info(struct mg_connection *);
 
@@ -267,6 +498,44 @@ void mg_lock(struct mg_connection* conn);
 void mg_unlock(struct mg_connection* conn);
 
 // Opcodes, from http://tools.ietf.org/html/rfc6455
+=======
+/* Return information associated with the request. */
+struct mg_request_info *mg_get_request_info(struct mg_connection *);
+
+
+/* Send data to the client.
+   Return:
+    0   when the connection has been closed
+    -1  on error
+    >0  number of bytes written on success */
+int mg_write(struct mg_connection *, const void *buf, size_t len);
+
+
+/* Send data to a websocket client wrapped in a websocket frame.  Uses mg_lock
+   to ensure that the transmission is not interrupted, i.e., when the
+   application is proactively communicating and responding to a request
+   simultaneously.
+
+   Send data to a websocket client wrapped in a websocket frame.
+   This function is available when civetweb is compiled with -DUSE_WEBSOCKET
+
+   Return:
+    0   when the connection has been closed
+    -1  on error
+    >0  number of bytes written on success */
+int mg_websocket_write(struct mg_connection* conn, int opcode,
+                       const char *data, size_t data_len);
+
+/* Blocks until unique access is obtained to this connection. Intended for use
+   with websockets only.
+   Invoke this before mg_write or mg_printf when communicating with a
+   websocket if your code has server-initiated communication as well as
+   communication in direct response to a message. */
+void mg_lock(struct mg_connection* conn);
+void mg_unlock(struct mg_connection* conn);
+
+/* Opcodes, from http://tools.ietf.org/html/rfc6455 */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 enum {
     WEBSOCKET_OPCODE_CONTINUATION = 0x0,
     WEBSOCKET_OPCODE_TEXT = 0x1,
@@ -277,7 +546,11 @@ enum {
 };
 
 
+<<<<<<< HEAD
 // Macros for enabling compiler-specific checks for printf-like arguments.
+=======
+/* Macros for enabling compiler-specific checks for printf-like arguments. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 #undef PRINTF_FORMAT_STRING
 #if defined(_MSC_VER) && _MSC_VER >= 1400
 #include <sal.h>
@@ -296,13 +569,20 @@ enum {
 #define PRINTF_ARGS(x, y)
 #endif
 
+<<<<<<< HEAD
 // Send data to the client using printf() semantics.
 //
 // Works exactly like mg_write(), but allows to do message formatting.
+=======
+/* Send data to the client using printf() semantics.
+
+   Works exactly like mg_write(), but allows to do message formatting. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 int mg_printf(struct mg_connection *,
               PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
 
 
+<<<<<<< HEAD
 // Send contents of the entire file together with HTTP headers.
 void mg_send_file(struct mg_connection *conn, const char *path);
 
@@ -383,10 +663,94 @@ int mg_get_var2(const char *data, size_t data_len,
 //          parameter is not found).
 //      -2 (destination buffer is NULL, zero length or too small to hold the
 //          value).
+=======
+/* Send contents of the entire file together with HTTP headers. */
+void mg_send_file(struct mg_connection *conn, const char *path);
+
+
+/* Read data from the remote end, return number of bytes read.
+   Return:
+     0     connection has been closed by peer. No more data could be read.
+     < 0   read error. No more data could be read from the connection.
+     > 0   number of bytes read into the buffer. */
+int mg_read(struct mg_connection *, void *buf, size_t len);
+
+
+/* Get the value of particular HTTP header.
+
+   This is a helper function. It traverses request_info->http_headers array,
+   and if the header is present in the array, returns its value. If it is
+   not present, NULL is returned. */
+const char *mg_get_header(const struct mg_connection *, const char *name);
+
+
+/* Get a value of particular form variable.
+
+   Parameters:
+     data: pointer to form-uri-encoded buffer. This could be either POST data,
+           or request_info.query_string.
+     data_len: length of the encoded data.
+     var_name: variable name to decode from the buffer
+     dst: destination buffer for the decoded variable
+     dst_len: length of the destination buffer
+
+   Return:
+     On success, length of the decoded variable.
+     On error:
+        -1 (variable not found).
+        -2 (destination buffer is NULL, zero length or too small to hold the
+            decoded variable).
+
+   Destination buffer is guaranteed to be '\0' - terminated if it is not
+   NULL or zero length. */
+int mg_get_var(const char *data, size_t data_len,
+               const char *var_name, char *dst, size_t dst_len);
+
+/* Get a value of particular form variable.
+
+   Parameters:
+     data: pointer to form-uri-encoded buffer. This could be either POST data,
+           or request_info.query_string.
+     data_len: length of the encoded data.
+     var_name: variable name to decode from the buffer
+     dst: destination buffer for the decoded variable
+     dst_len: length of the destination buffer
+     occurrence: which occurrence of the variable, 0 is the first, 1 the
+                 second...
+                this makes it possible to parse a query like
+                b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1
+
+   Return:
+     On success, length of the decoded variable.
+     On error:
+        -1 (variable not found).
+        -2 (destination buffer is NULL, zero length or too small to hold the
+            decoded variable).
+
+   Destination buffer is guaranteed to be '\0' - terminated if it is not
+   NULL or zero length. */
+int mg_get_var2(const char *data, size_t data_len,
+                const char *var_name, char *dst, size_t dst_len, size_t occurrence);
+
+/* Fetch value of certain cookie variable into the destination buffer.
+
+   Destination buffer is guaranteed to be '\0' - terminated. In case of
+   failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
+   parameter. This function returns only first occurrence.
+
+   Return:
+     On success, value length.
+     On error:
+        -1 (either "Cookie:" header is not present at all or the requested
+            parameter is not found).
+        -2 (destination buffer is NULL, zero length or too small to hold the
+            value). */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 int mg_get_cookie(const char *cookie, const char *var_name,
                   char *buf, size_t buf_len);
 
 
+<<<<<<< HEAD
 // Download data from the remote web server.
 //   host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
 //   port: port number, e.g. 80.
@@ -401,12 +765,30 @@ int mg_get_cookie(const char *cookie, const char *var_name,
 //   struct mg_connection *conn;
 //   conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
 //                      "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
+=======
+/* Download data from the remote web server.
+     host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
+     port: port number, e.g. 80.
+     use_ssl: wether to use SSL connection.
+     error_buffer, error_buffer_size: error message placeholder.
+     request_fmt,...: HTTP request.
+   Return:
+     On success, valid pointer to the new connection, suitable for mg_read().
+     On error, NULL. error_buffer contains error message.
+   Example:
+     char ebuf[100];
+     struct mg_connection *conn;
+     conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
+                        "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
+ */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 struct mg_connection *mg_download(const char *host, int port, int use_ssl,
                                   char *error_buffer, size_t error_buffer_size,
                                   PRINTF_FORMAT_STRING(const char *request_fmt),
                                   ...) PRINTF_ARGS(6, 7);
 
 
+<<<<<<< HEAD
 // Close the connection opened by mg_download().
 void mg_close_connection(struct mg_connection *conn);
 
@@ -419,10 +801,25 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir);
 
 // Convenience function -- create detached thread.
 // Return: 0 on success, non-0 on error.
+=======
+/* Close the connection opened by mg_download(). */
+void mg_close_connection(struct mg_connection *conn);
+
+
+/* File upload functionality. Each uploaded file gets saved into a temporary
+   file and MG_UPLOAD event is sent.
+   Return number of uploaded files. */
+int mg_upload(struct mg_connection *conn, const char *destination_dir);
+
+
+/* Convenience function -- create detached thread.
+   Return: 0 on success, non-0 on error. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 typedef void * (*mg_thread_func_t)(void *);
 int mg_start_thread(mg_thread_func_t f, void *p);
 
 
+<<<<<<< HEAD
 // Return builtin mime type for the given file name.
 // For unrecognized extensions, "text/plain" is returned.
 const char *mg_get_builtin_mime_type(const char *file_name);
@@ -465,10 +862,60 @@ void mg_cry(struct mg_connection *conn,
             PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
 
 // utility method to compare two buffers, case incensitive.
+=======
+/* Return builtin mime type for the given file name.
+   For unrecognized extensions, "text/plain" is returned. */
+const char *mg_get_builtin_mime_type(const char *file_name);
+
+
+/* Return Civetweb version. */
+const char *mg_version(void);
+
+/* URL-decode input buffer into destination buffer.
+   0-terminate the destination buffer.
+   form-url-encoded data differs from URI encoding in a way that it
+   uses '+' as character for space, see RFC 1866 section 8.2.1
+   http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
+   Return: length of the decoded data, or -1 if dst buffer is too small. */
+int mg_url_decode(const char *src, int src_len, char *dst,
+                  int dst_len, int is_form_url_encoded);
+
+/* URL-encode input buffer into destination buffer.
+   returns the length of the resulting buffer or -1
+   is the buffer is too small. */
+int mg_url_encode(const char *src, char *dst, size_t dst_len);
+
+/* MD5 hash given strings.
+   Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
+   ASCIIz strings. When function returns, buf will contain human-readable
+   MD5 hash. Example:
+     char buf[33];
+     mg_md5(buf, "aa", "bb", NULL); */
+char *mg_md5(char buf[33], ...);
+
+
+/* Print error message to the opened error log stream.
+   This utilizes the provided logging configuration.
+     conn: connection
+     fmt: format string without the line return
+     ...: variable argument list
+   Example:
+     mg_cry(conn,"i like %s", "logging"); */
+void mg_cry(struct mg_connection *conn,
+            PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
+
+/* utility method to compare two buffers, case incensitive. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 int mg_strncasecmp(const char *s1, const char *s2, size_t len);
 
 #ifdef __cplusplus
 }
+<<<<<<< HEAD
 #endif // __cplusplus
 
 #endif // CIVETWEB_HEADER_INCLUDED
+=======
+#endif /* __cplusplus */
+
+#endif /* CIVETWEB_HEADER_INCLUDED */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3

+ 13 - 0
resources/Makefile.in-lua

@@ -48,7 +48,20 @@ SQLITE_SOURCES = $(addprefix $(SQLITE_DIR)/, $(SQLITE_SOURCE_FILES))
 SQLITE_OBJECTS = $(SQLITE_SOURCES:.c=.o)
 SQLITE_CFLAGS = -I$(SQLITE_DIR) -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
 
+<<<<<<< HEAD
 OBJECTS += $(LUA_OBJECTS) $(SQLITE_OBJECTS)
 CFLAGS += $(LUA_CFLAGS) $(SQLITE_CFLAGS) -DUSE_LUA -DUSE_LUA_SQLITE3
 SOURCE_DIRS = $(LUA_DIR) $(SQLITE_DIR) 
+=======
+LFS_DIR = src/third_party
+LFS_SOURCE_FILES = lfs.c
+LFS_SOURCES = $(addprefix $(LFS_DIR)/, $(LFS_SOURCE_FILES))
+LFS_OBJECTS = $(LFS_SOURCES:.c=.o)
+LFS_CFLAGS = -I$(LFS_DIR)
+
+
+OBJECTS += $(LUA_OBJECTS) $(SQLITE_OBJECTS) $(LFS_OBJECTS)
+CFLAGS += $(LUA_CFLAGS) $(SQLITE_CFLAGS) $(LFS_CFLAGS) -DUSE_LUA -DUSE_LUA_SQLITE3 -DUSE_LUA_FILE_SYSTEM
+SOURCE_DIRS = $(LUA_DIR) $(SQLITE_DIR) %(LFS_DIR)
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 436 - 0
src/civetweb.c


+ 239 - 0
src/main.c

@@ -1,3 +1,4 @@
+<<<<<<< HEAD
 // Copyright (c) 2004-2013 Sergey Lyubka
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,6 +23,33 @@
 #define _CRT_SECURE_NO_WARNINGS  // Disable deprecation warning in VS2005
 #else
 #define _XOPEN_SOURCE 600  // For PATH_MAX on linux
+=======
+/* Copyright (c) 2004-2013 Sergey Lyubka
+ *
+ * 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.
+*/
+
+#if defined(_WIN32)
+#define _CRT_SECURE_NO_WARNINGS  /* Disable deprecation warning in VS2005 */
+#else
+#define _XOPEN_SOURCE 600  /* For PATH_MAX on linux */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 #endif
 
 #ifndef IGNORE_UNUSED_RESULT
@@ -69,21 +97,36 @@ extern char *_getcwd(char *buf, size_t size);
 #define DIRSEP '/'
 #define WINCDECL
 #define abs_path(rel, abs, abs_size) realpath((rel), (abs))
+<<<<<<< HEAD
 #endif // _WIN32
+=======
+#endif /* _WIN32 */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 #define MAX_OPTIONS 100
 #define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
 
 static int exit_flag;
+<<<<<<< HEAD
 static char server_name[40];        // Set by init_server_name()
 static char config_file[PATH_MAX] = "";  // Set by process_command_line_arguments()
 static struct mg_context *ctx;      // Set by start_civetweb()
+=======
+static char server_name[40];        /* Set by init_server_name() */
+static char config_file[PATH_MAX] = ""; /* Set by
+                                           process_command_line_arguments() */
+static struct mg_context *ctx;      /* Set by start_civetweb() */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 #if !defined(CONFIG_FILE)
 #define CONFIG_FILE "civetweb.conf"
 #endif /* !CONFIG_FILE */
 
+<<<<<<< HEAD
 // backup config file
+=======
+/* backup config file */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 #if !defined(CONFIG_FILE2) && defined(LINUX)
 #define CONFIG_FILE2 "/usr/local/etc/civetweb.conf"
 #endif
@@ -167,7 +210,11 @@ static void create_config_file(const char *path)
     FILE *fp;
     int i;
 
+<<<<<<< HEAD
     // Create config file if it is not present yet
+=======
+    /* Create config file if it is not present yet */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if ((fp = fopen(path, "r")) != NULL) {
         fclose(fp);
     } else if ((fp = fopen(path, "a+")) != NULL) {
@@ -222,12 +269,20 @@ static void process_command_line_arguments(char *argv[], char **options)
     FILE *fp = NULL;
     size_t i, cmd_line_opts_start = 1, line_no = 0;
 
+<<<<<<< HEAD
     // Should we use a config file ?
+=======
+    /* Should we use a config file ? */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if (argv[1] != NULL && argv[1][0] != '-') {
         snprintf(config_file, sizeof(config_file), "%s", argv[1]);
         cmd_line_opts_start = 2;
     } else if ((p = strrchr(argv[0], DIRSEP)) == NULL) {
+<<<<<<< HEAD
         // No command line flags specified. Look where binary lives
+=======
+        /* No command line flags specified. Look where binary lives */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         snprintf(config_file, sizeof(config_file)-1, "%s", CONFIG_FILE);
         config_file[sizeof(config_file)-1] = 0;
     } else {
@@ -238,13 +293,21 @@ static void process_command_line_arguments(char *argv[], char **options)
 
     fp = fopen(config_file, "r");
 
+<<<<<<< HEAD
     // If config file was set in command line and open failed, die
+=======
+    /* If config file was set in command line and open failed, die */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if (cmd_line_opts_start == 2 && fp == NULL) {
         die("Cannot open config file %s: %s", config_file, strerror(errno));
     }
 
 #ifdef CONFIG_FILE2
+<<<<<<< HEAD
     // try alternate config file
+=======
+    /* try alternate config file */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if (fp == NULL) {
         fp = fopen(CONFIG_FILE2, "r");
         if (fp != NULL) {
@@ -253,6 +316,7 @@ static void process_command_line_arguments(char *argv[], char **options)
     }
 #endif
 
+<<<<<<< HEAD
     // Load config file settings first
     if (fp != NULL) {
         fprintf(stderr, "Loading config file %s\n", config_file);
@@ -270,6 +334,32 @@ static void process_command_line_arguments(char *argv[], char **options)
             if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
                 printf("%s: line %d is invalid, ignoring it:\n %s",
                        config_file, (int) line_no, line);
+=======
+    /* Load config file settings first */
+    if (fp != NULL) {
+        fprintf(stderr, "Loading config file %s\n", config_file);
+
+        /* Loop over the lines in config file */
+        while (fgets(line, sizeof(line), fp) != NULL) {
+
+            if (!line_no && !memcmp(line,"\xEF\xBB\xBF",3)) {
+                /* strip UTF-8 BOM */
+                p = line+3;
+            } else {
+                p = line;
+            }
+            line_no++;
+
+            /* Ignore empty lines and comments */
+            for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++;
+            if (p[i] == '#' || p[i] == '\0') {
+                continue;
+            }
+
+            if (sscanf(p, "%s %[^\r\n#]", opt, val) != 2) {
+                printf("%s: line %d is invalid, ignoring it:\n %s",
+                       config_file, (int) line_no, p);
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
             } else {
                 set_option(options, opt, val);
             }
@@ -278,12 +368,21 @@ static void process_command_line_arguments(char *argv[], char **options)
         (void) fclose(fp);
     }
 
+<<<<<<< HEAD
     // If we're under MacOS and started by launchd, then the second
     // argument is process serial number, -psn_.....
     // In this case, don't process arguments at all.
     if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) {
         // Handle command line flags.
         // They override config file and default settings.
+=======
+    /* If we're under MacOS and started by launchd, then the second
+       argument is process serial number, -psn_.....
+       In this case, don't process arguments at all. */
+    if (argv[1] == NULL || memcmp(argv[1], "-psn_", 5) != 0) {
+        /* Handle command line flags.
+           They override config file and default settings. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
             if (argv[i][0] != '-' || argv[i + 1] == NULL) {
                 show_usage_and_exit();
@@ -310,8 +409,14 @@ static int is_path_absolute(const char *path)
 {
 #ifdef _WIN32
     return path != NULL &&
+<<<<<<< HEAD
            ((path[0] == '\\' && path[1] == '\\') ||  // UNC path, e.g. \\server\dir
             (isalpha(path[0]) && path[1] == ':' && path[2] == '\\'));  // E.g. X:\dir
+=======
+           ((path[0] == '\\' && path[1] == '\\') ||  /* UNC path, e.g.
+                                                        \\server\dir */
+            (isalpha(path[0]) && path[1] == ':' && path[2] == '\\'));  /* E.g. X:\dir */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 #else
     return path != NULL && path[0] == '/';
 #endif
@@ -334,6 +439,23 @@ static void verify_existence(char **options, const char *option_name,
     struct stat st;
     const char *path = get_option(options, option_name);
 
+<<<<<<< HEAD
+=======
+#ifdef _WIN32
+    wchar_t wbuf[1024];
+    char mbbuf[1024];
+    int len;
+
+    if (path) {
+        memset(wbuf, 0, sizeof(wbuf));
+        memset(mbbuf, 0, sizeof(mbbuf));
+        len = MultiByteToWideChar(CP_UTF8, 0, path, -1, wbuf, (int) sizeof(wbuf)/sizeof(wbuf[0])-1);
+        wcstombs(mbbuf, wbuf, sizeof(mbbuf)-1);
+        path = mbbuf;
+    }
+#endif
+
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if (path != NULL && (stat(path, &st) != 0 ||
                          ((S_ISDIR(st.st_mode) ? 1 : 0) != must_be_dir))) {
         die("Invalid path for %s: [%s]: (%s). Make sure that path is either "
@@ -348,6 +470,7 @@ static void set_absolute_path(char *options[], const char *option_name,
     char path[PATH_MAX] = "", abs[PATH_MAX] = "", *option_value;
     const char *p;
 
+<<<<<<< HEAD
     // Check whether option is already set
     option_value = get_option(options, option_name);
 
@@ -357,6 +480,17 @@ static void set_absolute_path(char *options[], const char *option_name,
         // Not absolute. Use the directory where civetweb executable lives
         // be the relative directory for everything.
         // Extract civetweb executable directory into path.
+=======
+    /* Check whether option is already set */
+    option_value = get_option(options, option_name);
+
+    /* If option is already set and it is an absolute path,
+       leave it as it is -- it's already absolute. */
+    if (option_value != NULL && !is_path_absolute(option_value)) {
+        /* Not absolute. Use the directory where civetweb executable lives
+           be the relative directory for everything.
+           Extract civetweb executable directory into path. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         if ((p = strrchr(path_to_civetweb_exe, DIRSEP)) == NULL) {
             IGNORE_UNUSED_RESULT(getcwd(path, sizeof(path)));
         } else {
@@ -368,7 +502,11 @@ static void set_absolute_path(char *options[], const char *option_name,
         strncat(path, "/", sizeof(path) - 1);
         strncat(path, option_value, sizeof(path) - 1);
 
+<<<<<<< HEAD
         // Absolutize the path, and set the option
+=======
+        /* Absolutize the path, and set the option */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         IGNORE_UNUSED_RESULT(abs_path(path, abs, sizeof(abs)));
         set_option(options, option_name, abs);
     }
@@ -380,7 +518,11 @@ static void start_civetweb(int argc, char *argv[])
     char *options[MAX_OPTIONS];
     int i;
 
+<<<<<<< HEAD
     // Edit passwords file if -A option is specified
+=======
+    /* Edit passwords file if -A option is specified */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if (argc > 1 && !strcmp(argv[1], "-A")) {
         if (argc != 6) {
             show_usage_and_exit();
@@ -389,7 +531,11 @@ static void start_civetweb(int argc, char *argv[])
              EXIT_SUCCESS : EXIT_FAILURE);
     }
 
+<<<<<<< HEAD
     // Show usage if -h or --help options are specified
+=======
+    /* Show usage if -h or --help options are specified */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
         show_usage_and_exit();
     }
@@ -397,10 +543,17 @@ static void start_civetweb(int argc, char *argv[])
     options[0] = NULL;
     set_option(options, "document_root", ".");
 
+<<<<<<< HEAD
     // Update config based on command line arguments
     process_command_line_arguments(argv, options);
 
     // Make sure we have absolute paths for files and directories
+=======
+    /* Update config based on command line arguments */
+    process_command_line_arguments(argv, options);
+
+    /* Make sure we have absolute paths for files and directories */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     set_absolute_path(options, "document_root", argv[0]);
     set_absolute_path(options, "put_delete_auth_file", argv[0]);
     set_absolute_path(options, "cgi_interpreter", argv[0]);
@@ -409,16 +562,28 @@ static void start_civetweb(int argc, char *argv[])
     set_absolute_path(options, "global_auth_file", argv[0]);
     set_absolute_path(options, "ssl_certificate", argv[0]);
 
+<<<<<<< HEAD
     // Make extra verification for certain options
+=======
+    /* Make extra verification for certain options */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     verify_existence(options, "document_root", 1);
     verify_existence(options, "cgi_interpreter", 0);
     verify_existence(options, "ssl_certificate", 0);
 
+<<<<<<< HEAD
     // Setup signal handler: quit on Ctrl-C
     signal(SIGTERM, signal_handler);
     signal(SIGINT, signal_handler);
 
     // Start Civetweb
+=======
+    /* Setup signal handler: quit on Ctrl-C */
+    signal(SIGTERM, signal_handler);
+    signal(SIGINT, signal_handler);
+
+    /* Start Civetweb */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     memset(&callbacks, 0, sizeof(callbacks));
     callbacks.log_message = &log_message;
     ctx = mg_start(&callbacks, NULL, (const char **) options);
@@ -437,6 +602,7 @@ enum {
     ID_REMOVE_SERVICE, ID_STATIC, ID_GROUP, ID_SAVE, ID_RESET_DEFAULTS,
     ID_STATUS, ID_CONNECT,
 
+<<<<<<< HEAD
     // All dynamically created text boxes for options have IDs starting from
     // ID_CONTROLS, incremented by one.
     ID_CONTROLS = 200,
@@ -444,6 +610,15 @@ enum {
     // Text boxes for files have "..." buttons to open file browser. These
     // buttons have IDs that are ID_FILE_BUTTONS_DELTA higher than associated
     // text box ID.
+=======
+    /* All dynamically created text boxes for options have IDs starting from
+       ID_CONTROLS, incremented by one. */
+    ID_CONTROLS = 200,
+
+    /* Text boxes for files have "..." buttons to open file browser. These
+       buttons have IDs that are ID_FILE_BUTTONS_DELTA higher than associated
+       text box ID. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     ID_FILE_BUTTONS_DELTA = 1000
 };
 static HICON hIcon;
@@ -544,7 +719,11 @@ static void save_config(HWND hDlg, FILE *fp)
             GetDlgItemText(hDlg, id, value, sizeof(value));
         }
         default_value = options[i * 2 + 1] == NULL ? "" : options[i * 2 + 1];
+<<<<<<< HEAD
         // If value is the same as default, skip it
+=======
+        /* If value is the same as default, skip it */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         if (strcmp(value, default_value) != 0) {
             fprintf(fp, "%s %s\n", name, value);
         }
@@ -694,7 +873,11 @@ static void show_settings_dialog()
     static int guard;
 
     static struct {
+<<<<<<< HEAD
         DLGTEMPLATE template; // 18 bytes
+=======
+        DLGTEMPLATE template; /* 18 bytes */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         WORD menu, class;
         wchar_t caption[1];
         WORD fontsiz;
@@ -775,7 +958,11 @@ static int manage_service(int action)
     static const char *service_name = "Civetweb";
     SC_HANDLE hSCM = NULL, hService = NULL;
     SERVICE_DESCRIPTION descr = {server_name};
+<<<<<<< HEAD
     char path[PATH_MAX + 20] = "";  // Path to executable plus magic argument
+=======
+    char path[PATH_MAX + 20] = "";/* Path to executable plus magic argument */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     int success = 1;
 
     if ((hSCM = OpenSCManager(NULL, NULL, action == ID_INSTALL_SERVICE ?
@@ -825,7 +1012,11 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
     char buf[200], *service_argv[] = {__argv[0], NULL};
     POINT pt;
     HMENU hMenu;
+<<<<<<< HEAD
     static UINT s_uTaskbarRestart; // for taskbar creation
+=======
+    static UINT s_uTaskbarRestart; /* for taskbar creation */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
     switch (msg) {
     case WM_CREATE:
@@ -894,7 +1085,11 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
         mg_stop(ctx);
         Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
         PostQuitMessage(0);
+<<<<<<< HEAD
         return 0;  // We've just sent our own quit message, with proper hwnd.
+=======
+        return 0;/* We've just sent our own quit message, with proper hwnd. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     default:
         if (msg==s_uTaskbarRestart)
             Shell_NotifyIcon(NIM_ADD, &TrayIcon);
@@ -936,7 +1131,11 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show)
         DispatchMessage(&msg);
     }
 
+<<<<<<< HEAD
     // Return the WM_QUIT value.
+=======
+    /* Return the WM_QUIT value. */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     return (int) msg.wParam;
 }
 #elif defined(USE_COCOA)
@@ -973,15 +1172,24 @@ int main(int argc, char *argv[])
     [NSAutoreleasePool new];
     [NSApplication sharedApplication];
 
+<<<<<<< HEAD
     // Add delegate to process menu item actions
     Civetweb *myDelegate = [[Civetweb alloc] autorelease];
 [NSApp setDelegate: myDelegate];
 
     // Run this app as agent
+=======
+    /* Add delegate to process menu item actions */
+    Civetweb *myDelegate = [[Civetweb alloc] autorelease];
+[NSApp setDelegate: myDelegate];
+
+    /* Run this app as agent */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     ProcessSerialNumber psn = { 0, kCurrentProcess };
     TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
     SetFrontProcess(&psn);
 
+<<<<<<< HEAD
     // Add status bar menu
     id menu = [[NSMenu new] autorelease];
 
@@ -992,31 +1200,62 @@ int main(int argc, char *argv[])
                 action:@selector(noexist) keyEquivalent:@""] autorelease]];
 
     // Add configuration menu item
+=======
+    /* Add status bar menu */
+    id menu = [[NSMenu new] autorelease];
+
+    /* Add version menu item */
+[menu addItem:[[[NSMenuItem alloc]
+                    /*initWithTitle:[NSString stringWithFormat:@"%s", server_name]*/
+                initWithTitle:[NSString stringWithUTF8String:server_name]
+                action:@selector(noexist) keyEquivalent:@""] autorelease]];
+
+    /* Add configuration menu item */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 [menu addItem:[[[NSMenuItem alloc]
                 initWithTitle:@"Edit configuration"
                 action:@selector(editConfig) keyEquivalent:@""] autorelease]];
 
+<<<<<<< HEAD
     // Add connect menu item
+=======
+    /* Add connect menu item */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 [menu addItem:[[[NSMenuItem alloc]
                 initWithTitle:@"Open web root in a browser"
                 action:@selector(openBrowser) keyEquivalent:@""] autorelease]];
 
+<<<<<<< HEAD
     // Separator
 [menu addItem:[NSMenuItem separatorItem]];
 
     // Add quit menu item
+=======
+    /* Separator */
+[menu addItem:[NSMenuItem separatorItem]];
+
+    /* Add quit menu item */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 [menu addItem:[[[NSMenuItem alloc]
                 initWithTitle:@"Quit"
                 action:@selector(shutDown) keyEquivalent:@"q"] autorelease]];
 
+<<<<<<< HEAD
     // Attach menu to the status bar
+=======
+    /* Attach menu to the status bar */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     id item = [[[NSStatusBar systemStatusBar]
             statusItemWithLength:NSVariableStatusItemLength] retain];
 [item setHighlightMode:YES];
 [item setImage:[NSImage imageNamed:@"civetweb_22x22.png"]];
 [item setMenu:menu];
 
+<<<<<<< HEAD
     // Run the app
+=======
+    /* Run the app */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 [NSApp activateIgnoringOtherApps:YES];
     [NSApp run];
 

+ 20 - 0
src/mod_lua.inl

@@ -161,10 +161,17 @@ static int lsp(struct mg_connection *conn, const char *path,
 
     for (i = 0; i < len; i++) {
         if (p[i] == '\n') lines++;
+<<<<<<< HEAD
         if (p[i] == '<' && p[i + 1] == '?') {
             for (j = i + 1; j < len ; j++) {
                 if (p[j] == '\n') lualines++;
                 if (p[j] == '?' && p[j + 1] == '>') {
+=======
+        if ((i + 1) < len && p[i] == '<' && p[i + 1] == '?') {
+            for (j = i + 1; j < len ; j++) {
+                if (p[j] == '\n') lualines++;
+                if ((j + 1) < len && p[j] == '?' && p[j + 1] == '>') {
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
                     mg_write(conn, p + pos, i - pos);
 
                     snprintf(chunkname, sizeof(chunkname), "@%s+%i", path, lines);
@@ -271,6 +278,15 @@ static void prepare_lua_environment(struct mg_connection *conn, lua_State *L)
         luaopen_lsqlite3(L);
     }
 #endif
+<<<<<<< HEAD
+=======
+#ifdef USE_LUA_FILE_SYSTEM
+    {
+        extern int luaopen_lfs(lua_State *);
+        luaopen_lfs(L);
+    }
+#endif
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
     luaL_newmetatable(L, LUASOCKET);
     lua_pushliteral(L, "__index");
@@ -414,5 +430,9 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path,
     if (L != NULL && ls == NULL) lua_close(L);
     if (p != NULL) munmap(p, filep->size);
     mg_fclose(filep);
+<<<<<<< HEAD
+=======
+    conn->must_close=1;
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     return error;
 }

+ 895 - 0
src/third_party/lfs.c

@@ -0,0 +1,895 @@
+/*
+** LuaFileSystem
+** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
+**
+** File system manipulation library.
+** This library offers these functions:
+**   lfs.attributes (filepath [, attributename])
+**   lfs.chdir (path)
+**   lfs.currentdir ()
+**   lfs.dir (path)
+**   lfs.lock (fh, mode)
+**   lfs.lock_dir (path)
+**   lfs.mkdir (path)
+**   lfs.rmdir (path)
+**   lfs.setmode (filepath, mode)
+**   lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts
+**   lfs.touch (filepath [, atime [, mtime]])
+**   lfs.unlock (fh)
+**
+** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
+*/
+
+#ifdef _MSC_VER
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS /* disable Visual Studio compiler warnings for using standard C functions */
+#endif
+#endif
+
+#ifndef _WIN32
+#ifndef _AIX
+#define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
+#else
+#define _LARGE_FILES 1 /* AIX */
+#endif
+#endif
+
+#define _LARGEFILE64_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#include <windows.h>
+#include <io.h>
+#include <sys/locking.h>
+#ifdef __BORLANDC__
+ #include <utime.h>
+#else
+ #include <sys/utime.h>
+#endif
+#include <fcntl.h>
+#else
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "lfs.h"
+
+#define LFS_VERSION "1.6.2"
+#define LFS_LIBNAME "lfs"
+
+#if LUA_VERSION_NUM < 502
+#  define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
+#endif
+
+/* Define 'strerror' for systems that do not implement it */
+#ifdef NO_STRERROR
+#define strerror(_)     "System unable to describe the error"
+#endif
+
+/* Define 'getcwd' for systems that do not implement it */
+#ifdef NO_GETCWD
+#define getcwd(p,s)     NULL
+#define getcwd_error    "Function 'getcwd' not provided by system"
+#else
+#define getcwd_error    strerror(errno)
+  #ifdef _WIN32
+	 /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
+    #define LFS_MAXPATHLEN MAX_PATH
+  #else
+	/* For MAXPATHLEN: */
+    #include <sys/param.h>
+    #define LFS_MAXPATHLEN MAXPATHLEN
+  #endif
+#endif
+
+#define DIR_METATABLE "directory metatable"
+typedef struct dir_data {
+        int  closed;
+#ifdef _WIN32
+        long hFile;
+        char pattern[MAX_PATH+1];
+#else
+        DIR *dir;
+#endif
+} dir_data;
+
+#define LOCK_METATABLE "lock metatable"
+
+#ifdef _WIN32
+ #ifdef __BORLANDC__
+  #define lfs_setmode(L,file,m)   ((void)L, setmode(_fileno(file), m))
+  #define STAT_STRUCT struct stati64
+ #else
+  #define lfs_setmode(L,file,m)   ((void)L, _setmode(_fileno(file), m))
+  #define STAT_STRUCT struct _stati64
+ #endif
+#define STAT_FUNC _stati64
+#define LSTAT_FUNC STAT_FUNC
+#else
+#define _O_TEXT               0
+#define _O_BINARY             0
+#define lfs_setmode(L,file,m)   ((void)L, (void)file, (void)m, 0)
+#define STAT_STRUCT struct stat
+#define STAT_FUNC stat
+#define LSTAT_FUNC lstat
+#endif
+
+/*
+** Utility functions
+*/
+static int pusherror(lua_State *L, const char *info)
+{
+        lua_pushnil(L);
+        if (info==NULL)
+                lua_pushstring(L, strerror(errno));
+        else
+                lua_pushfstring(L, "%s: %s", info, strerror(errno));
+        lua_pushinteger(L, errno);
+        return 3;
+}
+
+static int pushresult(lua_State *L, int i, const char *info)
+{
+        if (i==-1)
+                return pusherror(L, info);
+        lua_pushinteger(L, i);
+        return 1;
+}
+
+
+/*
+** This function changes the working (current) directory
+*/
+static int change_dir (lua_State *L) {
+        const char *path = luaL_checkstring(L, 1);
+        if (chdir(path)) {
+                lua_pushnil (L);
+                lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
+                                path, chdir_error);
+                return 2;
+        } else {
+                lua_pushboolean (L, 1);
+                return 1;
+        }
+}
+
+/*
+** This function returns the current directory
+** If unable to get the current directory, it returns nil
+**  and a string describing the error
+*/
+static int get_dir (lua_State *L) {
+  char *path;
+  /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
+  char buf[LFS_MAXPATHLEN];
+  if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
+    lua_pushnil(L);
+    lua_pushstring(L, getcwd_error);
+    return 2;
+  }
+  else {
+    lua_pushstring(L, path);
+    return 1;
+  }
+}
+
+/*
+** Check if the given element on the stack is a file and returns it.
+*/
+static FILE *check_file (lua_State *L, int idx, const char *funcname) {
+        FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
+        if (fh == NULL) {
+                luaL_error (L, "%s: not a file", funcname);
+                return 0;
+        } else if (*fh == NULL) {
+                luaL_error (L, "%s: closed file", funcname);
+                return 0;
+        } else
+                return *fh;
+}
+
+
+/*
+**
+*/
+static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
+        int code;
+#ifdef _WIN32
+        /* lkmode valid values are:
+           LK_LOCK    Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.
+           LK_NBLCK   Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
+           LK_NBRLCK  Same as _LK_NBLCK.
+           LK_RLCK    Same as _LK_LOCK.
+           LK_UNLCK   Unlocks the specified bytes, which must have been previously locked.
+
+           Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
+
+           http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
+        */
+        int lkmode;
+        switch (*mode) {
+                case 'r': lkmode = LK_NBLCK; break;
+                case 'w': lkmode = LK_NBLCK; break;
+                case 'u': lkmode = LK_UNLCK; break;
+                default : return luaL_error (L, "%s: invalid mode", funcname);
+        }
+        if (!len) {
+                fseek (fh, 0L, SEEK_END);
+                len = ftell (fh);
+        }
+        fseek (fh, start, SEEK_SET);
+#ifdef __BORLANDC__
+        code = locking (fileno(fh), lkmode, len);
+#else
+        code = _locking (fileno(fh), lkmode, len);
+#endif
+#else
+        struct flock f;
+        switch (*mode) {
+                case 'w': f.l_type = F_WRLCK; break;
+                case 'r': f.l_type = F_RDLCK; break;
+                case 'u': f.l_type = F_UNLCK; break;
+                default : return luaL_error (L, "%s: invalid mode", funcname);
+        }
+        f.l_whence = SEEK_SET;
+        f.l_start = (off_t)start;
+        f.l_len = (off_t)len;
+        code = fcntl (fileno(fh), F_SETLK, &f);
+#endif
+        return (code != -1);
+}
+
+#ifdef _WIN32
+typedef struct lfs_Lock {
+  HANDLE fd;
+} lfs_Lock;
+static int lfs_lock_dir(lua_State *L) {
+  size_t pathl; HANDLE fd;
+  lfs_Lock *lock;
+  char *ln;
+  const char *lockfile = "/lockfile.lfs";
+  const char *path = luaL_checklstring(L, 1, &pathl);
+  ln = (char*)malloc(pathl + strlen(lockfile) + 1);
+  if(!ln) {
+    lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
+  }
+  strcpy(ln, path); strcat(ln, lockfile);
+  /* Use "CreateFileA" to use the Multi-Byte-Character version, even if the rest of the project uses the Unicode (UTF16) version */
+  if((fd = CreateFileA(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
+                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
+        int en = GetLastError();
+        free(ln); lua_pushnil(L);
+        if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
+                lua_pushstring(L, "File exists");
+        else
+                lua_pushstring(L, strerror(en));
+        return 2;
+  }
+  free(ln);
+  lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
+  lock->fd = fd;
+  luaL_getmetatable (L, LOCK_METATABLE);
+  lua_setmetatable (L, -2);
+  return 1;
+}
+static int lfs_unlock_dir(lua_State *L) {
+  lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE);
+  CloseHandle(lock->fd);
+  return 0;
+}
+#else
+typedef struct lfs_Lock {
+  char *ln;
+} lfs_Lock;
+static int lfs_lock_dir(lua_State *L) {
+  lfs_Lock *lock;
+  size_t pathl;
+  char *ln;
+  const char *lockfile = "/lockfile.lfs";
+  const char *path = luaL_checklstring(L, 1, &pathl);
+  lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
+  ln = (char*)malloc(pathl + strlen(lockfile) + 1);
+  if(!ln) {
+    lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
+  }
+  strcpy(ln, path); strcat(ln, lockfile);
+  if(symlink("lock", ln) == -1) {
+    free(ln); lua_pushnil(L);
+    lua_pushstring(L, strerror(errno)); return 2;
+  }
+  lock->ln = ln;
+  luaL_getmetatable (L, LOCK_METATABLE);
+  lua_setmetatable (L, -2);
+  return 1;
+}
+static int lfs_unlock_dir(lua_State *L) {
+  lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE);
+  if(lock->ln) {
+    unlink(lock->ln);
+    free(lock->ln);
+    lock->ln = NULL;
+  }
+  return 0;
+}
+#endif
+
+static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
+  static const int mode[] = {_O_BINARY, _O_TEXT};
+  static const char *const modenames[] = {"binary", "text", NULL};
+  int op = luaL_checkoption(L, arg, NULL, modenames);
+  int res = lfs_setmode(L, f, mode[op]);
+  if (res != -1) {
+    int i;
+    lua_pushboolean(L, 1);
+    for (i = 0; modenames[i] != NULL; i++) {
+      if (mode[i] == res) {
+        lua_pushstring(L, modenames[i]);
+        goto exit;
+      }
+    }
+    lua_pushnil(L);
+  exit:
+    return 2;
+  } else {
+    int en = errno;
+    lua_pushnil(L);
+    lua_pushfstring(L, "%s", strerror(en));
+    lua_pushinteger(L, en);
+    return 3;
+  }
+}
+
+static int lfs_f_setmode(lua_State *L) {
+  return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
+}
+
+/*
+** Locks a file.
+** @param #1 File handle.
+** @param #2 String with lock mode ('w'rite, 'r'ead).
+** @param #3 Number with start position (optional).
+** @param #4 Number with length (optional).
+*/
+static int file_lock (lua_State *L) {
+        FILE *fh = check_file (L, 1, "lock");
+        const char *mode = luaL_checkstring (L, 2);
+        const long start = luaL_optlong (L, 3, 0);
+        long len = luaL_optlong (L, 4, 0);
+        if (_file_lock (L, fh, mode, start, len, "lock")) {
+                lua_pushboolean (L, 1);
+                return 1;
+        } else {
+                lua_pushnil (L);
+                lua_pushfstring (L, "%s", strerror(errno));
+                return 2;
+        }
+}
+
+
+/*
+** Unlocks a file.
+** @param #1 File handle.
+** @param #2 Number with start position (optional).
+** @param #3 Number with length (optional).
+*/
+static int file_unlock (lua_State *L) {
+        FILE *fh = check_file (L, 1, "unlock");
+        const long start = luaL_optlong (L, 2, 0);
+        long len = luaL_optlong (L, 3, 0);
+        if (_file_lock (L, fh, "u", start, len, "unlock")) {
+                lua_pushboolean (L, 1);
+                return 1;
+        } else {
+                lua_pushnil (L);
+                lua_pushfstring (L, "%s", strerror(errno));
+                return 2;
+        }
+}
+
+
+/*
+** Creates a link.
+** @param #1 Object to link to.
+** @param #2 Name of link.
+** @param #3 True if link is symbolic (optional).
+*/
+static int make_link(lua_State *L)
+{
+#ifndef _WIN32
+        const char *oldpath = luaL_checkstring(L, 1);
+        const char *newpath = luaL_checkstring(L, 2);
+        return pushresult(L,
+                (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL);
+#else
+        return pusherror(L, "make_link is not supported on Windows");
+#endif
+}
+
+
+/*
+** Creates a directory.
+** @param #1 Directory path.
+*/
+static int make_dir (lua_State *L) {
+        const char *path = luaL_checkstring (L, 1);
+        int fail;
+#ifdef _WIN32
+        fail = _mkdir (path);
+#else
+        fail =  mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
+                             S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH );
+#endif
+        if (fail) {
+                lua_pushnil (L);
+        lua_pushfstring (L, "%s", strerror(errno));
+                return 2;
+        }
+        lua_pushboolean (L, 1);
+        return 1;
+}
+
+/*
+** Removes a directory.
+** @param #1 Directory path.
+*/
+static int remove_dir (lua_State *L) {
+        const char *path = luaL_checkstring (L, 1);
+        int fail;
+
+        fail = rmdir (path);
+
+        if (fail) {
+                lua_pushnil (L);
+                lua_pushfstring (L, "%s", strerror(errno));
+                return 2;
+        }
+        lua_pushboolean (L, 1);
+        return 1;
+}
+
+/*
+** Directory iterator
+*/
+static int dir_iter (lua_State *L) {
+#ifdef _WIN32
+        struct _finddata_t c_file;
+#else
+        struct dirent *entry;
+#endif
+        dir_data *d = (dir_data *)luaL_checkudata (L, 1, DIR_METATABLE);
+        luaL_argcheck (L, d->closed == 0, 1, "closed directory");
+#ifdef _WIN32
+        if (d->hFile == 0L) { /* first entry */
+                if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) {
+                        lua_pushnil (L);
+                        lua_pushstring (L, strerror (errno));
+                        d->closed = 1;
+                        return 2;
+                } else {
+                        lua_pushstring (L, c_file.name);
+                        return 1;
+                }
+        } else { /* next entry */
+                if (_findnext (d->hFile, &c_file) == -1L) {
+                        /* no more entries => close directory */
+                        _findclose (d->hFile);
+                        d->closed = 1;
+                        return 0;
+                } else {
+                        lua_pushstring (L, c_file.name);
+                        return 1;
+                }
+        }
+#else
+        if ((entry = readdir (d->dir)) != NULL) {
+                lua_pushstring (L, entry->d_name);
+                return 1;
+        } else {
+                /* no more entries => close directory */
+                closedir (d->dir);
+                d->closed = 1;
+                return 0;
+        }
+#endif
+}
+
+
+/*
+** Closes directory iterators
+*/
+static int dir_close (lua_State *L) {
+        dir_data *d = (dir_data *)lua_touserdata (L, 1);
+#ifdef _WIN32
+        if (!d->closed && d->hFile) {
+                _findclose (d->hFile);
+        }
+#else
+        if (!d->closed && d->dir) {
+                closedir (d->dir);
+        }
+#endif
+        d->closed = 1;
+        return 0;
+}
+
+
+/*
+** Factory of directory iterators
+*/
+static int dir_iter_factory (lua_State *L) {
+        const char *path = luaL_checkstring (L, 1);
+        dir_data *d;
+        lua_pushcfunction (L, dir_iter);
+        d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
+        luaL_getmetatable (L, DIR_METATABLE);
+        lua_setmetatable (L, -2);
+        d->closed = 0;
+#ifdef _WIN32
+        d->hFile = 0L;
+        if (strlen(path) > MAX_PATH-2)
+          luaL_error (L, "path too long: %s", path);
+        else
+          sprintf (d->pattern, "%s/*", path);
+#else
+        d->dir = opendir (path);
+        if (d->dir == NULL)
+          luaL_error (L, "cannot open %s: %s", path, strerror (errno));
+#endif
+        return 2;
+}
+
+
+/*
+** Creates directory metatable.
+*/
+static int dir_create_meta (lua_State *L) {
+        luaL_newmetatable (L, DIR_METATABLE);
+
+        /* Method table */
+        lua_newtable(L);
+        lua_pushcfunction (L, dir_iter);
+        lua_setfield(L, -2, "next");
+        lua_pushcfunction (L, dir_close);
+        lua_setfield(L, -2, "close");
+
+        /* Metamethods */
+        lua_setfield(L, -2, "__index");
+        lua_pushcfunction (L, dir_close);
+        lua_setfield (L, -2, "__gc");
+        return 1;
+}
+
+/*
+** Creates lock metatable.
+*/
+static int lock_create_meta (lua_State *L) {
+        luaL_newmetatable (L, LOCK_METATABLE);
+
+        /* Method table */
+        lua_newtable(L);
+        lua_pushcfunction(L, lfs_unlock_dir);
+        lua_setfield(L, -2, "free");
+
+        /* Metamethods */
+        lua_setfield(L, -2, "__index");
+        lua_pushcfunction(L, lfs_unlock_dir);
+        lua_setfield(L, -2, "__gc");
+        return 1;
+}
+
+
+#ifdef _WIN32
+ #ifndef S_ISDIR
+   #define S_ISDIR(mode)  (mode&_S_IFDIR)
+ #endif
+ #ifndef S_ISREG
+   #define S_ISREG(mode)  (mode&_S_IFREG)
+ #endif
+ #ifndef S_ISLNK
+   #define S_ISLNK(mode)  (0)
+ #endif
+ #ifndef S_ISSOCK
+   #define S_ISSOCK(mode)  (0)
+ #endif
+ #ifndef S_ISFIFO
+   #define S_ISFIFO(mode)  (0)
+ #endif
+ #ifndef S_ISCHR
+   #define S_ISCHR(mode)  (mode&_S_IFCHR)
+ #endif
+ #ifndef S_ISBLK
+   #define S_ISBLK(mode)  (0)
+ #endif
+#endif
+/*
+** Convert the inode protection mode to a string.
+*/
+#ifdef _WIN32
+static const char *mode2string (unsigned short mode) {
+#else
+static const char *mode2string (mode_t mode) {
+#endif
+  if ( S_ISREG(mode) )
+    return "file";
+  else if ( S_ISDIR(mode) )
+    return "directory";
+  else if ( S_ISLNK(mode) )
+        return "link";
+  else if ( S_ISSOCK(mode) )
+    return "socket";
+  else if ( S_ISFIFO(mode) )
+        return "named pipe";
+  else if ( S_ISCHR(mode) )
+        return "char device";
+  else if ( S_ISBLK(mode) )
+        return "block device";
+  else
+        return "other";
+}
+
+
+/*
+** Set access time and modification values for file
+*/
+static int file_utime (lua_State *L) {
+        const char *file = luaL_checkstring (L, 1);
+        struct utimbuf utb, *buf;
+
+        if (lua_gettop (L) == 1) /* set to current date/time */
+                buf = NULL;
+        else {
+                utb.actime = (time_t)luaL_optnumber (L, 2, 0);
+                utb.modtime = (time_t)luaL_optnumber (L, 3, utb.actime);
+                buf = &utb;
+        }
+        if (utime (file, buf)) {
+                lua_pushnil (L);
+                lua_pushfstring (L, "%s", strerror (errno));
+                return 2;
+        }
+        lua_pushboolean (L, 1);
+        return 1;
+}
+
+
+/* inode protection mode */
+static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
+        lua_pushstring (L, mode2string (info->st_mode));
+}
+/* device inode resides on */
+static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_dev);
+}
+/* inode's number */
+static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_ino);
+}
+/* number of hard links to the file */
+static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_nlink);
+}
+/* user-id of owner */
+static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_uid);
+}
+/* group-id of owner */
+static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_gid);
+}
+/* device type, for special file inode */
+static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_rdev);
+}
+/* time of last access */
+static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, info->st_atime);
+}
+/* time of last data modification */
+static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, info->st_mtime);
+}
+/* time of last file status change */
+static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, info->st_ctime);
+}
+/* file size, in bytes */
+static void push_st_size (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_size);
+}
+#ifndef _WIN32
+/* blocks allocated for file */
+static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_blocks);
+}
+/* optimal file system I/O blocksize */
+static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
+        lua_pushnumber (L, (lua_Number)info->st_blksize);
+}
+#endif
+static void push_invalid (lua_State *L, STAT_STRUCT *info) {
+  luaL_error(L, "invalid attribute name");
+#ifndef _WIN32
+  info->st_blksize = 0; /* never reached */
+#endif
+}
+
+ /*
+** Convert the inode protection mode to a permission list.
+*/
+
+#ifdef _WIN32
+static const char *perm2string (unsigned short mode) {
+  static char perms[10] = "---------\0";
+  int i;
+  for (i=0;i<9;i++) perms[i]='-';
+  if (mode  & _S_IREAD)
+   { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
+  if (mode  & _S_IWRITE)
+   { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
+  if (mode  & _S_IEXEC)
+   { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
+  return perms;
+}
+#else
+static const char *perm2string (mode_t mode) {
+  static char perms[10] = "---------\0";
+  int i;
+  for (i=0;i<9;i++) perms[i]='-';
+  if (mode & S_IRUSR) perms[0] = 'r';
+  if (mode & S_IWUSR) perms[1] = 'w';
+  if (mode & S_IXUSR) perms[2] = 'x';
+  if (mode & S_IRGRP) perms[3] = 'r';
+  if (mode & S_IWGRP) perms[4] = 'w';
+  if (mode & S_IXGRP) perms[5] = 'x';
+  if (mode & S_IROTH) perms[6] = 'r';
+  if (mode & S_IWOTH) perms[7] = 'w';
+  if (mode & S_IXOTH) perms[8] = 'x';
+  return perms;
+}
+#endif
+
+/* permssions string */
+static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
+    lua_pushstring (L, perm2string (info->st_mode));
+}
+
+typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
+
+struct _stat_members {
+        const char *name;
+        _push_function push;
+};
+
+struct _stat_members members[] = {
+        { "mode",         push_st_mode },
+        { "dev",          push_st_dev },
+        { "ino",          push_st_ino },
+        { "nlink",        push_st_nlink },
+        { "uid",          push_st_uid },
+        { "gid",          push_st_gid },
+        { "rdev",         push_st_rdev },
+        { "access",       push_st_atime },
+        { "modification", push_st_mtime },
+        { "change",       push_st_ctime },
+        { "size",         push_st_size },
+        { "permissions",  push_st_perm },
+#ifndef _WIN32
+        { "blocks",       push_st_blocks },
+        { "blksize",      push_st_blksize },
+#endif
+        { NULL, push_invalid }
+};
+
+/*
+** Get file or symbolic link information
+*/
+static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
+        int i;
+        STAT_STRUCT info;
+        const char *file = luaL_checkstring (L, 1);
+
+        if (st(file, &info)) {
+                lua_pushnil (L);
+                lua_pushfstring (L, "cannot obtain information from file `%s'", file);
+                return 2;
+        }
+        if (lua_isstring (L, 2)) {
+                int v;
+                const char *member = lua_tostring (L, 2);
+                if (strcmp (member, "mode") == 0) v = 0;
+#ifndef _WIN32
+                else if (strcmp (member, "blocks")  == 0) v = 11;
+                else if (strcmp (member, "blksize") == 0) v = 12;
+#endif
+                else /* look for member */
+                        for (v = 1; members[v].name; v++)
+                                if (*members[v].name == *member)
+                                        break;
+                /* push member value and return */
+                members[v].push (L, &info);
+                return 1;
+        } else if (!lua_istable (L, 2))
+                /* creates a table if none is given */
+                lua_newtable (L);
+        /* stores all members in table on top of the stack */
+        for (i = 0; members[i].name; i++) {
+                lua_pushstring (L, members[i].name);
+                members[i].push (L, &info);
+                lua_rawset (L, -3);
+        }
+        return 1;
+}
+
+
+/*
+** Get file information using stat.
+*/
+static int file_info (lua_State *L) {
+        return _file_info_ (L, STAT_FUNC);
+}
+
+
+/*
+** Get symbolic link information using lstat.
+*/
+static int link_info (lua_State *L) {
+        return _file_info_ (L, LSTAT_FUNC);
+}
+
+
+/*
+** Assumes the table is on top of the stack.
+*/
+static void set_info (lua_State *L) {
+        lua_pushliteral (L, "_COPYRIGHT");
+        lua_pushliteral (L, "Copyright (C) 2003-2012 Kepler Project");
+        lua_settable (L, -3);
+        lua_pushliteral (L, "_DESCRIPTION");
+        lua_pushliteral (L, "LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution");
+        lua_settable (L, -3);
+        lua_pushliteral (L, "_VERSION");
+        lua_pushliteral (L, "LuaFileSystem "LFS_VERSION);
+        lua_settable (L, -3);
+}
+
+
+static const struct luaL_Reg fslib[] = {
+        {"attributes", file_info},
+        {"chdir", change_dir},
+        {"currentdir", get_dir},
+        {"dir", dir_iter_factory},
+        {"link", make_link},
+        {"lock", file_lock},
+        {"mkdir", make_dir},
+        {"rmdir", remove_dir},
+        {"symlinkattributes", link_info},
+        {"setmode", lfs_f_setmode},
+        {"touch", file_utime},
+        {"unlock", file_unlock},
+        {"lock_dir", lfs_lock_dir},
+        {NULL, NULL},
+};
+
+int luaopen_lfs (lua_State *L) {
+        dir_create_meta (L);
+        lock_create_meta (L);
+        luaL_newlib (L, fslib);
+        lua_pushvalue(L, -1);
+        lua_setglobal(L, LFS_LIBNAME);
+        set_info (L);
+        return 1;
+}

+ 17 - 0
src/third_party/lfs.h

@@ -0,0 +1,17 @@
+/*
+** LuaFileSystem
+** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
+**
+** $Id: lfs.h,v 1.5 2008/02/19 20:08:23 mascarenhas Exp $
+*/
+
+/* Define 'chdir' for systems that do not implement it */
+#ifdef NO_CHDIR
+#define chdir(p)	(-1)
+#define chdir_error	"Function 'chdir' not provided by system"
+#else
+#define chdir_error	strerror(errno)
+#endif
+
+
+int luaopen_lfs (lua_State *L);

+ 327 - 0
src/third_party/lsqlite3.c

@@ -1,6 +1,10 @@
 /************************************************************************
 * lsqlite3                                                              *
+<<<<<<< HEAD
 * Copyright (C) 2002-2007 Tiago Dionizio, Doug Currie                   *
+=======
+* Copyright (C) 2002-2013 Tiago Dionizio, Doug Currie                   *
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 * All rights reserved.                                                  *
 * Author    : Tiago Dionizio <tiago.dionizio@ist.utl.pt>                *
 * Author    : Doug Currie <doug.currie@alum.mit.edu>                    *
@@ -34,12 +38,34 @@
 #include "lua.h"
 #include "lauxlib.h"
 
+<<<<<<< HEAD
+=======
+#if LUA_VERSION_NUM > 501
+//
+// Lua 5.2
+//
+#define lua_strlen lua_rawlen
+// luaL_typerror always used with arg at ndx == NULL
+#define luaL_typerror(L,ndx,str) luaL_error(L,"bad argument %d (%s expected, got nil)",ndx,str)
+// luaL_register used once, so below expansion is OK for this case
+#define luaL_register(L,name,reg) lua_newtable(L);luaL_setfuncs(L,reg,0)
+// luaL_openlib always used with name == NULL
+#define luaL_openlib(L,name,reg,nup) luaL_setfuncs(L,reg,nup)
+#endif
+
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 #include "sqlite3.h"
 
 /* compile time features */
 #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK)
     #define SQLITE_OMIT_PROGRESS_CALLBACK 0
 #endif
+<<<<<<< HEAD
+=======
+#if !defined(LSQLITE_OMIT_UPDATE_HOOK)
+    #define LSQLITE_OMIT_UPDATE_HOOK 0
+#endif
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 typedef struct sdb sdb;
 typedef struct sdb_vm sdb_vm;
@@ -77,6 +103,22 @@ struct sdb {
 
     int trace_cb;       /* trace callback */
     int trace_udata;
+<<<<<<< HEAD
+=======
+
+#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
+
+    int update_hook_cb; /* update_hook callback */
+    int update_hook_udata;
+
+    int commit_hook_cb; /* commit_hook callback */
+    int commit_hook_udata;
+
+    int rollback_hook_cb; /* rollback_hook callback */
+    int rollback_hook_udata;
+
+#endif
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 };
 
 static const char *sqlite_meta      = ":sqlite3";
@@ -579,7 +621,20 @@ static sdb *newdb (lua_State *L) {
     db->progress_cb =
     db->progress_udata =
     db->trace_cb =
+<<<<<<< HEAD
     db->trace_udata = LUA_NOREF;
+=======
+    db->trace_udata = 
+#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
+    db->update_hook_cb =
+    db->update_hook_udata =
+    db->commit_hook_cb =
+    db->commit_hook_udata =
+    db->rollback_hook_cb =
+    db->rollback_hook_udata =
+#endif
+     LUA_NOREF;
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
     luaL_getmetatable(L, sqlite_meta);
     lua_setmetatable(L, -2);        /* set metatable */
@@ -627,6 +682,17 @@ static int cleanupdb(lua_State *L, sdb *db) {
     luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
     luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
     luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
+<<<<<<< HEAD
+=======
+#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
+    luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
+    luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
+    luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
+    luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
+    luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
+    luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
+#endif
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
     /* close database */
     result = sqlite3_close(db->db);
@@ -648,7 +714,11 @@ static int cleanupdb(lua_State *L, sdb *db) {
 
 static sdb *lsqlite_getdb(lua_State *L, int index) {
     sdb *db = (sdb*)luaL_checkudata(L, index, sqlite_meta);
+<<<<<<< HEAD
     // TODO lsm if (db == NULL) luaL_typerror(L, index, "sqlite database");
+=======
+    if (db == NULL) luaL_typerror(L, index, "sqlite database");
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     return db;
 }
 
@@ -680,7 +750,11 @@ static lcontext *lsqlite_make_context(lua_State *L) {
 
 static lcontext *lsqlite_getcontext(lua_State *L, int index) {
     lcontext *ctx = (lcontext*)luaL_checkudata(L, index, sqlite_ctx_meta);
+<<<<<<< HEAD
     // TODO lsm if (ctx == NULL) luaL_typerror(L, index, "sqlite context");
+=======
+    if (ctx == NULL) luaL_typerror(L, index, "sqlite context");
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     return ctx;
 }
 
@@ -1180,7 +1254,11 @@ static int db_trace(lua_State *L) {
         db->trace_cb =
         db->trace_udata = LUA_NOREF;
 
+<<<<<<< HEAD
         /* clear busy handler */
+=======
+        /* clear trace handler */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         sqlite3_trace(db->db, NULL, NULL);
     }
     else {
@@ -1195,13 +1273,202 @@ static int db_trace(lua_State *L) {
         db->trace_udata = luaL_ref(L, LUA_REGISTRYINDEX);
         db->trace_cb = luaL_ref(L, LUA_REGISTRYINDEX);
 
+<<<<<<< HEAD
         /* set busy handler */
+=======
+        /* set trace handler */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
         sqlite3_trace(db->db, db_trace_callback, db);
     }
 
     return 0;
 }
 
+<<<<<<< HEAD
+=======
+#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
+
+/*
+** update_hook callback:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata, {one of SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE}, 
+**          database name, table name (containing the affected row), rowid of the row
+*/
+static void db_update_hook_callback(void *user, int op, char const *dbname, char const *tblname, sqlite3_int64 rowid) {
+    sdb *db = (sdb*)user;
+    lua_State *L = db->L;
+    int top = lua_gettop(L);
+    lua_Number n;
+
+    /* setup lua callback call */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_cb);    /* get callback */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_udata); /* get callback user data */
+    lua_pushnumber(L, (lua_Number )op);
+    lua_pushstring(L, dbname); /* update_hook database name */
+    lua_pushstring(L, tblname); /* update_hook database name */
+    n = (lua_Number)rowid;
+    if (n == rowid)
+        lua_pushnumber(L, n);
+    else
+        lua_pushfstring(L, "%ll", rowid);
+
+    /* call lua function */
+    lua_pcall(L, 5, 0, 0);
+    /* ignore any error generated by this function */
+
+    lua_settop(L, top);
+}
+
+static int db_update_hook(lua_State *L) {
+    sdb *db = lsqlite_checkdb(L, 1);
+
+    if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
+        luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
+        luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
+
+        db->update_hook_cb =
+        db->update_hook_udata = LUA_NOREF;
+
+        /* clear update_hook handler */
+        sqlite3_update_hook(db->db, NULL, NULL);
+    }
+    else {
+        luaL_checktype(L, 2, LUA_TFUNCTION);
+
+        /* make sure we have an userdata field (even if nil) */
+        lua_settop(L, 3);
+
+        luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
+        luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
+
+        db->update_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
+        db->update_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+
+        /* set update_hook handler */
+        sqlite3_update_hook(db->db, db_update_hook_callback, db);
+    }
+
+    return 0;
+}
+
+/*
+** commit_hook callback:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata
+** Returned value: Return false or nil to continue the COMMIT operation normally.
+**  return true (non false, non nil), then the COMMIT is converted into a ROLLBACK. 
+*/
+static int db_commit_hook_callback(void *user) {
+    sdb *db = (sdb*)user;
+    lua_State *L = db->L;
+    int top = lua_gettop(L);
+    int rollback = 0;
+
+    /* setup lua callback call */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_cb);    /* get callback */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_udata); /* get callback user data */
+
+    /* call lua function */
+    if (!lua_pcall(L, 1, 1, 0))
+        rollback = lua_toboolean(L, -1); /* use result if there was no error */
+
+    lua_settop(L, top);
+    return rollback;
+}
+
+static int db_commit_hook(lua_State *L) {
+    sdb *db = lsqlite_checkdb(L, 1);
+
+    if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
+        luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
+        luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
+
+        db->commit_hook_cb =
+        db->commit_hook_udata = LUA_NOREF;
+
+        /* clear commit_hook handler */
+        sqlite3_commit_hook(db->db, NULL, NULL);
+    }
+    else {
+        luaL_checktype(L, 2, LUA_TFUNCTION);
+
+        /* make sure we have an userdata field (even if nil) */
+        lua_settop(L, 3);
+
+        luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
+        luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
+
+        db->commit_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
+        db->commit_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+
+        /* set commit_hook handler */
+        sqlite3_commit_hook(db->db, db_commit_hook_callback, db);
+    }
+
+    return 0;
+}
+
+/*
+** rollback hook callback:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata
+*/
+static void db_rollback_hook_callback(void *user) {
+    sdb *db = (sdb*)user;
+    lua_State *L = db->L;
+    int top = lua_gettop(L);
+
+    /* setup lua callback call */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);    /* get callback */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_udata); /* get callback user data */
+
+    /* call lua function */
+    lua_pcall(L, 1, 0, 0);
+    /* ignore any error generated by this function */
+
+    lua_settop(L, top);
+}
+
+static int db_rollback_hook(lua_State *L) {
+    sdb *db = lsqlite_checkdb(L, 1);
+
+    if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
+        luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
+        luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
+
+        db->rollback_hook_cb =
+        db->rollback_hook_udata = LUA_NOREF;
+
+        /* clear rollback_hook handler */
+        sqlite3_rollback_hook(db->db, NULL, NULL);
+    }
+    else {
+        luaL_checktype(L, 2, LUA_TFUNCTION);
+
+        /* make sure we have an userdata field (even if nil) */
+        lua_settop(L, 3);
+
+        luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
+        luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
+
+        db->rollback_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
+        db->rollback_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+
+        /* set rollback_hook handler */
+        sqlite3_rollback_hook(db->db, db_rollback_hook_callback, db);
+    }
+
+    return 0;
+}
+
+#endif /* #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK */
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
 #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK
 
@@ -1721,6 +1988,43 @@ static const struct {
     SC(INTEGER)     SC(FLOAT)       SC(TEXT)        SC(BLOB)
     SC(NULL)
 
+<<<<<<< HEAD
+=======
+    /* Authorizer Action Codes */
+    SC(CREATE_INDEX       )
+    SC(CREATE_TABLE       )
+    SC(CREATE_TEMP_INDEX  )
+    SC(CREATE_TEMP_TABLE  )
+    SC(CREATE_TEMP_TRIGGER)
+    SC(CREATE_TEMP_VIEW   )
+    SC(CREATE_TRIGGER     )
+    SC(CREATE_VIEW        )
+    SC(DELETE             )
+    SC(DROP_INDEX         )
+    SC(DROP_TABLE         )
+    SC(DROP_TEMP_INDEX    )
+    SC(DROP_TEMP_TABLE    )
+    SC(DROP_TEMP_TRIGGER  )
+    SC(DROP_TEMP_VIEW     )
+    SC(DROP_TRIGGER       )
+    SC(DROP_VIEW          )
+    SC(INSERT             )
+    SC(PRAGMA             )
+    SC(READ               )
+    SC(SELECT             )
+    SC(TRANSACTION        )
+    SC(UPDATE             )
+    SC(ATTACH             )
+    SC(DETACH             )
+    SC(ALTER_TABLE        )
+    SC(REINDEX            )
+    SC(ANALYZE            )
+    SC(CREATE_VTABLE      )
+    SC(DROP_VTABLE        )
+    SC(FUNCTION           )
+    SC(SAVEPOINT          )
+
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
     /* terminator */
     { NULL, 0 }
 };
@@ -1746,6 +2050,14 @@ static const luaL_Reg dblib[] = {
     {"progress_handler",    db_progress_handler     },
     {"busy_timeout",        db_busy_timeout         },
     {"busy_handler",        db_busy_handler         },
+<<<<<<< HEAD
+=======
+#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
+    {"update_hook",         db_update_hook          },
+    {"commit_hook",         db_commit_hook          },
+    {"rollback_hook",       db_rollback_hook        },
+#endif
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
     {"prepare",             db_prepare              },
     {"rows",                db_rows                 },
@@ -1855,6 +2167,17 @@ static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
     lua_pop(L, 1);
 }
 
+<<<<<<< HEAD
+=======
+
+static int luaopen_sqlitelib (lua_State *L) {
+    luaL_newlibtable(L, sqlitelib);
+    luaL_setfuncs(L, sqlitelib, 0);
+    return 1;
+}
+
+
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 LUALIB_API int luaopen_lsqlite3(lua_State *L) {
     create_meta(L, sqlite_meta, dblib);
     create_meta(L, sqlite_vm_meta, vmlib);
@@ -1864,7 +2187,11 @@ LUALIB_API int luaopen_lsqlite3(lua_State *L) {
     sqlite_ctx_meta_ref = luaL_ref(L, LUA_REGISTRYINDEX);
 
     /* register (local) sqlite metatable */
+<<<<<<< HEAD
     luaL_register(L, "sqlite3", sqlitelib);
+=======
+    luaL_requiref(L, "sqlite3", luaopen_sqlitelib, 1);
+>>>>>>> b393b8d2410737a01a0d18987b5dfc185b3c0ef3
 
     {
         int i = 0;

+ 73 - 0
test/ajax/echo.cgi

@@ -0,0 +1,73 @@
+#!/usr/bin/lua5.1
+
+-- Every CGI script that returns any valid JSON object will work in the test.
+-- In case you do not have not yet used CGI, you may want to use this script which is written in Lua.
+-- You may download an interpreter from http://luabinaries.sourceforge.net/download.html, extract it
+-- to some folder in your search path (the path of the webserver or /usr/bin on Linux), and add the
+-- following lines to your .conf file.
+-- cgi_interpreter c:\somewhere\lua5.1.exe
+-- enable_keep_alive yes
+
+resp = "{";
+
+method = os.getenv("REQUEST_METHOD")
+uri = os.getenv("REQUEST_URI");
+query = os.getenv("QUERY_STRING");
+datalen = os.getenv("CONTENT_LENGTH");
+
+if method then
+  resp = resp .. '"method" : "' .. method .. '", ';
+end
+if uri then
+  resp = resp .. '"uri" : "' .. uri .. '", ';
+end
+if query then
+  resp = resp .. '"query" : "' .. query .. '", ';
+end
+if datalen then
+  resp = resp .. '"datalen" : "' .. datalen .. '", ';
+end
+
+resp = resp .. '"time" : "' .. os.date() .. '" ';
+
+resp = resp .. "}";
+
+
+
+
+print "Status: 200 OK"
+print "Connection: close"
+--print "Connection: keep-alive"
+print "Content-Type: text/html; charset=utf-8"
+print "Cache-Control: no-cache"
+--print ("Content-Length: " .. resp:len())
+print ""
+
+print (resp)
+
+
+doLogging = false
+
+if (doLogging) then
+  -- Store the POST data to a file
+  if (method == "POST") then
+    myFile = io.open("data" .. query:sub(4) .. ".txt", "wb");
+    myFile:write(resp)
+    myFile:write("\r\n\r\n")  
+    if datalen then
+      datalen = tonumber(datalen)
+      myFile:write("<<< " .. datalen .. " bytes of data >>>\r\n")
+      
+      data = io.stdin:read(datalen)
+      myFile:write(data)
+      
+      myFile:write("\r\n<<< end >>>\r\n")
+    else
+      myFile:write("<<< no data >>>\r\n")
+    end  
+    myFile:close()
+  end
+end
+
+
+

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 0
test/ajax/jquery.js


+ 140 - 0
test/ajax/test.html

@@ -0,0 +1,140 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+  <head>
+    <title>Test</title>
+    <script type='text/javascript' language="javascript" src='jquery.js'></script>
+    <script type='text/javascript' language="javascript">
+    <!--
+
+    function mbox() {
+      alert('Javascript OK');
+    }
+
+
+    var totalCount = 10;
+    var pendingCount = 0;
+    var errorCount = 0;
+    var pushCount = 0;
+
+
+    function runTest(method, isAsync) {
+
+      ++pushCount;
+      document.getElementById('start').innerHTML = 'Test: ' + pushCount;
+      document.getElementById('resTotal').innerHTML = 'running';
+
+      for (var i = 1; i <= totalCount; ++i) {
+        document.getElementById('res'+i).innerHTML = "ready";
+      }
+
+      errorCount = 0;
+      pendingCount = totalCount;
+
+      for (var i = 1; i <= totalCount; ++i) {
+
+        fetch(i,  method, isAsync);
+      }
+    }
+
+
+    function fetch(id, method, isAsync) {
+
+      document.getElementById('res'+id).innerHTML = "pending";
+
+      $.ajax({
+        async: isAsync,
+        url: 'echo.cgi?id=' + id,
+        type: method,
+        timeout: 10000,
+        data: { 'id' : id ,
+                'longText1' : "adfsdfasdklkjlgasfdfjkhq345sdafbmkanq3trsdghkjqw4etrjlkabsdfkabvauiregtlkjasdbvabl4btrjawebbfjsdhbjk342r5bjksdbfkljbhasdfbhj234qjhasdg76k11234jhv900adfasddsfmzasdfhjgajsvhgkjhasdf77aefcae4fkjzasdfgukeaf7dkkegasdfigjcvxgui",
+                'longText2' : "bsdfsdfasdklkjlgasdfjkhq345sdafbmkanq3trsdghkjqw4etrjlkabsdfkabvauiregtlkjasdbvabl4btrjawebbfjsdhbjk342r5bjksdbfkljbhasdfbhj234qjhasdg76k11234jhv900adfasddsfmzasdfhjgajsvhgkjhasdf77aefcae4fkjzasdfgukeaf7dkkegasdfigjcvxgui",
+                'longText3' : "sdfsadagsdklkjlgasdfjkhq345sdafbmkanq3trsdghkjqw4etrjlkabsdfkabvauiregtlkjasdbvabl4btrjawebbfjsdhbjk342r5bjksdbfkljbhasdfbhj234qjhasdg76k11234jhv900adfasddsfmzasdfhjgajsvhgkjhasdf77aefcae4fkjzasdfgukeaf7dkkegasdfigjcvxgui",
+                'longText4' : "q34sdfas3fhbkjlgasdfjkhq345sdafbmkanq3trsdghkjqw4etrjlkabsdfkabvauiregtlkjasdbvabl4btrjawebbfjsdhbjk342r5bjksdbfkljbhasdfbhj234qjhasdg76k11234jhv900adfasddsfmzasdfhjgajsvhgkjhasdf77aefcae4fkjzasdfgukeaf7dkkegasdfigjcvxgui",
+                'longText5' : "askj2kjcvxychklgasdfjkhq345sdafbmkanq3trsdghkjqw4etrjlkabsdfkabvauiregtlkjasdbvabl4btrjawebbfjsdhbjk342r5bjksdbfkljbhasdfbhj234qjhasdg76k11234jhv900adfasddsfmzasdfhjgajsvhgkjhasdf77aefcae4fkjzasdfgukeaf7dkkegasdfigjcvxgui",
+                'longText6' : "asdfjklhlkjhv8öajsdfjkhq345sdafbmkanq3trsdghkjqw4etrjlkabsdfkabvauiregtlkjasdbvabl4btrjawebbfjsdhbjk342r5bjksdbfkljbhasdfbhj234qjhasdg76k11234jhv900adfasddsfmzasdfhjgajsvhgkjhasdf77aefcae4fkjzasdfgukeaf7dkkegasdfigjcvxgui",
+                'async' : isAsync
+              },
+        dataType: 'json',
+        succes: function(data) {
+        },
+        error: function() {
+          ++errorCount;
+        },
+        complete: function(jqXHR, textStatus) {
+
+          --pendingCount;
+
+          document.getElementById('res'+id).innerHTML = textStatus;
+          console.log('id: ' + id + ' (' + pendingCount + '/' + totalCount + '), status: ' + textStatus);
+
+          if (pendingCount == 0) {
+            document.getElementById('resTotal').innerHTML = 'done';
+            console.log('complete, error count: ' + errorCount);
+          }
+        }
+      });
+
+    }
+
+
+    //-->
+    </script>
+
+  </head>
+  <body>
+    <p>
+      <div id="start">Test not started.</div>
+    </p>
+    <p>
+      <table>
+        <tr>
+          <td>
+            <input id="testButton1" type="button" onclick="javascript:runTest('GET', false)" value="sync GET"></input>
+          </td>
+          <td>
+            <input id="testButton2" type="button" onclick="javascript:runTest('POST', false)" value="sync POST"></input>
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <input id="testButton3" type="button" onclick="javascript:runTest('GET', true)" value="async GET"></input>
+          </td>
+          <td>
+            <input id="testButton4" type="button" onclick="javascript:runTest('POST', true)" value="async POST"></input>
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <input id="testButtonReset" type="button" onclick="javascript:location.reload(true)" value="reset"></input>
+          </td>
+          <td>
+          </td>
+        </tr>
+        <tr>
+          <td>
+            <input id="testButtonBox" type="button" onclick="javascript:mbox()" value="MsgBox"></input>
+          </td>
+          <td>
+          </td>
+        </tr>
+      </table>
+    </p>
+    <p>
+      <table border="1">
+        <tr><th>Test</th><th>Result</th></tr>
+        <tr><td>1</td><td><div id="res1">not started</div></td></tr>
+        <tr><td>2</td><td><div id="res2">not started</div></td></tr>
+        <tr><td>3</td><td><div id="res3">not started</div></td></tr>
+        <tr><td>4</td><td><div id="res4">not started</div></td></tr>
+        <tr><td>5</td><td><div id="res5">not started</div></td></tr>
+        <tr><td>6</td><td><div id="res6">not started</div></td></tr>
+        <tr><td>7</td><td><div id="res7">not started</div></td></tr>
+        <tr><td>8</td><td><div id="res8">not started</div></td></tr>
+        <tr><td>9</td><td><div id="res9">not started</div></td></tr>
+        <tr><td>10</td><td><div id="res10">not started</div></td></tr>
+      </table>
+      <div id="resTotal">Push [Test] to start.</div>
+    </p>
+  </body>
+</html>

+ 65 - 0
test/page2.lp

@@ -0,0 +1,65 @@
+<? mg.write("HTTP/1.0 200 OK") ?>
+<? mg.write("Content-Type: text/html") ?>
+
+<html><body>
+
+<p>This is another example of a Lua server page, served by
+<a href="http://code.google.com/p/civetweb">Civetweb web server</a>.
+</p><p>
+The following features are available:
+<ul>
+<?
+  -- function in one Lua tag should still be available in the next one
+  function test(tab, name)
+    if tab then
+      mg.write("<li>" .. name .. "</li>")
+    end
+  end
+  function recurse(tab)
+    mg.write("<ul>")
+    for k,v in pairs(tab) do      
+      if type(v) == "table" then
+        mg.write("<li>" .. tostring(k) .. ":</li>")
+        recurse(v)
+      else
+        mg.write("<li>" .. tostring(k) .. " = " .. tostring(v) .. "</li>")        
+      end
+    end
+    mg.write("</ul>")
+  end
+?>
+<?
+  mg.write("<li>" .. _VERSION .. " with the following standard libraries</li>")
+  mg.write("<ul>")
+  libs = {"string", "math", "table", "io", "os", "bit32", "package", "coroutine", "debug"};
+  for _,n in ipairs(libs) do
+    test(_G[n], n);
+  end
+  mg.write("</ul>")
+  test(sqlite3, "sqlite3 binding")
+  test(lfs,"lua file system")
+  
+  libname = "mg"
+  test(_G[libname], libname .. " library")
+  recurse(_G[libname])
+?>
+</ul></p>
+<p> Today is <? mg.write(os.date("%A")) ?>
+
+<p>
+<?
+  -- for k,v in pairs(_G) do mg.write(k, '\n') end  
+
+  if lfs then    
+    mg.write("Files in " .. lfs.currentdir())
+    mg.write("<ul>")
+    for f in lfs.dir(".") do
+      mg.write("<li>" .. f .. "</li>")
+      local at = lfs.attributes(f);
+      recurse(at)
+    end
+    mg.write("</ul>")
+  end
+?>
+</p>
+</body></html>

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä