pax_global_header00006660000000000000000000000064122066445600014517gustar00rootroot0000000000000052 comment=a339eca97d6be099fe0958b345dca57c46c734d7 lua-apr-0.23.2.dfsg/000077500000000000000000000000001220664456000140665ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/LICENSE000066400000000000000000000021511220664456000150720ustar00rootroot00000000000000Copyright: 2011, Peter Odding , zhiguo zhao 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. lua-apr-0.23.2.dfsg/Makefile000066400000000000000000000165431220664456000155370ustar00rootroot00000000000000# This is the UNIX makefile for the Lua/APR binding. # # Author: Peter Odding # Last Change: November 26, 2011 # Homepage: http://peterodding.com/code/lua/apr/ # License: MIT # # This makefile has been tested on Ubuntu Linux 10.04. VERSION = $(shell grep _VERSION src/apr.lua | cut "-d'" -f2) RELEASE = 1 PACKAGE = lua-apr-$(VERSION)-$(RELEASE) # Based on http://www.luarocks.org/en/Recommended_practices_for_Makefiles LUA_DIR = /usr/local LUA_LIBDIR = $(LUA_DIR)/lib/lua/5.1 LUA_SHAREDIR = $(LUA_DIR)/share/lua/5.1 # Location for generated HTML documentation. LUA_APR_DOCS = $(LUA_DIR)/share/doc/lua-apr # Names of source / binary modules to install. SOURCE_MODULE = src/apr.lua SERIALIZATION_MODULE = src/serialize.lua BINARY_MODULE = core.so APREQ_BINARY = apreq.so # Names of source code files to compile & link (the individual lines enable # automatic rebasing between git feature branches and the master branch). SOURCES = src/base64.c \ src/buffer.c \ src/crypt.c \ src/date.c \ src/dbd.c \ src/dbm.c \ src/env.c \ src/errno.c \ src/filepath.c \ src/fnmatch.c \ src/getopt.c \ src/http.c \ src/io_dir.c \ src/io_file.c \ src/io_net.c \ src/io_pipe.c \ src/ldap.c \ src/lua_apr.c \ src/memcache.c \ src/memory_pool.c \ src/object.c \ src/permissions.c \ src/pollset.c \ src/proc.c \ src/serialize.c \ src/shm.c \ src/signal.c \ src/stat.c \ src/str.c \ src/thread.c \ src/thread_queue.c \ src/time.c \ src/uri.c \ src/user.c \ src/uuid.c \ src/xlate.c \ src/xml.c # Determine compiler flags and linker flags for external dependencies using a # combination of pkg-config, apr-1-config, apu-1-config and apreq2-config. override CFLAGS += $(shell lua etc/make.lua --cflags) override LFLAGS += $(shell lua etc/make.lua --lflags) # Create debug builds by default but enable release # builds using the command line "make DO_RELEASE=1". ifndef DO_RELEASE override CFLAGS += -g -DDEBUG override LFLAGS += -g endif # Enable profiling with "make PROFILING=1". ifdef PROFILING override CFLAGS += -fprofile-arcs -ftest-coverage override LFLAGS += -fprofile-arcs endif # We need this to successfully build Lua/APR on Mac OS X. # See also https://github.com/xolox/lua-apr/issues/10. ifeq (Darwin,$(shell uname -s)) LINK_TYPE = -bundle -undefined dynamic_lookup else LINK_TYPE = -shared endif # Names of compiled object files. OBJECTS = $(patsubst %.c,%.o,$(SOURCES)) # The default build rule, just a shortcut for the "apr.so" target. default: $(BINARY_MODULE) # Build the binary module. $(BINARY_MODULE): $(OBJECTS) Makefile $(CC) $(LINK_TYPE) -o $@ $(OBJECTS) $(LFLAGS) || lua etc/make.lua --check # Build the standalone libapreq2 binding (not sure if anyone out there is # actually using this, if you are please speak up or I may remove this :-) $(APREQ_BINARY): etc/apreq_standalone.c Makefile $(CC) -Wall $(LINK_TYPE) -o $@ $(CFLAGS) -fPIC etc/apreq_standalone.c $(LFLAGS) || lua etc/make.lua --check # Compile individual source code files to object files. $(OBJECTS): %.o: %.c src/lua_apr.h Makefile $(CC) -Wall -c $(CFLAGS) -fPIC $< -o $@ || lua etc/make.lua --check # Always try to regenerate the error handling module. src/errno.c: etc/errors.lua Makefile @lua etc/errors.lua # Install the Lua/APR binding under $LUA_DIR. install: $(BINARY_MODULE) docs mkdir -p $(LUA_SHAREDIR)/apr/test cp $(SOURCE_MODULE) $(LUA_SHAREDIR)/apr.lua cp $(SERIALIZATION_MODULE) $(LUA_SHAREDIR)/apr/serialize.lua cp test/*.lua $(LUA_SHAREDIR)/apr/test mkdir -p $(LUA_LIBDIR)/apr cp $(BINARY_MODULE) $(LUA_LIBDIR)/apr/$(BINARY_MODULE) [ ! -f $(APREQ_BINARY) ] || cp $(APREQ_BINARY) $(LUA_LIBDIR)/$(APREQ_BINARY) [ -d $(LUA_APR_DOCS) ] || mkdir -p $(LUA_APR_DOCS) cp doc/docs.html doc/notes.html doc/readme.html doc/todo.html $(LUA_APR_DOCS) 2>/dev/null || true # Remove previously installed files. uninstall: rm -f $(LUA_SHAREDIR)/apr.lua rm -fR $(LUA_SHAREDIR)/apr/test rm -fR $(LUA_LIBDIR)/apr cd $(LUA_APR_DOCS) && rm -r docs.html notes.html readme.html todo.html rmdir $(LUA_APR_DOCS) 2>/dev/null || true # Run the test suite. test: install export LD_PRELOAD=/lib/libSegFault.so; lua -e "require 'apr.test' ()" # Run the test suite under Valgrind to detect and analyze errors. valgrind: valgrind -q --track-origins=yes --leak-check=full lua -e "require 'apr.test' ()" # Create or update test coverage report using "lcov". coverage: [ -d etc/coverage ] || mkdir etc/coverage rm -f src/errno.gcda src/errno.gcno lcov -d src -b . --capture --output-file etc/coverage/lua-apr.info genhtml -o etc/coverage etc/coverage/lua-apr.info # Convert the Markdown documents to HTML. docs: doc/docs.md $(SOURCE_MODULE) $(SOURCES) @lua etc/wrap.lua doc/docs.md doc/docs.html @lua etc/wrap.lua README.md doc/readme.html @lua etc/wrap.lua NOTES.md doc/notes.html @lua etc/wrap.lua TODO.md doc/todo.html # Extract the documentation from the source code and generate a Markdown file # containing all documentation including coverage statistics (if available). # XXX This file won't be regenerated automatically because A) the documentation # in the ZIP archives I release contains coverage statistics that cannot be # generated without first building and installing a profiling release and # running the test suite and B) new users certainly won't know how to generate # coverage statistics which means "make install" would overwrite the existing # documentation and lose the coverage statistics... doc/docs.md: etc/docs.lua @[ -d doc ] || mkdir doc @lua etc/docs.lua > doc/docs.md # Create a profiling build, run the test suite, generate documentation # including test coverage, then clean the intermediate files. package_prerequisites: clean @echo Collecting coverage statistics using profiling build @export PROFILING=1; lua etc/buildbot.lua --local @echo Generating documentation including coverage statistics @rm -f doc/docs.md; make --no-print-directory docs # Prepare a source ZIP archive from which Lua/APR can be build. zip_package: package_prerequisites @rm -f $(PACKAGE).zip @mkdir -p $(PACKAGE)/doc @cp doc/docs.html doc/notes.html doc/readme.html doc/todo.html $(PACKAGE)/doc @mkdir -p $(PACKAGE)/etc @cp -a etc/buildbot.lua etc/make.lua etc/docs.lua etc/errors.lua etc/wrap.lua $(PACKAGE)/etc @mkdir -p $(PACKAGE)/benchmarks @cp -a benchmarks/* $(PACKAGE)/benchmarks @mkdir -p $(PACKAGE)/examples @cp -a examples/*.lua $(PACKAGE)/examples @mkdir -p $(PACKAGE)/src @cp -a src/lua_apr.h $(SOURCES) $(SOURCE_MODULE) $(PACKAGE)/src @mkdir -p $(PACKAGE)/test @cp -a test/*.lua $(PACKAGE)/test @cp Makefile Makefile.win make.cmd README.md NOTES.md TODO.md $(PACKAGE) @zip $(PACKAGE).zip -qr $(PACKAGE) @echo Generated $(PACKAGE).zip @rm -R $(PACKAGE) # Prepare a LuaRocks rockspec for the current release. rockspec: zip_package @cat etc/template.rockspec \ | sed "s/{{VERSION}}/$(VERSION)-$(RELEASE)/g" \ | sed "s/{{DATE}}/`export LANG=; date '+%B %d, %Y'`/" \ | sed "s/{{HASH}}/`md5sum $(PACKAGE).zip | cut '-d ' -f1 `/" \ > lua-apr-$(VERSION)-$(RELEASE).rockspec @echo Generated $(PACKAGE).rockspec # Clean generated files from working directory. clean: @rm -Rf $(OBJECTS) $(BINARY_MODULE) $(APREQ_BINARY) doc/docs.md @git checkout src/errno.c 2>/dev/null || true .PHONY: install uninstall test valgrind coverage docs \ package_prerequisites zip_package rockspec clean # vim: ts=4 sw=4 noet lua-apr-0.23.2.dfsg/Makefile.win000066400000000000000000000124521220664456000163260ustar00rootroot00000000000000# This is the Windows makefile for the Lua/APR binding. # # Author: Peter Odding # Last Change: November 20, 2011 # Homepage: http://peterodding.com/code/lua/apr/ # License: MIT # # This makefile has been tested on Windows XP with NMAKE from the free # Microsoft Visual C++ 2010 Express tool chain. You may want to change the # following settings: # The directories where "lua.h" and "lua51.lib" can be found (these defaults # are based on the directory structure used by Lua for Windows v5.1.4-40). LUA_DIR = C:\Program Files\Lua\5.1 LUA_INCDIR = $(LUA_DIR)\include LUA_LIBDIR = $(LUA_DIR)\clibs LUA_LINKDIR = $(LUA_DIR)\lib LUA_SHAREDIR = $(LUA_DIR)\lua # The directories where "apr.h" and "libapr-1.lib" can be found. APR_INCDIR = C:\lua-apr\apr\include APR_LIBDIR = C:\lua-apr\apr\release # The directories where "apu.h" and "libaprutil-1.lib" can be found. APU_INCDIR = C:\lua-apr\apr-util\include APU_LIBDIR = C:\lua-apr\apr-util\release # The directory where "libapriconv-1.lib" can be found. API_LIBDIR = C:\lua-apr\apr-iconv\release # The directories where "apreq.h" and "libapreq-2.lib" can be found. APREQ_INCDIR = C:\lua-apr\libapreq2\include APREQ_LIBDIR = C:\lua-apr\libapreq2\win32\libs # You shouldn't need to change anything below here. BINARY_MODULE = core.dll APREQ_BINARY = apreq.dll # Compiler and linker flags composed from the above settings. CFLAGS = "/I$(LUA_INCDIR)" "/I$(APR_INCDIR)" "/I$(APU_INCDIR)" /D"_CRT_SECURE_NO_DEPRECATE" LFLAGS = "/LIBPATH:$(LUA_LINKDIR)" lua51.lib "/LIBPATH:$(APR_LIBDIR)" libapr-1.lib "/LIBPATH:$(APU_LIBDIR)" libaprutil-1.lib Wldap32.Lib # Names of compiled object files (the individual lines enable automatic # rebasing between git feature branches and the master branch). OBJECTS = src\base64.obj \ src\buffer.obj \ src\crypt.obj \ src\date.obj \ src\dbd.obj \ src\dbm.obj \ src\env.obj \ src\errno.obj \ src\filepath.obj \ src\fnmatch.obj \ src\getopt.obj \ src\http.obj \ src\io_dir.obj \ src\io_file.obj \ src\io_net.obj \ src\io_pipe.obj \ src\ldap.obj \ src\lua_apr.obj \ src\memcache.obj \ src\memory_pool.obj \ src\object.obj \ src\permissions.obj \ src\pollset.obj \ src\proc.obj \ src\serialize.obj \ src\shm.obj \ src\signal.obj \ src\stat.obj \ src\str.obj \ src\thread.obj \ src\thread_queue.obj \ src\time.obj \ src\uri.obj \ src\user.obj \ src\uuid.obj \ src\xlate.obj \ src\xml.obj # Create debug builds by default but enable release builds # using the command line "NMAKE /f Makefile.win RELEASE=1". !IFNDEF RELEASE CFLAGS = $(CFLAGS) /Zi /Fd"core.pdb" /DDEBUG LFLAGS = $(LFLAGS) /debug !ENDIF # Experimental support for HTTP request parsing using libapreq2. CFLAGS = $(CFLAGS) "/I$(APREQ_INCDIR)" /DLUA_APR_HAVE_APREQ=1 LFLAGS = $(LFLAGS) "/LIBPATH:$(APREQ_LIBDIR)" libapreq2.lib # Build the binary module. $(BINARY_MODULE): $(OBJECTS) Makefile @LINK /nologo /dll /out:$@ $(OBJECTS) $(LFLAGS) @IF EXIST $@.manifest MT -nologo -manifest $@.manifest -outputresource:$@;2 # Build the standalone libapreq2 binding. $(APREQ_BINARY): etc\apreq_standalone.c CD etc && CL /W3 /nologo /MD /D"WIN32" /D"LUA_BUILD_AS_DLL" $(CFLAGS) /TC /c apreq_standalone.c LINK /nologo /dll /out:$@ etc\apreq_standalone.obj $(LFLAGS) IF EXIST $@.manifest MT -nologo -manifest $@.manifest -outputresource:$@;2 # Compile individual source code files to object files. $(OBJECTS): Makefile .c.obj: @CL /W3 /nologo /MD /D"WIN32" /D"LUA_BUILD_AS_DLL" $(CFLAGS) /TC /c $< /Fo$@ # Always try to regenerate the error handling module. src\errno.c: etc\errors.lua @LUA etc\errors.lua > src\errno.c.new && MOVE src\errno.c.new src\errno.c || EXIT /B 0 # Install the Lua/APR binding and external dependencies. install: $(BINARY_MODULE) COPY src\apr.lua "$(LUA_SHAREDIR)" IF NOT EXIST "$(LUA_SHAREDIR)\apr" MD "$(LUA_SHAREDIR)\apr" IF NOT EXIST "$(LUA_SHAREDIR)\apr\test" MD "$(LUA_SHAREDIR)\apr\test" COPY test\*.lua "$(LUA_SHAREDIR)\apr\test" IF NOT EXIST "$(LUA_LIBDIR)\apr" MD "$(LUA_LIBDIR)\apr" COPY $(BINARY_MODULE) "$(LUA_LIBDIR)\apr" COPY "$(APR_LIBDIR)\libapr-1.dll" "$(LUA_DIR)" COPY "$(APU_LIBDIR)\libaprutil-1.dll" "$(LUA_DIR)" COPY "$(API_LIBDIR)\libapriconv-1.dll" "$(LUA_DIR)" IF EXIST "$(APREQ_LIBDIR)\libapreq2.dll" COPY "$(APREQ_LIBDIR)\libapreq2.dll" "$(LUA_DIR)" # Remove previously installed files. uninstall: DEL "$(LUA_SHAREDIR)\apr.lua" DEL "$(LUA_SHAREDIR)\apr\test\*.lua" RD "$(LUA_SHAREDIR)\apr\test" RD "$(LUA_SHAREDIR)\apr" DEL "$(LUA_LIBDIR)\apr\$(BINARY_MODULE)" RD "$(LUA_LIBDIR)\apr" DEL "$(LUA_DIR)\libapr-1.dll" DEL "$(LUA_DIR)\libaprutil-1.dll" DEL "$(LUA_DIR)\libapriconv-1.dll" IF EXIST "$(LUA_DIR)\libapreq2.dll" DEL "$(LUA_DIR)\libapreq2.dll" # Run the test suite. test: install LUA -e "require 'apr.test' ()" # Debug the test suite using NTSD. debug: NTSD -g LUA -e "require 'apr.test' ()" # Clean generated files from working directory. clean: DEL $(OBJECTS) $(BINARY_MODULE) core.lib core.exp core.pdb core.ilk core.dll.manifest 2>NUL DEL $(APREQ_BINARY) apreq.lib apreq.exp apreq.pdb apreq.ilk 2>NUL .PHONY: install uninstall test debug clean # vim: ts=4 sw=4 lua-apr-0.23.2.dfsg/NOTES.md000066400000000000000000000112431220664456000153010ustar00rootroot00000000000000# Notes about the Lua/APR binding ## APR documentation The [online API documentation for APR] [api_docs] has been my most useful resource while working on the Lua/APR binding but it leaves something to be desired when you're looking for a high level overview. The following online resources help in this regard: * [God's gift to C] [gift_to_c] is an introductory article to the functionality of APR by [The Register] [register]. * The [libapr tutorial by Inoue Seiichiro] [tutorial] is a useful starting point for writing code. [api_docs]: http://apr.apache.org/docs/apr/trunk/modules.html [gift_to_c]: http://www.theregister.co.uk/2006/04/27/gift_to_c/ [register]: http://www.theregister.co.uk/ [tutorial]: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial.html ## Building APR on Windows Building APR on Windows can be a pain in the ass. It is meant to be done with Microsoft tools but fortunately these are freely available. Here are some notes I made in the process: 1. Install [Microsoft Visual C++ Express] [msvc]. You only need the command line tools, the GUI isn't needed. 2. Install the [Microsoft Platform SDK] [sdk]. The full SDK is over 1 GB but you only need the following: * Microsoft Windows Core SDK * Build environment (x86 32-bit) * Microsoft Web Workshop (IE) SDK * Build environment 3. Download the APR, APR-util, APR-iconv and libapreq2 archives (I used `apr-1.4.2-win32-src.zip`, `apr-util-1.3.9-win32-src.zip`, `apr-iconv-1.2.1-win32-src-r2.zip` and `libapreq2-2.13.tar.gz`) from [apr.apache.org] [apr_homepage] (you can [get libapreq2 here] [apreq_downloads]). Unpack all archives to the same directory and rename the subdirectories to `apr`, `apr-util` and `apr-iconv` (those three are build at the same time while libapreq2 is build separately). 4. *The instructions about [building APR on Windows] [compile_hints] don't work for me so this is where things get sketchy:* Open a Windows SDK command prompt and navigate to the `apr-util` directory. Inside this directory execute `nmake -f Makefile.win buildall`. This doesn't work for me out of the box because of what's probably a bug in the APR-util makefile; I needed to replace `apr_app` with `aprapp` on lines 176 and 177 of `Makefile.win`. After this change `nmake` still exits with errors but nevertheless seems to build `libapr-1.dll` and `libaprutil-1.dll`... 5. You also have to build APREQ, last I tried this was a mess on Windows, I collected some notes at the bottom of this page. [msvc]: http://www.microsoft.com/express/Downloads/#2010-Visual-CPP [sdk]: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK#Obtaining_the_SDK [apr_homepage]: http://apr.apache.org/ [apreq_downloads]: http://www.apache.org/dist/httpd/libapreq/ [compile_hints]: http://apr.apache.org/compiling_win32.html ### Building the SQlite3 database driver on Windows The SQLite 3 driver is included in the [Windows binaries] [win32_binaries] but for the benefit of those who want to build the Apache Portable Runtime on Windows here are the steps involved: 1. Download the [precompiled SQLite 3 binaries For Windows] [sqlite_binaries] (273.98 KiB) and unpack the files somewhere. 2. Create `sqlite3.lib` from `sqlite3.def` (included in the precompiled binaries) using the command `lib /machine:i386 /def:sqlite3.def` and copy `sqlite3.lib` to `apr-util-1.3.9/LibR`. 3. Download the corresponding [source code distribution] [sqlite_sources] (1.20 MiB) and copy `sqlite3.h` to `apr-util-1.3.9/include`. 4. Build the driver in the Windows SDK command prompt using the command `nmake /f apr_dbd_sqlite3.mak`. 5. To install the driver you can copy `sqlite3.dll` and `apr_dbd_sqlite3-1.dll` to Lua's installation directory. [win32_binaries]: http://peterodding.com/code/lua/apr/downloads/lua-apr-0.20-win32.zip [sqlite_binaries]: http://www.sqlite.org/sqlite-dll-win32-x86-3070400.zip [sqlite_sources]: http://www.sqlite.org/sqlite-preprocessed-3070400.zip ### Building `libapreq2` on Windows I wasted a few hours getting `libapreq2` version 2.13 to build on Windows because of the following issues: * The included makefile `libapreq2.mak` is full of syntax errors. * The makefile unconditionally includes the Apache module and consequently doesn't link without a full Apache build. * The build environment requires a specific flavor of Perl which I haven't gotten to work. Eventually I decided to just rewrite the damned makefile and be done with it, enabling me to finally test the HTTP request parsing module on Windows (all tests passed the first time). I've included the [customized makefile] [apreq_makefile] in the Lua/APR git repository. [apreq_makefile]: https://github.com/xolox/lua-apr/blob/master/etc/win32-bootstrap/libapreq2.mak lua-apr-0.23.2.dfsg/README.md000066400000000000000000000226771220664456000153630ustar00rootroot00000000000000# Apache Portable Runtime binding for Lua [Lua/APR][homepage] is a binding of the [Apache Portable Runtime][wp_apr] (APR) for the [Lua programming language][wp_lua]. APR powers software such as the Apache webserver and Subversion and Lua/APR makes the APR operating system interfaces available to Lua, serving as an extended standard library. Thus far the following modules have been implemented (the following links take you straight to the relevant documentation): [homepage]: http://peterodding.com/code/lua/apr/ [wp_apr]: http://en.wikipedia.org/wiki/Apache_Portable_Runtime [wp_lua]: http://en.wikipedia.org/wiki/Lua_(programming_language) * [Base64 encoding](http://peterodding.com/code/lua/apr/docs/#base64_encoding) * [Cryptography routines](http://peterodding.com/code/lua/apr/docs/#cryptography_routines) * [Date parsing](http://peterodding.com/code/lua/apr/docs/#date_parsing) * [Relational database drivers](http://peterodding.com/code/lua/apr/docs/#relational_database_drivers) * [DBM routines](http://peterodding.com/code/lua/apr/docs/#dbm_routines) * [Environment manipulation](http://peterodding.com/code/lua/apr/docs/#environment_manipulation) * [File path manipulation](http://peterodding.com/code/lua/apr/docs/#file_path_manipulation) * [Filename matching](http://peterodding.com/code/lua/apr/docs/#filename_matching) * [Directory manipulation](http://peterodding.com/code/lua/apr/docs/#directory_manipulation) * [File I/O handling](http://peterodding.com/code/lua/apr/docs/#file_i_o_handling) * [Network I/O handling](http://peterodding.com/code/lua/apr/docs/#network_i_o_handling) * [Pipe I/O handling](http://peterodding.com/code/lua/apr/docs/#pipe_i_o_handling) * [Memcached client](http://peterodding.com/code/lua/apr/docs/#memcached_client) * [Command argument parsing](http://peterodding.com/code/lua/apr/docs/#command_argument_parsing) * [HTTP request parsing](http://peterodding.com/code/lua/apr/docs/#http_request_parsing) * [LDAP connection handling](http://peterodding.com/code/lua/apr/docs/#ldap_connection_handling) * [Process handling](http://peterodding.com/code/lua/apr/docs/#process_handling) * [Pollset module](http://peterodding.com/code/lua/apr/docs/#pollset) * [Shared memory](http://peterodding.com/code/lua/apr/docs/#shared_memory) * [Signal handling](http://peterodding.com/code/lua/apr/docs/#signal_handling) * [String routines](http://peterodding.com/code/lua/apr/docs/#string_routines) * [Multi threading](http://peterodding.com/code/lua/apr/docs/#multi_threading) * [Thread queues](http://peterodding.com/code/lua/apr/docs/#thread_queues) * [Time routines](http://peterodding.com/code/lua/apr/docs/#time_routines) * [Uniform resource identifier parsing](http://peterodding.com/code/lua/apr/docs/#uniform_resource_identifier_parsing) * [User/group identification](http://peterodding.com/code/lua/apr/docs/#user_group_identification) * [Universally unique identifiers](http://peterodding.com/code/lua/apr/docs/#universally_unique_identifiers) * [Character encoding translation](http://peterodding.com/code/lua/apr/docs/#character_encoding_translation) * [XML parsing](http://peterodding.com/code/lua/apr/docs/#xml_parsing) ## How to get and install the binding You can find the source code of the most recently released version under [downloads][srcdl]. The source code is also available online in the [GitHub repository][github]. There are [Windows binaries][winbin] available that have been tested with [Lua for Windows][lfw] v5.1.4-40 and there is an offical Debian Linux package. You can also build the Lua/APR binding yourself using the instructions below. [srcdl]: http://peterodding.com/code/lua/apr/downloads [github]: http://github.com/xolox/lua-apr [winbin]: http://peterodding.com/code/lua/apr/downloads/lua-apr-0.23.1-win32.zip [lfw]: http://code.google.com/p/luaforwindows/ ### Install using Debian package The Lua/APR binding has an official Debian package which is available in [wheezy (testing)] [wheezy], [sid (unstable)] [sid] and Ubuntu [Oneiric Ocelot (11.10)] [oneiric]. If you are running any of those (or a newer release) the following commands should get you started: $ apt-get install liblua5.1-apr1 $ lua -e "require 'apr.test' ()" If you are running an older Debian release or a derivative of Debian which doesn't have the official package yet, you may be able to download and install one of the Debian packages manually from one of the three pages linked above. [wheezy]: http://packages.debian.org/source/wheezy/lua-apr [sid]: http://packages.debian.org/source/sid/lua-apr [oneiric]: http://packages.ubuntu.com/source/oneiric/lua-apr ### Build on UNIX using LuaRocks The easiest way to download, build and install the Lua/APR binding is to use [LuaRocks] [lr]. The following commands will install the Lua/APR binding from the main repository and run the test suite to make sure everything works: $ luarocks install lua-apr $ lua -e "require 'apr.test' ()" If LuaRocks fails to build the Lua/APR binding this is likely because of missing dependencies. Lua/APR depends on the APR, APR-util and libapreq2 system libraries but LuaRocks cannot install these because it only deals with Lua modules. When the build fails the makefile runs a Lua script that knows how to detect missing dependencies on Debian, Ubuntu, Arch Linux, Red Hat, Fedora Core, Suse Linux and CentOS. As a general guideline for other systems and package managers, you'll need the binary and development packages of Lua 5.1, APR, APR-util and libapreq2. The latest rockspec and sources are also available from the author's website (in case the main LuaRocks repository is unavailable or lagging behind): $ luarocks install http://peterodding.com/code/lua/apr/downloads/lua-apr-0.23.1-1.rockspec If you have git installed you can also download and install the latest sources directly from [GitHub] [github]: $ luarocks install http://peterodding.com/code/lua/apr/downloads/lua-apr-scm-1.rockspec [lr]: http://luarocks.org/ ### Build on UNIX using makefile If you don't have LuaRocks installed the following shell commands should help you get started on UNIX: $ if which git; then # Get the latest sources using `git'? $ git clone git://github.com/xolox/lua-apr.git $ else # Or get the most recently released archive using `wget'. $ wget http://peterodding.com/code/lua/apr/downloads/lua-apr-0.23.1-1.zip $ unzip lua-apr-0.23.1-1.zip $ mv lua-apr-0.23.1-1 lua-apr $ fi $ cd lua-apr $ sudo make install # installs apr.lua and apr/core.so in /usr/local $ lua -e "require 'apr.test' ()" # runs the test suite The makefile creates a debug build by default. Use `sudo make install DO_RELEASE=1` to create a release build instead. Just be sure to run `make clean` when switching between debug/release mode to avoid linking incompatible object files. ### Build on Windows using makefile A makefile for Microsoft Windows is included in the repository. It has been tested on Windows XP with `NMAKE` from the free [Microsoft Visual C++ Express][msvc] 2010 tool chain. If you don't have git installed you can [download the latest sources][autozip] directly from GitHub as a ZIP file. At the top of the makefile several file locations are defined, you'll need to change these to match your system. The makefile creates a debug build by default. Use `NMAKE /f Makefile.win DO_RELEASE=1` to create a release build instead. Just be sure to run `NMAKE /f Makefile.win clean` when switching between debug/release mode to avoid linking incompatible object files. Please note that the Windows makefile only builds the Lua/APR binding, you need to build the APR, APR-util and APREQ libraries yourself. There are instructions available on [how to build APR/APR-util on apache.org][apr_build] but [my notes on the process][notes] may be a more useful starting point. I've also recently created a Windows batch script that bootstraps a Lua/APR development environment by downloading, unpacking, patching and building the libraries involved. To use it, download the [ZIP archive][bootstrap_zip], unpack it to a directory, open a Windows SDK command prompt in the directory where you unpacked the ZIP archive and execute `make.cmd`. I've only tested it on a 32 bit Windows XP virtual machine, but even if it doesn't work out of the box for you it may provide a useful starting point. [msvc]: http://www.microsoft.com/express/Downloads/#2010-Visual-CPP [autozip]: http://github.com/xolox/lua-apr/zipball/master [apr_build]: http://apr.apache.org/compiling_win32.html [notes]: https://github.com/xolox/lua-apr/blob/master/NOTES.md#readme [bootstrap_zip]: http://peterodding.com/code/lua/apr/downloads/win32-bootstrap.zip ## Status The following functionality has not been implemented yet but is on the to-do list: * **Encrypted network communication** (unfortunately this isn't provided by APR so [io\_net.c][io_net] could get messy…) [io_net]: https://github.com/xolox/lua-apr/blob/master/src/io_net.c ## Contact If you have questions, bug reports, suggestions, etc. the author can be contacted at . The latest version is available at and . ## License This software is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License). © 2011 Peter Odding () and zhiguo zhao (). The LDAP connection handling module is based on LuaLDAP, designed and implemented by Roberto Ierusalimschy, André Carregal and Tomás Guisasola. © 2003-2007 The Kepler Project. lua-apr-0.23.2.dfsg/TODO.md000066400000000000000000000036151220664456000151620ustar00rootroot00000000000000# To-do list for the Lua/APR binding ## New features * **Encrypted network communication**. It appears that APR itself doesn't support this but clearly it's possible because there are dozens of projects that use APR and support encrypted network communication (the [Apache HTTP server] [httpd], [ApacheBench] [ab], [Tomcat] [tomcat], etc.) * Make it possible to enable text mode for files, pipes and sockets on platforms where there is no distinction between text/binary mode (because `CR` + `LF` → `LF` translation can be useful on UNIX as well) [httpd]: http://en.wikipedia.org/wiki/Apache_HTTP_Server [ab]: http://en.wikipedia.org/wiki/ApacheBench [tomcat]: http://en.wikipedia.org/wiki/Apache_Tomcat ## Known problems * Find out why **`apr.xlate()` doesn't work on Windows** (I can't seem to get `apr_iconv` working on Windows) * Zhiguo Zhao mentioned that he's using `apr.xlate()` on Windows using the original `libiconv` instead of `apr_iconv` (see [issue #11] [issue_11]) * Investigate **escaping problem in `apr_proc_create()`** as found by the test for the `apr.namedpipe_create()` function (see `etc/tests.lua` around line 625) * Why is the DBD `LD_PRELOAD` trick needed?! [More information] [dbd_trick] [issue_11]: https://github.com/xolox/lua-apr/issues/11#issuecomment-2888555 [dbd_trick]: https://answers.launchpad.net/ubuntu/+source/apr-util/+question/143914 ## Anything else? * Propose the [libapreq2 binding] [apreq_binding] for inclusion as the official Lua language binding of [libapreq2] [libapreq2]? (first make the binding a lot more complete) * [Maybe][atexit] I shouldn't be using `atexit()` to call `apr_terminate()`? (BTW the whole linked blog post is interesting, as is the follow-up post) [apreq_binding]: https://github.com/xolox/lua-apr/blob/master/src/http.c [libapreq2]: http://httpd.apache.org/apreq/ [atexit]: http://davidz25.blogspot.com/2011/06/writing-c-library-part-1.html lua-apr-0.23.2.dfsg/benchmarks/000077500000000000000000000000001220664456000162035ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/benchmarks/file_io.lua000077500000000000000000000072761220664456000203330ustar00rootroot00000000000000#!/usr/bin/env lua --[[ Benchmarks of the different formats supported by file:read() as implemented in the Lua standard library vs. the Lua/APR binding. Requires gnuplot to generate graphs in PNG format. See http://peterodding.com/code/lua/apr/benchmarks for examples of the generated graphs. --]] local apr = require 'apr' local function msg(...) io.stderr:write(string.format(...), '\n') end local formats = {{ format = '*a', graph = 'file-read-all.png', title = "Performance of file:read('*a')", generate = function(size) local random = io.open('/dev/urandom') local data = random:read(math.min(size, 1024 * 512)) random:close() if #data < size then data = data:rep(size / #data) end return data end, }, { format = '*l', graph = 'file-read-lines.png', title = "Performance of file:read('*l')", generate = function(size) -- Generate a line with random printable characters. local line = {} local char = string.char local random = math.random for i = 1, 512 do line[#line + 1] = char(random(0x20, 0x7E)) end line = table.concat(line) -- Generate a few lines of random lengths. local lines = {} local count = 0 while #lines < 100 do local cline = line:sub(1, math.random(1, #line)) lines[#lines + 1] = cline size = size + #cline end lines = table.concat(lines, '\n') -- Now generate the requested size in lines. return lines:rep(size / #lines) end, }, { format = '*n', graph = 'file-read-numbers.png', title = "Performance of file:read('*n')", generate = function(size) local numbers = {} for i = 1, 100 do numbers[#numbers + 1] = tostring(math.random()) end numbers = table.concat(numbers, '\n') return numbers:rep(size / #numbers) end, }} local function benchformat(func, path, format, size, label) local best for i = 1, 2 do local start = apr.time_now() local handle = func(path) repeat local result = handle:read(format) until format == '*a' and result == '' or not result handle:close() local total = apr.time_now() - start msg('%17s: read %s with file:read(%s) at %s/s', label, apr.strfsize(size), format, apr.strfsize(size / total)) best = best and best < total and best or total end return { time = best, size = size / 1024 / 1024 } end local function writeresults(fname, data) local handle = io.open(fname, 'w') for _, sample in ipairs(data) do handle:write(sample.size, ' ', sample.time, '\n') end handle:close() end local datafile = os.tmpname() .. '.bin' local luafile = os.tmpname() .. '.dat' local aprfile = os.tmpname() .. '.dat' for _, format in ipairs(formats) do local luatimes = {{ time = 0, size= 0 }} local aprtimes = {{ time = 0, size= 0 }} local size = 1024 * 1024 local max = 1024 * 1024 * 25 local data = format.generate(max) while size <= max do local handle = io.open(datafile, 'w') handle:write(data:sub(1, size)) handle:close() table.insert(luatimes, benchformat(io.open, datafile, format.format, size, "Standard library")) table.insert(aprtimes, benchformat(apr.file_open, datafile, format.format, size, "Lua/APR")) size = size + 1024 * 1024 end writeresults(luafile, luatimes) writeresults(aprfile, aprtimes) local gnuplot = io.popen('gnuplot', 'w') gnuplot:write(string.format([[ set title "%s" set xlabel "size in megabytes" set ylabel "time in seconds" set term png set output '%s' plot '%s' with lines lt 3 title "Lua standard library", \ '%s' with lines lt 4 title "Lua/APR binding" ]], format.title, format.graph, luafile, aprfile)) gnuplot:close() end os.remove(datafile) os.remove(luafile) os.remove(aprfile) lua-apr-0.23.2.dfsg/benchmarks/webservers.cmd000066400000000000000000000015231220664456000210600ustar00rootroot00000000000000@ECHO OFF REM This is a batch script to benchmark the example webservers included in the REM Lua/APR binding on Windows platforms. This script uses "ab.exe" (ApacheBench). SET SECONDS=5 SET THREADS=4 REM Benchmark the single threaded webserver. SET PORT=%RANDOM% START lua ../examples/webserver.lua %PORT% lua -e "require('apr').sleep(5)" ab.exe -q -t%SECONDS% http://localhost:%PORT%/ ECHO Finished test 1 REM Benchmark the multi threaded webserver with several thread pool sizes. REM FOR /l %%i in (1, 1, %THREADS%) DO ECHO %%i FOR /l %%I in (1, 1, %THREADS%) DO CALL :THREADED_TEST %%I GOTO :EOF :THREADED_TEST ECHO Starting test %1 SET PORT=%RANDOM% START lua ../examples/threaded-webserver.lua %1 %PORT% lua -e "require('apr').sleep(5)" ECHO ON ab.exe -q -t%SECONDS% -c%1 http://localhost:%PORT%/ @ECHO OFF ECHO. GOTO :EOF lua-apr-0.23.2.dfsg/benchmarks/webservers.sh000077500000000000000000000020541220664456000207320ustar00rootroot00000000000000#!/bin/bash # This is a Bash script to benchmark the example webservers included in the # Lua/APR binding on UNIX platforms. This script uses "ab" (ApacheBench). # Note that the last request sent by ApacheBench may be terminated prematurely # because of the "ab -t" option. In other words, don't worry about the sporadic # error message just before or after ApacheBench reports its results. SECONDS=5 # Number of seconds to run each benchmark. THREADS=4 # Number of threads to test. # Benchmark the single threaded webserver. PORT=$((($RANDOM % 30000) + 1000)) lua ../examples/webserver.lua $PORT & disown PID=$! sleep 5 ab -q -t$SECONDS http://localhost:$PORT/ | grep 'Requests per second\|Transfer rate' kill $PID echo # Benchmark the multi threaded webserver with several thread pool sizes. for ((i=1; $i<=$THREADS; i+=1)); do PORT=$((($RANDOM % 30000) + 1000)) lua ../examples/threaded-webserver.lua $i $PORT & disown PID=$! sleep 5 ab -q -t$SECONDS -c$i http://localhost:$PORT/ | grep 'Requests per second\|Transfer rate' kill $PID echo done lua-apr-0.23.2.dfsg/etc/000077500000000000000000000000001220664456000146415ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/etc/apreq_standalone.c000066400000000000000000000042571220664456000203350ustar00rootroot00000000000000/* Standalone libapreq2 binding based on the Lua/APR binding. * * Author: Peter Odding * Last Change: February 27, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * This file transforms the HTTP request parsing module for the Lua/APR binding * into a standalone binding to libapreq2, making it a lighter dependency for * other web projects. */ #include "../src/lua_apr.h" /* Make memory_pool.c use separate memory pool for standalone APREQ module. */ #undef LUA_APR_POOL_MT #define LUA_APR_POOL_MT "APREQ memory pool type" #undef LUA_APR_POOL_KEY #define LUA_APR_POOL_KEY "APREQ memory pool instance" #define APREQ_STANDALONE /* Dependencies copied from Lua/APR. */ int status_to_message(lua_State *L, apr_status_t status) { char message[LUA_APR_MSGSIZE]; apr_strerror(status, message, count(message)); lua_pushstring(L, message); return 1; } int push_error_status(lua_State *L, apr_status_t status) { lua_pushnil(L); status_to_message(L, status); status_to_name(L, status); return 3; } #include "../src/errno.c" #include "../src/memory_pool.c" #include "../src/http.c" /* Module loader. */ /* Used to make sure that APR is only initialized once. */ static int apr_was_initialized = 0; LUA_APR_EXPORT int luaopen_apreq(lua_State *L) { apr_status_t status; /* The Lua/APR binding probably isn't loaded which makes the APREQ binding * responsible for correctly initializing the Apache Portable Runtime. */ if (!apr_was_initialized) { if ((status = apr_initialize()) != APR_SUCCESS) raise_error_status(L, status); if (atexit(apr_terminate) != 0) raise_error_message(L, "APREQ: Failed to register apr_terminate()"); apr_was_initialized = 1; } /* Create the memory pool for APREQ functions and install a __gc metamethod * to destroy the memory pool when the Lua state is closed. */ to_pool(L); /* Create and return the module table. */ lua_newtable(L); # define push_libfun(f) \ lua_pushcfunction(L, lua_apr_ ## f); \ lua_setfield(L, -2, #f) push_libfun(parse_headers); push_libfun(parse_multipart); push_libfun(parse_cookie_header); push_libfun(parse_query_string); return 1; } lua-apr-0.23.2.dfsg/etc/buildbot.lua000066400000000000000000000136151220664456000171560ustar00rootroot00000000000000#!/usr/bin/env lua --[[ Multi platform build bot for the Lua/APR binding. Author: Peter Odding Last Change: November 13, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script makes it easier for me to build and test the Lua/APR binding on multiple platforms simultaneously. In its simplest form this script builds the Lua/APR binding, copies the installation files to a temporary directory and runs the test suite inside this temporary directory. The script can also be started in server mode where it will wait for another build bot that commands it over TCP to run a build and report the results. I start this script in server mode in a Windows XP virtual machine, then more or less forget about the virtual machine and just run the build bot from my Ubuntu Linux host environment, where it reports the build and test results from both my Linux and Windows environments :-) The following issues influenced the design of this build bot (I came up with these after finding out the hard way every variation that didn't work out): * On Windows the build bot can't run "make install" because the build bot itself uses the Lua/APR binding and on Windows it is impossible to overwrite dynamic link libraries while they're in use :-\ * On UNIX the build bot can be run from a low privilege account because "make install" is no longer needed. This makes it easier to run the build bot from a web hook (for example) Note that this script uses the Lua/APR binding so you'll need to run "make install" or similar at least once before trying to run this script. --]] local apr = require 'apr' local serverport = 38560 local projectdir = assert(apr.filepath_get()) local builddir = projectdir .. '/build' local libext = apr.platform_get() == 'WIN32' and 'dll' or 'so' local libname = 'core.' .. libext local buildfiles = { [libname] = 'apr/' .. libname, ['src/apr.lua'] = 'apr.lua', ['src/serialize.lua'] = 'apr/serialize.lua', ['test'] = 'apr/test', } local usage = [[ Usage: buildbot [OPTS] --local build and test on this machine --remote=IP build and test on a remote machine --server become a server, waiting for commands --port=NR port number for server build bot ]] function main() -- {{{1 local opts, args = apr.getopt(usage) local did_something = false if opts['local'] then for line in local_build() do printf('%s', line) end did_something = true end if opts.remote then remote_build(opts.remote, serverport or opts.port) did_something = true end if opts.server then start_server(serverport or opts.port) did_something = true end if not did_something then io.write(usage) end end function local_build() -- {{{1 -- Create a binary for the current platform using a makefile. return coroutine.wrap(function() local started = apr.time_now() local platform = apr.platform_get() coroutine.yield("Building on " .. platform .. " ..") local build = assert(io.popen(platform ~= 'WIN32' and 'make --no-print-directory 2>&1' or 'nmake /nologo /f Makefile.win 2>&1')) for line in build:lines() do coroutine.yield(line) end create_env() run_tests() printf("\nFinished local build in %.2f seconds!\n", apr.time_now() - started) end) end function create_env() -- {{{1 -- Create or update the virtual environment. for source, target in pairs(buildfiles) do source = projectdir .. '/' .. source target = builddir .. '/' .. target if apr.stat(source, 'type') ~= 'directory' then copy_file(source, target) else local directory = assert(apr.dir_open(source)) for entry in directory:entries 'name' do if entry:find '%.lua$' then copy_file(source .. '/' .. entry, target .. '/' .. entry) end end assert(directory:close()) end end end function create_dir(path) -- {{{2 -- Create directories in virtual environment automatically. if apr.stat(path, 'type') ~= 'directory' then assert(apr.dir_make_recursive(path)) end end function copy_file(source, target) -- {{{2 -- Copy changed files to the virtual environment. if apr.stat(source, 'mtime') ~= apr.stat(target, 'mtime') then create_dir(apr.filepath_parent(target)) assert(apr.file_copy(source, target)) end end function run_tests() -- {{{1 -- Run the test suite in the virtual environment. local pathsep = package.config:sub(3, 3) assert(apr.env_set('LUA_PATH', builddir .. '/?.lua' .. pathsep .. builddir .. '/?/init.lua')) assert(apr.env_set('LUA_CPATH', builddir .. '/?.' .. libext)) assert(apr.env_set('LD_PRELOAD', '/lib/libSegFault.so')) local testsuite = assert(io.popen [[ lua -e "require 'apr.test' ()" 2>&1 ]]) for line in testsuite:lines() do coroutine.yield(line) end assert(testsuite:close()) end function start_server(port) -- {{{1 -- Open a TCP server socket and wait for commands from another build bot. local server = assert(apr.socket_create('tcp', 'inet')) local localhost = apr.host_to_addr(apr.hostname_get()) assert(server:bind('*', port)) assert(server:listen(1)) while true do printf("Build bot listening on %s:%i ..", localhost, port) local client = assert(server:accept()) for line in local_build() do printf('%s', line) client:write(line, '\n') end assert(client:close()) printf "Finished build .." end end function remote_build(host, port) -- {{{1 -- Command a remote build bot to perform a build and report its results. local started = apr.time_now() local socket = assert(apr.socket_create('tcp', 'inet')) assert(socket:connect(host, port)) for line in socket:lines() do printf('%s', line) end assert(socket:close()) printf("\nFinished remote build in %.2f seconds!\n", apr.time_now() - started) end function printf(...) -- {{{1 io.stderr:write(string.format(...), '\n') io.stderr:flush() end -- }}} main() lua-apr-0.23.2.dfsg/etc/docs.lua000066400000000000000000000447731220664456000163130ustar00rootroot00000000000000--[[ Documentation generator for the Lua/APR binding. Author: Peter Odding Last Change: December 6, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT ]] -- Files containing documentation fragments (the individual lines enable -- automatic rebasing between git feature branches and the master branch). local SOURCES = [[ base64.c crypt.c date.c dbd.c dbm.c env.c filepath.c fnmatch.c io_dir.c io_file.c io_net.c io_pipe.c ldap.c memcache.c getopt.c http.c pollset.c proc.c shm.c signal.c str.c thread.c thread_queue.c time.c uri.c user.c uuid.c xlate.c xml.c serialize.c apr.lua lua_apr.c permissions.c errno.c ../examples/download.lua ../examples/webserver.lua ../examples/threaded-webserver.lua ../examples/async-webserver.lua ]] local modules = {} local sorted_modules = {} local fmt = string.format local function trim(s) return s:match '^%s*(.-)%s*$' end local function getmodule(name, file, header) local key = name:lower() local value = modules[key] if not value then local metadata, newheader = (header .. '\n\n'):match '\n\n(.-)\n\n(.-)$' -- strip metadata header = (newheader or ''):find '%S' and trim(newheader) or nil value = {name=name, file=file, header=header, functions={}} modules[key] = value table.insert(sorted_modules, value) end return value end local function message(...) io.stderr:write(fmt(...), '\n') end local function stripfoldmarker(s) return trim(s:gsub('{{%{%d', '')) end local function stripcomment(s) return trim(s:gsub('\n %* ?', '\n')) end local shareddocs = { -- file:read() {{{1 ['file:read'] = [[ _This function implements the interface of the [file:read()] [fread] function described in the Lua 5.1 reference manual. Here is the description from the reference manual:_ Read from file, according to the given formats, which specify what to read. For each format, the function returns a string (or a number) with the characters read, or nil if it cannot read data with the specified format. When called without formats, it uses a default format that reads the entire next line (see below). The available formats are: - `'*n'`: reads a number; this is the only format that returns a number instead of a string - `'*a'`: reads all data from the file, starting at the current position. On end of input, it returns the empty string - `'*l'`: reads the next line (skipping the end of line), returning nil on end of input (this is the default format) - `number`: reads a string with up to this number of characters, returning nil on end of input. If number is zero, it reads nothing and returns an empty string, or nil on end of input [fread]: http://www.lua.org/manual/5.1/manual.html#pdf-file:read ]], -- file:write() {{{1 ['file:write'] = [[ _This function implements the interface of the [file:write()] [fwrite] function described in the Lua 5.1 reference manual. Here is the description from the reference manual:_ Write the value of each argument to file. The arguments must be strings or numbers. To write other values, use `tostring()` or `string.format()` before this function. [fwrite]: http://www.lua.org/manual/5.1/manual.html#pdf-file:write ]], -- file:seek() {{{1 ['file:seek'] = [[ _This function implements the interface of the [file:seek()] [fseek] function described in the Lua 5.1 reference manual. Here is the description from the reference manual:_ Sets and gets the file position, measured from the beginning of the file, to the position given by @offset plus a base specified by the string @whence, as follows: - `'set'`: base is position 0 (beginning of the file) - `'cur'`: base is current position - `'end'`: base is end of file In case of success, function `seek` returns the final file position, measured in bytes from the beginning of the file. If this function fails, it returns nil, plus a string describing the error. The default value for @whence is `'cur'`, and for offset is 0. Therefore, the call `file:seek()` returns the current file position, without changing it; the call `file:seek('set')` sets the position to the beginning of the file (and returns 0); and the call `file:seek('end')` sets the position to the end of the file, and returns its size. [fseek]: http://www.lua.org/manual/5.1/manual.html#pdf-file:seek ]], -- file:lines() {{{1 ['file:lines'] = [[ _This function implements the interface of the [file:lines()] [flines] function described in the Lua 5.1 reference manual. Here is the description from the reference manual:_ Return an iterator function that, each time it is called, returns a new line read from the file. Therefore, the construction for line in file:lines() do body end will iterate over all lines. This function does not close the file when the loop ends. [flines]: http://www.lua.org/manual/5.1/manual.html#pdf-file:lines ]], -- }}}1 } -- Extract test coverage statistics from gcov. {{{1 -- XXX The gcov invocation below used to work fine with multiple source code -- files (gcov -f *.c) but at some point it broke?! Therefor I've now resorted -- to running gcov once for each C source code file. local coverage = {} for filename in SOURCES:gmatch '%S+' do if filename:find '%.c$' and filename ~= 'errno.c' then local gcov = assert(io.popen('gcov -o src -nf ' .. filename .. ' 2>/dev/null')) local cfun local count = 0 for line in gcov:lines() do local test = line:match "^Function '(.-)'$" if test then cfun = test elseif cfun then local value = tonumber(line:match "^Lines executed:%s*(%d+%.?%d*)%% of %d+$") if value then coverage[cfun] = value count = count + 1 cfun = nil end end end assert(gcov:close()) end end -- Parse documentation comments in C and Lua source code files. {{{1 local function mungedesc(signature, description) local sname = description:match "This function implements the interface of Lua's `([^`]+)%(%)` function." if sname and shareddocs[sname] then local oldtype = sname:match '^(%w+)' local newtype = signature:match '^%s*(%w+)' local firstline, otherlines = shareddocs[sname]:match '^(.-)\n\n(.+)$' local otherlines, lastline = otherlines:match '^(.+)\n\n(.-)$' if newtype == 'shm' then otherlines = otherlines:gsub('file:seek', 'shm:seek') otherlines = otherlines:gsub('@file', '@shm') otherlines = otherlines:gsub('file', 'shared memory') end otherlines = otherlines:gsub(oldtype, newtype) description = firstline .. '\n\n' .. otherlines .. '\n\n' .. lastline end return description end for filename in SOURCES:gmatch '%S+' do local handle = assert(io.open('src/' .. filename)) local source = assert(handle:read('*all')):gsub('\r\n', '\n') handle:close() if filename:find '%.c$' then -- Don't extract documentation from ignored C source code. source = source:gsub('\n#if 0.-\n#endif', '') local header = stripcomment(source:match '^/%*(.-)%*/' or '') local modulename = header:match '^([^\n]-) module' if not modulename then message("%s: Failed to determine module name!", filename) end local module = getmodule(modulename, filename, header) local pattern = '\n/%*([^\n]-%->.-)%*/\n\n%w[^\n]- ([%w_]+)%([^\n]-%)\n(%b{})' for docblock, funcname, funcbody in source:gmatch(pattern) do local signature, description = docblock:match '^([^\n]- %-> [^\n]+)(\n.-)$' if signature then description = mungedesc(signature, description) local by = funcbody:find 'luaL_checklstring' or funcbody:find 'datum_check' or funcbody:find 'lua_pushlstring' local bn = funcbody:find 'luaL_checkstring' or funcbody:find 'lua_tostring' or funcbody:find 'luaL_optstring' or funcbody:find 'lua_pushstring' local binarysafe; if by and not bn then binarysafe = true elseif bn then binarysafe = false end table.insert(module.functions, { signature = stripfoldmarker(signature), description = stripcomment(description), binarysafe = binarysafe }) end end elseif not filename:find '[\\/]examples[\\/]' then local pattern = '\n(\n%-%- (apr%.[%w_]+)%(.-\n%-%-[^\n]*)\n\n' for docblock, funcname in source:gmatch(pattern) do docblock = trim(docblock:gsub('\n%-%- ?', '\n')) local signature, description = docblock:match '^([^\n]- %-> [^\n]+)(\n.-)$' if not signature then message("%s: Function %s doesn't have a signature!", filename, funcname) else local text, modulename = description:match '^(.-)\nPart of the "(.-)" module%.$' local module = getmodule(modulename, filename) table.insert(module.functions, { signature = stripfoldmarker(signature), -- strip Vim fold markers description = text or description }) end end else local header, modulename, example = source:match '^%-%-%[%[%s+(([^\n]+).-)%]%]\n(.-)$' modulename = trim(modulename) header = trim(header:gsub('\n ', '\n')) getmodule(modulename, filename, header).example = trim(example) end end -- Convert documentation comments to Markdown hypertext. {{{1 local function findrelease() for line in io.lines 'src/apr.lua' do local version = line:match "^apr%._VERSION = '(.-)'" if version then return version end end assert(false, "Failed to determine Lua/APR version number!") end local blocks = { trim([[ # Lua/APR binding documentation The [Lua/APR binding] [homepage] aims to bring most of the functionality in the [Apache Portable Runtime (APR)] [apr_wiki] to the small and flexible [programming language Lua] [lua_wiki]. This document contains the documentation for the Lua/APR binding. Some notes about this documentation: - Most of the documentation is based on the [official APR documentation] [apr_docs] but I've had to consult the APR source code here and there when the official documentation didn't suffice. If anything seems amiss [please let me know](mailto:peter@peterodding.com). - The entries for all functions are automatically generated from the C and Lua source code of the binding to prevent that documentation and implementation become out of sync. *This document was generated from the Lua/APR **]] .. findrelease() .. [[** source code.* [homepage]: http://peterodding.com/code/lua/apr/ [apr_wiki]: http://en.wikipedia.org/wiki/Apache_Portable_Runtime [lua_wiki]: http://en.wikipedia.org/wiki/Lua_%28programming_language%29 [apr_docs]: http://apr.apache.org/docs/apr/trunk/modules.html ]]) } function blocks:add(template, ...) self[#self+1] = fmt(template, ...) end local function toanchor(s) s = s:lower() s = s:gsub('[^a-z0-9_.:]+', '_') s = s:gsub('example:_', 'example_') return s end local function sig2pubfun(s) if s:find '^#result_set' then return 'result_set:__len' else return s:match '^[%w_.:]+' end end local function sig2privfun(s) if s:find '^#' then return s:gsub('^#result_set.-$', 'dbr_len') else s = s:match '^[%w_.:]+' s = s:gsub('%W', '_') s = s:gsub('^directory_', 'dir_') s = s:gsub('^process_', 'proc_') s = s:gsub('^driver_', 'dbd_') s = s:gsub('^prepared_statement_', 'dbp_') s = s:gsub('^result_set_', 'dbr_') s = s:gsub('^xml_parser_', 'xml_') s = s:gsub('^mc_client_', 'mc_') s = s:gsub('^ldap_conn', 'lua_apr_ldap') return s end end local function gsplit(string, pattern, capture_delimiters) return coroutine.wrap(function() local index = 1 repeat local first, last = string:find(pattern, index) if first and last then if index < first then coroutine.yield(string:sub(index, first - 1)) end if capture_delimiters then coroutine.yield(string:sub(first, last)) end index = last + 1 else if index <= #string then coroutine.yield(string:sub(index)) end break end until index > #string end) end local function preprocess(text) local output = {} for block in gsplit(text, '\n\n', false) do output[#output + 1] = block:find '^ ' and block or (block :gsub('@permissions', '[permissions](#file_system_permissions)') :gsub('error handling', '[error handling](#error_handling)') :gsub('(%s)@([%w_]+)', '%1*%2*') :gsub('([%s])true([%s%p])', '%1*true*%2') :gsub('([%s%p])false([%s%p])', '%1*false*%2') :gsub('([%s%p])nil([%s%p])', '%1*nil*%2') :gsub('`([%w_.:]+)%(%)`', function(funcname) local target if funcname:find '^apr%.[%w_]+$' or funcname:find '^[%w_]+:[%w_]+$' then target = '#' .. toanchor(funcname) else target = 'http://www.lua.org/manual/5.1/manual.html#pdf-' .. funcname end return fmt('[%s()](%s)', funcname:gsub('_', '\\_'), target) end)) end return table.concat(output, '\n\n') end blocks:add '## Table of contents' local lines = { '
' } local misc_entries = {} for _, module in ipairs(sorted_modules) do if not module.functions[1] then table.insert(misc_entries, module) else lines[#lines + 1] = fmt('
%s
', toanchor(module.name), module.name) lines[#lines + 1] = '
    ' for _, entry in ipairs(module.functions) do local signature = entry.signature:match '^#?[%w.:_]+' local anchor = toanchor(sig2pubfun(signature)) if not signature:find '#' then signature = signature .. '()' end lines[#lines + 1] = fmt('
  • %s
  • ', anchor, signature) end lines[#lines + 1] = '

' -- lines[#lines + 1] = '' -- blocks:add('%s', table.concat(lines, '\n')) end end lines[#lines + 1] = '
Miscellaneous sections
' lines[#lines + 1] = '
    ' for _, module in ipairs(misc_entries) do lines[#lines + 1] = fmt('
  • %s
  • ', toanchor(module.name), module.name) end lines[#lines + 1] = '
' lines[#lines + 1] = '
' blocks:add('%s', table.concat(lines, '\n')) local bsignore = { ['apr.dbd'] = true, ['apr.ldap'] = true, ['apr.ldap_info'] = true, ['apr.ldap_url_check'] = true, ['apr.ldap_url_parse'] = true, ['apr.os_default_encoding'] = true, ['apr.os_locale_encoding'] = true, ['apr.parse_cookie_header'] = true, ['apr.parse_headers'] = true, ['apr.parse_multipart'] = true, ['apr.parse_query_string'] = true, ['apr.ref'] = true, ['apr.deref'] = true, ['apr.platform_get'] = true, ['apr.proc_fork'] = true, ['apr.signal_names'] = true, ['apr.strfsize'] = true, ['apr.type'] = true, ['apr.uri_port_of_scheme'] = true, ['apr.uuid_format'] = true, ['apr.uuid_get'] = true, ['apr.uuid_parse'] = true, ['apr.version_get'] = true, ['driver:driver'] = true, ['driver:transaction_mode'] = true, ['file:lock'] = true, ['ldap_conn:bind'] = true, ['ldap_conn:option_get'] = true, ['ldap_conn:option_set'] = true, ['ldap_conn:rebind_add'] = true, ['ldap_conn:search'] = true, ['mc_client:add'] = true, ['mc_client:add_server'] = true, ['mc_client:add_server'] = true, ['mc_client:decr'] = true, ['mc_client:delete'] = true, ['mc_client:find_server'] = true, ['mc_client:find_server'] = true, ['mc_client:get'] = true, ['mc_client:incr'] = true, ['mc_client:replace'] = true, ['mc_client:set'] = true, ['mc_client:stats'] = true, ['mc_client:version'] = true, ['md5_context:digest'] = true, ['sha1_context:digest'] = true, ['socket:recvfrom'] = true, ['socket:listen'] = true, ['thread:join'] = true, ['thread:status'] = true, ['xml_parser:geterror'] = true, } local function dumpentries(functions) for _, entry in ipairs(functions) do local signature = entry.signature:gsub('%->', '→') local funcname = sig2pubfun(signature) local anchor = toanchor(funcname) local tc = '' if next(coverage) then local covkey = sig2privfun(signature) if not coverage[covkey] then covkey = 'lua_' .. covkey end tc = coverage[covkey] or '' if tc ~= '' then local template = 'test coverage: %s
' local color = tc >= 75 and 'green' or tc >= 50 and 'orange' or 'red' tc = fmt(template, color, tc == 0 and 'none' or fmt('%i%%', tc)) end end blocks:add('### %s `%s`', tc, anchor, anchor, signature) blocks:add('%s', preprocess(entry.description)) if entry.binarysafe ~= nil and not bsignore[funcname] and not entry.description:find 'This function is binary safe' and not entry.description:find 'This function is not binary safe' then blocks:add('*This function %s binary safe.*', entry.binarysafe and 'is' or 'is not') end end end local function htmlencode(s) return (s:gsub('&', '&') :gsub('<', '<') :gsub('>', '>')) end local custom_sorting = { ['crypt.c'] = [[ apr.md5 apr.md5_encode apr.password_validate apr.password_get apr.md5_init md5_context:update md5_context:digest md5_context:reset apr.sha1 apr.sha1_init sha1_context:update sha1_context:digest sha1_context:reset ]], ['thread.c'] = [[ apr.thread apr.thread_yield thread:status thread:join ]], ['serialize.c'] = [[ apr.serialize apr.unserialize apr.ref apr.deref ]], ['io_file.c'] = [[ apr.file_link apr.file_copy apr.file_append apr.file_rename apr.file_remove apr.file_truncate apr.file_mtime_set apr.file_attrs_set apr.file_perms_set apr.stat apr.file_open file:stat file:lines file:truncate file:read file:write file:seek file:flush file:lock file:unlock pipe:timeout_get pipe:timeout_set file:fd_get file:inherit_set file:inherit_unset file:close ]], } for _, module in ipairs(sorted_modules) do local a = toanchor(module.name) blocks:add('## %s', a, a, module.name) if module.header then blocks:add('%s', preprocess(module.header)) end if module.example then blocks:add(' %s', module.example:gsub('\n', '\n ')) end if custom_sorting[module.file] then local ordertbl = { n = 0 } for f in custom_sorting[module.file]:gmatch '%S+' do ordertbl[f], ordertbl.n = ordertbl.n, ordertbl.n + 1 end local function order(f) return ordertbl[f.signature:match '^[%w_.:]+'] end table.sort(module.functions, function(a, b) return order(a) < order(b) end) end dumpentries(module.functions) end -- Join the blocks of Markdown source and write them to the 1st file. io.write(table.concat(blocks, '\n\n')) lua-apr-0.23.2.dfsg/etc/errors.lua000066400000000000000000000204111220664456000166560ustar00rootroot00000000000000--[[ Error handling code generator for the Lua/APR binding. Author: Peter Odding Last Change: December 7, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT The Apache Portable Runtime defines a long list of error codes whose integer value differs between platforms and to make it even more complex several integer values can map to the same error code. This script goes through the APR header file, extracts the defined error codes (by name) and generates some C source code that will convert APR error codes to symbolic strings. --]] local verbose = false local constants = {} local tests = {} local ignored = { APR_AFNOSUPPORT = true, -- error: ‘APR_AFNOSUPPORT’ undeclared APR_CHILD_DONE = true, APR_CHILD_NOTDONE = true, APR_DECLARE = true, APR_ERRNO_H = true, APR_FROM_OS_ERROR = true, APR_HAVE_ERRNO_H = true, APR_OS2_STATUS = true, APR_OS_ERRSPACE_SIZE = true, APR_OS_START_CANONERR = true, APR_OS_START_EAIERR = true, APR_OS_START_ERROR = true, APR_OS_START_STATUS = true, APR_OS_START_SYSERR = true, APR_OS_START_USEERR = true, APR_OS_START_USERERR = true, APR_OS_START_USERERR = true, APR_STATUS_IS_CHILD_DONE = true, APR_STATUS_IS_CHILD_NOTDONE = true, APR_STATUS_IS_ENETDOWN = true, -- warning: implicit declaration of function ‘APR_STATUS_IS_ENETDOWN’ APR_TO_OS_ERROR = true, APR_UTIL_ERRSPACE_SIZE = true, APR_UTIL_START_STATUS = true, } local function check(path) io.stderr:write("Looking for headers at ", path, " .. ") local status = pcall(io.input, path) io.stderr:write(status and "Found them!\n" or "Failed!\n") return status end if not (check '/usr/include/apr-1.0/apr_errno.h' -- Debian / Ubuntu or check '/usr/include/apr-1/apr_errno.h' -- Arch Linux / Mac OS X or check '/usr/local/include/apr-1/apr_errno.h') then -- FreeBSD io.stderr:write [[ Failed to determine where apr_errno.h is defined! This means the error handling module can't be regenerated, but don't worry: The Lua/APR repository includes a generated "errno.c" for just these situations. ]] return end -- Parse the header file. {{{1 local function add(table, token) if not table[token] then table[#table + 1] = token table[token] = true end end local source = io.read '*a' source = source:gsub('/%*.-%*/', '') for token in source :gmatch '[%w_]+' do if not ignored[token] then if token:find '^APR_STATUS_IS_[A-Z0-9_]+$' then add(tests, token) elseif token:find '^APR_[A-Z0-9_]+$' then add(constants, token) end end end table.sort(constants) table.sort(tests) -- Report intermediate results? {{{1 if verbose then io.write('Found ', #constants, ' error constants:\n') for i, constant in ipairs(constants) do io.write(' - ', constant, '\n') if not tests[constant:gsub('^APR_(.-)$', 'APR_STATUS_IS_%1')] then io.write(" (doesn't have a matching test)\n") end end io.write '\n' io.write('Found ', #tests, ' error tests:\n') for i, test in ipairs(tests) do io.write(' - ', test, '\n') if not constants[test:gsub('^APR_STATUS_IS_', 'APR_')] then io.write(" (doesn't have a matching constant)\n") end longest_test = math.max(#test, longest_test) end io.write '\n' end -- Generate the error handling module's source code. {{{1 local tempfile = assert(os.tmpname()) local handle = assert(io.open(tempfile, 'w')) -- Documentation. {{{2 handle:write([[ /* Error handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: ]], os.date '%B %d, %Y\n', [[ * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Most functions in the Lua/APR binding follow the Lua idiom of returning nil * followed by an error message string. These functions also return a third * argument which is the symbolic name of the error (or the error code in case * a symbolic name cannot be determined). The following symbolic names are * currently defined (there's actually a lot more but they shouldn't be * relevant when working in Lua): * * - `'ENOSTAT'`: APR was unable to perform a stat on the file * - `'EBADDATE'`: APR was given an invalid date * - `'EINVALSOCK'`: APR was given an invalid socket * - `'ENOPROC'`: APR was not given a process structure * - `'ENOTIME'`: APR was not given a time structure * - `'ENODIR'`: APR was not given a directory structure * - `'ENOTHREAD'`: APR was not given a thread structure * - `'EBADIP'`: the specified IP address is invalid * - `'EBADMASK'`: the specified netmask is invalid * - `'EDSOOPEN'`: APR was unable to open the DSO object * - `'EABSOLUTE'`: the given path was absolute * - `'ERELATIVE'`: the given path was relative * - `'EINCOMPLETE'`: the given path was neither relative nor absolute * - `'EABOVEROOT'`: the given path was above the root path * - `'EBADPATH'`: the given path was bad * - `'EPATHWILD'`: the given path contained wildcards * - `'ESYMNOTFOUND'`: could not find the requested symbol * - `'EPROC_UNKNOWN'`: the given process was not recognized by APR * - `'ENOTENOUGHENTROPY'`: APR could not gather enough [entropy] [entropy] to continue * - `'TIMEUP'`: the operation did not finish before the timeout * - `'INCOMPLETE'`: the operation was incomplete although some processing was performed and the results are partially valid * - `'EOF'`: APR has encountered the end of the file * - `'ENOTIMPL'`: the APR function has not been implemented on this platform, either because nobody has gotten to it yet, or the function is impossible on this platform * - `'EMISMATCH'`: two passwords do not match * - `'EACCES'`: permission denied * - `'EEXIST'`: file exists * - `'ENAMETOOLONG'`: path name is too long * - `'ENOENT'`: no such file or directory * - `'ENOTDIR'`: not a directory * - `'ENOSPC'`: no space left on device * - `'ENOMEM'`: not enough memory * - `'EMFILE'`: too many open files * - `'ENFILE'`: file table overflow * - `'EBADF'`: bad file number * - `'EINVAL'`: invalid argument * - `'ESPIPE'`: illegal seek * - `'EAGAIN'`: operation would block * - `'EINTR'`: interrupted system call * - `'ENOTSOCK'`: socket operation on a non-socket * - `'ECONNREFUSED'`: connection refused * - `'EINPROGRESS'`: operation now in progress * - `'ECONNABORTED'`: software caused connection abort * - `'ECONNRESET'`: connection Reset by peer * - `'ETIMEDOUT'`: operation timed out (deprecated) * - `'EHOSTUNREACH'`: no route to host * - `'ENETUNREACH'`: network is unreachable * - `'EFTYPE'`: inappropriate file type or format * - `'EPIPE'`: broken pipe * - `'EXDEV'`: cross device link * - `'ENOTEMPTY'`: directory not empty * - `'EAFNOSUPPORT'`: address family not supported * * Note that the error descriptions above were copied verbatim from [apr_errno.h] [errno]. * * [entropy]: http://en.wikipedia.org/wiki/Entropy_%28computing%29 * [errno]: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_errno.h?view=markup */ #include "lua_apr.h" #include void status_to_name(lua_State *L, apr_status_t status) { /* Use a switch statement for fast number to string mapping: */ switch (status) { ]]) -- Dynamically generated source code. {{{2 local template = [[ # ifdef %s case %s: lua_pushliteral(L, %q); return; # endif ]] for i, constant in ipairs(constants) do local name = constant:gsub('^APR_', '') handle:write(template:format(constant, constant, name)) end handle:write [[ } /* If the switch statement fails we fall back to the following monstrosity :-) */ if (0) ; ]] local template = [[ # ifdef %s else if (%s(status)) { lua_pushliteral(L, %q); return; } # endif ]] for i, test in ipairs(tests) do local name = test:gsub('^APR_STATUS_IS_', '') handle:write(template:format(test, test, name)) end handle:write [[ lua_pushinteger(L, status); } ]] -- Only replace the file if it has changed. {{{2 assert(handle:close()) local function getsrc(path) local handle = io.open(path) if handle then local source = assert(handle:read '*a') assert(handle:close()) return source:gsub('Last Change: [^\n]+', '') end end if getsrc(tempfile) == getsrc 'src/errno.c' then -- Either nothing or just the date changed. io.stderr:write("Up to date!\n") os.remove(tempfile) else assert(os.rename(tempfile, 'src/errno.c')) end lua-apr-0.23.2.dfsg/etc/lua-apr-scm-1.rockspec000066400000000000000000000016561220664456000206630ustar00rootroot00000000000000--[[ This is the LuaRocks rockspec for the Lua/APR binding. Author: Peter Odding Last Change: June 18, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] package = 'Lua-APR' version = 'scm-1' source = { url = 'git://github.com/xolox/lua-apr.git', branch = 'master' } description = { summary = 'Apache Portable Runtime binding for Lua', detailed = [[ Lua/APR is a binding to the Apache Portable Runtime (APR) library. APR powers software such as the Apache webserver and Subversion and Lua/APR makes the APR operating system interfaces available to Lua. ]], homepage = 'http://peterodding.com/code/lua/apr/', license = 'MIT', } dependencies = { 'lua >= 5.1' } build = { type = 'make', variables = { LUA_DIR = '$(PREFIX)', LUA_LIBDIR = '$(LIBDIR)', LUA_SHAREDIR = '$(LUADIR)', CFLAGS = '$(CFLAGS) -I$(LUA_INCDIR)', } } -- vim: ft=lua ts=2 sw=2 et lua-apr-0.23.2.dfsg/etc/make.lua000066400000000000000000000230671220664456000162710ustar00rootroot00000000000000--[[ Supporting code for the UNIX makefile of the Lua/APR binding. Author: Peter Odding Last Change: December 4, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This Lua script enhances the UNIX makefile of the Lua/APR binding in two ways, both aiming to make the build process more portable: - The external programs pkg-config, apr-1-config, apu-1-config and apreq2-config are used to find the compiler and linker flags for the Lua 5.1, APR 1, APR-util 1 and libapreq2 libraries. - It knows about needed system packages on Debian, Ubuntu, Arch Linux, Red Hat, Fedora Core, Suse Linux and CentOS. The makefile always invokes this script to find compiler and linker flags, but only when the build fails will the script be called to perform a "sanity check" of the external dependencies / system packages. ]] local DEBUG = os.getenv 'LUA_APR_DEBUG' -- Miscellaneous functions. {{{1 -- trim() -- Trim leading/trailing whitespace from string. {{{2 local function trim(s) return s:match '^%s*(.-)%s*$' end -- dedent() -- remove common leading whitespace from string. {{{2 local function dedent(text) local pattern = '\n' .. text:match '^[ \t]*' return trim(('\n' .. text):gsub(pattern, '\n')) end -- message() -- Print formatted message to standard error. {{{2 local function message(text, ...) io.stderr:write(dedent(text:format(...)), '\n') io.stderr:flush() end -- words() -- Iterate over whitespace separated words. {{{2 local function words(text) return text:gmatch '%S+' end -- readfile() -- Read the contents of a file into a string. {{{2 local function readfile(path) local handle = io.open(path) local content = handle and handle:read '*a' or '' if handle then handle:close() end return content end -- executable() -- Check whether a given program is executable. {{{2 local function executable(program) return os.execute('which ' .. program .. ' >/dev/null 2>&1') == 0 end -- readcmd() -- Get the results of a shell command (status, stdout, stderr). {{{2 local function readcmd(command) local stdout = os.tmpname() local stderr = os.tmpname() local status = os.execute(command .. ' 1>"' .. stdout .. '"' .. ' 2>"' .. stderr .. '"') local output = readfile(stdout) local errors = readfile(stderr) os.remove(stdout) os.remove(stderr) return status, output, errors end -- readstdout() -- Get the standard output of a shell command. {{{2 local function readstdout(command) local status, stdout, stderr = readcmd(command) return status == 0 and stdout or '' end -- sudo() -- Prepend `sudo' to a command when `sudo' is installed. {{{2 local function sudo(command, args) if executable 'sudo' and (os.getenv 'SUDO_USER' or readstdout 'id -un' ~= 'root') then command = 'sudo ' .. command end if #args > 0 then command = command .. ' ' .. table.concat(args, ' ') end return command end -- mergeflags() -- Merge command line flags reported by pkg-config. {{{2 local function mergeflags(flags, command) local status, stdout, stderr = readcmd(command) if status == 0 then for flag in words(stdout) do if not flags[flag] then local position = #flags + 1 flags[flag] = position flags[position] = flag end end end end -- getcflags() -- Get the compiler flags needed to build the Lua/APR binding. {{{1 local function getcflags() local flags, count = {}, 0 -- Compiler flags for Lua 5.1. mergeflags(flags, 'pkg-config --cflags lua5.1') -- Debian/Ubuntu mergeflags(flags, 'pkg-config --cflags lua-5.1') -- FreeBSD mergeflags(flags, 'pkg-config --cflags lua') -- Arch Linux if DEBUG and #flags == 0 then message "Warning: Failed to determine Lua 5.1 compiler flags." end count = #flags -- Compiler flags for APR 1. mergeflags(flags, 'apr-1-config --cflags --cppflags --includes') -- sometimes this is available mergeflags(flags, 'pkg-config --cflags apr-1') -- otherwise we fall back to pkg-config if DEBUG and #flags == count then message "Warning: Failed to determine APR 1 compiler flags." end count = #flags -- Compiler flags for APR-util 1. mergeflags(flags, 'apu-1-config --includes') -- sometimes this is available mergeflags(flags, 'pkg-config --cflags apr-util-1') -- otherwise we fall back to pkg-config if DEBUG and #flags == count then message "Warning: Failed to determine APR-util 1 compiler flags." end count = #flags -- Compiler flags for libapreq2. mergeflags(flags, 'apreq2-config --includes') local have_apreq = (#flags > count) if DEBUG and not have_apreq then message "Warning: Failed to determine libapreq2 compiler flags." end -- Let the C source code know whether libapreq2 is available. flags[#flags + 1] = '-DLUA_APR_HAVE_APREQ=' .. (have_apreq and 1 or 0) return table.concat(flags, ' ') end -- getlflags() -- Get the linker flags needed to build the Lua/APR binding. {{{1 local function getlflags() local flags = {} -- Linker flags for APR 1. mergeflags(flags, 'apr-1-config --link-ld --libs') mergeflags(flags, 'pkg-config --libs apr-1') if DEBUG and #flags == 0 then message "Warning: Failed to determine APR 1 linker flags." end count = #flags -- Linker flags for APR-util 1. mergeflags(flags, 'apu-1-config --link-ld --libs --ldap-libs') mergeflags(flags, 'pkg-config --libs apr-util-1') if DEBUG and #flags == count then message "Warning: Failed to determine APR-util 1 linker flags." end count = #flags -- Linker flags for libapreq2. mergeflags(flags, 'apreq2-config --link-ld') if DEBUG and #flags == 0 then message "Warning: Failed to determine apreq2 linker flags." end return table.concat(flags, ' ') end -- checkpackages() -- Check if required system packages are installed. {{{1 local function delimiter() message(string.rep('-', 79)) end local function checkpackages() -- Let the user know what's going on. delimiter() message [[ It looks like your Lua/APR build failed. This could be because you're missing some external dependencies. I will now check if you have the required system packages installed (this should work on Debian, Ubuntu, Arch Linux, Red Hat, Fedora Core, Suse Linux and CentOS). ]] delimiter() -- Perform platform detection. local command, requiredpackages, installedpackagescmd if executable 'dpkg' and executable 'apt-get' then -- Debian & Ubuntu. -- Tested on Ubuntu Linux 10.04 (Lucid Lynx). command = 'apt-get install' installedpackagescmd = [[ dpkg --list | awk '/^i/ {print $2}' ]] requiredpackages = [[ lua5.1 liblua5.1-0 liblua5.1-0-dev libapr1 libapr1-dev libaprutil1 libaprutil1-dev libaprutil1-dbd-sqlite3 libapreq2 libapreq2-dev ]] -- Newer versions of Ubuntu install "recommended packages" by default, but -- unfortunately the libapreq2 package recommends libapache2-mod-apreq2 which -- pulls in the whole Apache server :-|. I think this is stupid and work -- around it by passing the --no-install-recommends command line option -- when it seems to be supported (unfortunately "apt-get --help" doesn't list -- the supported command line options so we have to grep the binary :-P). if os.execute 'strings /usr/bin/apt-get | grep -q install-recommends 1>/dev/null 2>&1' == 0 then command = command .. ' --no-install-recommends' end elseif executable 'rpm' and executable 'yum' then -- Red Hat, Fedora Core, Suse Linux & CentOS. -- Tested on Fedora Core 15. command = 'yum install' installedpackagescmd = [[ rpm -qa --qf '%{NAME}\n' ]] requiredpackages = [[ lua lua-devel apr apr-devel apr-util apr-util-devel libapreq2 libapreq2-devel ]] elseif executable 'pacman' then -- Arch Linux. -- Tested on Arch Linux 2011.08.19. command = 'pacman -S' installedpackagescmd = [[ bash -c "comm -23 <(pacman -Qeq) <(pacman -Qmq)" ]] requiredpackages = [[ lua apr apr-util perl-libapreq2 ]] else message [[ Unknown platform: You'll have to install the required system packages manually (lua, apr, apr-util and libapreq2). ]] delimiter() os.exit(1) end -- Find the installed packages. local installedpackages = {} local handle = io.popen(installedpackagescmd) for name in handle:lines() do installedpackages[name] = true end -- Determine missing packages. local missingpackages = {} for name in words(requiredpackages) do if installedpackages[name] then message(" - Package `%s' is already installed.", name) else message(" - Missing package `%s'!", name) table.insert(missingpackages, name) end end -- If we found any missing system packages, suggest to the user how the -- missing packages can be installed. delimiter() if #missingpackages == 0 then message [[ It looks like you have all required external dependencies installed, something else must have gone wrong... ]] else message([[ The Lua/APR binding has several external dependencies and it looks like some are missing on your system. You should be able to install the dependencies with the following command: %s ]], sudo(command, missingpackages)) end delimiter() -- Because this script is executed from the makefile in || expressions we -- always exit with a non-zero exit code, so that the build still fails. os.exit(1) end -- }}}1 if arg[1] == '--cflags' then print(getcflags()) elseif arg[1] == '--lflags' then print(getlflags()) elseif arg[1] == '--check' then checkpackages() else message("Invalid option!") os.exit(1) end lua-apr-0.23.2.dfsg/etc/signals.lua000066400000000000000000000047221220664456000170110ustar00rootroot00000000000000--[[ Signal handling module code generator for the Lua/APR binding. Author: Peter Odding Last Change: June 23, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT APR supports signal handling but leaves the definition of signal names up to the system where APR is installed. This isn't a problem in C where the usual SIG* symbols are available by including but of course that doesn't work in Lua! This script works around the problem by generating some really nasty preprocessor heavy code :-). The list of signal names in this script was taken from "man 7 signal" on my Ubuntu Linux 10.04 installation. --]] -- Symbol names. local symbols = [[ -- The signals described in the original POSIX.1-1990 standard. SIGHUP SIGINT SIGQUIT SIGILL SIGABRT SIGFPE SIGKILL SIGSEGV SIGPIPE SIGALRM SIGTERM SIGUSR1 SIGUSR2 SIGCHLD SIGCONT SIGSTOP SIGTSTP SIGTTIN SIGTTOU -- The signals described in SUSv2 and POSIX.1-2001. SIGBUS SIGPOLL SIGPROF SIGSYS SIGTRAP SIGURG SIGVTALRM SIGXCPU SIGXFSZ -- "Various other signals." SIGIOT SIGEMT SIGSTKFLT SIGIO SIGCLD SIGPWR SIGINFO SIGLOST SIGWINCH SIGUNUSED ]] local map, index = {}, 1 for line in symbols:gmatch '[^\n]+' do local name = line:match 'SIG%S+' if name then map[index] = name index = index + 1 end end local signal_table = {} local signal_handlers = {} for i, name in ipairs(map) do signal_table[i] = string.format([[ # ifdef %s { "%s", %s, %s_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif]], name, name, name, name:lower()) signal_handlers[i] = string.format([[ #ifdef %s static void %s_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, %i); } #endif]], name, name:lower(), i - 1) end print(string.format([[ /* Generated signal handlers. */ %s /* Generated signal table. */ static struct { const char *name; /* Symbolic name of signal (used in Lua) */ const int value; /* Integer code of signal (used in C) */ void (*hook)(lua_State*, lua_Debug*); /* Lua hook to be called by signal handler */ lua_State *state; /* Lua state that installed signal handler */ lua_Hook oldhook; /* Old debug hook and related variables */ int oldmask, oldcount; } known_signals[] = { %s };]], table.concat(signal_handlers, '\n'), table.concat(signal_table, '\n'))) lua-apr-0.23.2.dfsg/etc/template.rockspec000066400000000000000000000017101220664456000202060ustar00rootroot00000000000000--[[ This is the LuaRocks rockspec for the Lua/APR binding. Author: Peter Odding Last Change: {{DATE}} Homepage: http://peterodding.com/code/lua/apr/ --]] package = 'Lua-APR' version = '{{VERSION}}' source = { url = 'http://peterodding.com/code/lua/apr/downloads/lua-apr-{{VERSION}}.zip', md5 = '{{HASH}}', } description = { summary = 'Apache Portable Runtime binding for Lua', detailed = [[ Lua/APR is a binding to the Apache Portable Runtime (APR) library. APR powers software such as the Apache webserver and Subversion and Lua/APR makes the APR operating system interfaces available to Lua. ]], homepage = 'http://peterodding.com/code/lua/apr/', license = 'MIT', } dependencies = { 'lua >= 5.1' } build = { type = 'make', variables = { LUA_DIR = '$(PREFIX)', LUA_LIBDIR = '$(LIBDIR)', LUA_SHAREDIR = '$(LUADIR)', CFLAGS = '$(CFLAGS) -I$(LUA_INCDIR)', } } -- vim: ft=lua ts=2 sw=2 et lua-apr-0.23.2.dfsg/etc/win32-bootstrap/000077500000000000000000000000001220664456000176165ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/etc/win32-bootstrap/clean.cmd000066400000000000000000000001721220664456000213650ustar00rootroot00000000000000RMDIR /S /Q apr RMDIR /S /Q apr-util RMDIR /S /Q apr-iconv RMDIR /S /Q libapreq2 RMDIR /S /Q sqlite3 RMDIR /S /Q binaries lua-apr-0.23.2.dfsg/etc/win32-bootstrap/libapreq2.mak000066400000000000000000000127611220664456000222000ustar00rootroot00000000000000# Microsoft Developer Studio Generated NMAKE File, Based on libapreq.dsp # Compile with NMAKE /f libapreq2.mak "CFG=libapreq2 - Win32 Debug" APR_LIB=$(ROOT)\apr\Debug\libapr-1.lib APU_LIB=$(ROOT)\apr-util\Debug\libaprutil-1.lib APREQ_HOME=$(ROOT)\libapreq2 !IF "$(CFG)" == "" CFG=libapreq2 - Win32 Release !MESSAGE No configuration specified. Defaulting to libapreq2 - Win32 Release. !ENDIF !IF "$(CFG)" != "libapreq2 - Win32 Release" && "$(CFG)" != "libapreq2 - Win32 Debug" !MESSAGE Invalid configuration "$(CFG)" specified. !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "libapreq2.mak" CFG="libapreq2 - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "libapreq2 - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "libapreq2 - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE !ERROR An invalid configuration is specified. !ENDIF !IF "$(OS)" == "Windows_NT" NULL= !ELSE NULL=nul !ENDIF CPP=cl.exe /I$(ROOT)\apr\include /I$(ROOT)\apr-util\include RSC=rc.exe /I$(ROOT)\apr\include /I$(ROOT)\apr-util\include CFG_HOME=$(APREQ_HOME)\win32 OUTDIR=$(CFG_HOME)\libs INTDIR=$(CFG_HOME)\libs LIBDIR=$(APREQ_HOME)\library LINK32_OBJS= \ "$(INTDIR)\cookie.obj" \ "$(INTDIR)\param.obj" \ "$(INTDIR)\parser.obj" \ "$(INTDIR)\parser_header.obj" \ "$(INTDIR)\parser_multipart.obj" \ "$(INTDIR)\parser_urlencoded.obj" \ "$(INTDIR)\util.obj" \ "$(INTDIR)\version.obj" \ "$(INTDIR)\error.obj" \ "$(INTDIR)\libapreq.res" !IF "$(CFG)" == "libapreq2 - Win32 Release" ALL: "$(OUTDIR)\libapreq2.dll" "$(OUTDIR)": if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APREQ_DECLARE_EXPORT" /I"$(APREQ_HOME)\include" /FD /c MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 RSC_PROJ=/l 0x409 /d "NDEBUG" /i "$(APREQ_HOME)\include" BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(OUTDIR)\libapreq2.bsc" LINK32=link.exe MANIFEST=$(OUTDIR)\libapreq2.dll.manifest LINK32_FLAGS="$(APR_LIB)" "$(APU_LIB)" kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:no /machine:I386 /out:"$(OUTDIR)\libapreq2.dll" /implib:"$(OUTDIR)\libapreq2.lib" "$(OUTDIR)\libapreq2.dll": "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) $(LINK32_FLAGS) $(DEF_FLAGS) $(LINK32_OBJS) if exist $(MANIFEST) mt /nologo /manifest $(MANIFEST) /outputresource:$(OUTDIR)\libapreq2.dll;2 !ELSEIF "$(CFG)" == "libapreq2 - Win32 Debug" ALL: "$(OUTDIR)\libapreq2.dll" "$(OUTDIR)": if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" CPP_PROJ=/nologo /MDd /W3 /Gm /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "APREQ_DECLARE_EXPORT" /I"$(APREQ_HOME)\include" /FD /RTC1 /c MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 RSC_PROJ=/l 0x409 /d "_DEBUG" /i "$(APREQ_HOME)\include" BSC32=bscmake.exe BSC32_FLAGS=/nologo /o"$(OUTDIR)\libapreq2.bsc" LINK32=link.exe MANIFEST=$(OUTDIR)\libapreq2.dll.manifest LINK32_FLAGS="$(APR_LIB)" "$(APU_LIB)" kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\libapreq2.pdb" /debug /machine:I386 /out:"$(OUTDIR)\libapreq2.dll" /implib:"$(OUTDIR)\libapreq2.lib" /pdbtype:sept "$(OUTDIR)\libapreq2.dll": "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) $(LINK32) $(LINK32_FLAGS) $(DEF_FLAGS) $(LINK32_OBJS) if exist $(MANIFEST) mt /nologo /manifest $(MANIFEST) /outputresource:$(OUTDIR)\libapreq2.dll;2 !ENDIF .c{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .cpp{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .cxx{$(INTDIR)}.obj:: $(CPP) @<< $(CPP_PROJ) $< << .c{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << .cpp{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << .cxx{$(INTDIR)}.sbr:: $(CPP) @<< $(CPP_PROJ) $< << !IF "$(CFG)" == "libapreq2 - Win32 Release" || "$(CFG)" == "libapreq2 - Win32 Debug" SOURCE=$(LIBDIR)\cookie.c "$(INTDIR)\cookie.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\cookie.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\param.c "$(INTDIR)\param.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\param.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\parser.c "$(INTDIR)\parser.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\parser.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\parser_header.c "$(INTDIR)\parser_header.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\parser_header.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\parser_multipart.c "$(INTDIR)\parser_multipart.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\parser_multipart.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\parser_urlencoded.c "$(INTDIR)\parser_urlencoded.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\parser_urlencoded.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\version.c "$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\version.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\util.c "$(INTDIR)\util.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\util.obj" $(CPP_PROJ) $(SOURCE) SOURCE=$(LIBDIR)\error.c "$(INTDIR)\error.obj" : $(SOURCE) "$(INTDIR)" $(CPP) /Fo"$(INTDIR)\error.obj" $(CPP_PROJ) $(SOURCE) SOURCE=.\libapreq.rc "$(INTDIR)\libapreq.res" : $(SOURCE) "$(INTDIR)" $(RSC) /fo"$(INTDIR)\libapreq.res" $(RSC_PROJ) $(SOURCE) !ENDIF lua-apr-0.23.2.dfsg/etc/win32-bootstrap/make.cmd000066400000000000000000000171541220664456000212300ustar00rootroot00000000000000:: Batch script to bootstrap a development environment for the Lua/APR binding. :: :: Author: Peter Odding :: Last Change: September 11, 2011 :: Homepage: http://peterodding.com/code/lua/apr/ :: License: MIT :: :: This is a Windows batch script that bootstraps a development environment for :: the Lua/APR binding. Run this script from a Windows SDK command prompt. :: Apart from the Windows SDK this script depends on the programs "wget.exe", :: "unzip.exe", "gunzip.exe", "tar.exe" and "sed.exe" from UnxUtils. I've :: tested this script on a virtualized 32 bits Windows XP installation in both :: the Win32 and x64 Windows SDK command prompts. There's a ZIP file with this :: script, the patched "libapreq2.mak" makefile and the above executables :: available online at the following location: :: :: http://peterodding.com/code/lua/apr/downloads/win32-bootstrap.zip :: :: TODO Currently fails to build libapreq2 for x64. Is it even possible?! :: Pick either "Debug" or "Release". SET BUILD_MODE=Debug :: Version strings (embedded in filenames and URLs). :: This script has only been tested with the versions below. SET APR_VERSION=1.4.5 SET APU_VERSION=1.3.12 SET API_VERSION=1.2.1 SET APQ_VERSION=2.13 SET SQLITE_VERSION=3070701 :: Location of source code archives mirror. SET APR_MIRROR=http://www.apache.org/dist/apr SET APQ_MIRROR=http://www.apache.org/dist/httpd/libapreq SET SQLITE_SITE=http://sqlite.org :: Names of source code archives. SET APR_ARCHIVE=apr-%APR_VERSION%-win32-src.zip SET APU_ARCHIVE=apr-util-%APU_VERSION%-win32-src.zip SET API_ARCHIVE=apr-iconv-%API_VERSION%-win32-src-r2.zip SET APQ_ARCHIVE=libapreq2-%APQ_VERSION%.tar.gz SET SQLITE_ARCHIVE=sqlite-amalgamation-%SQLITE_VERSION%.zip :: Try to detect the intended platform. IF "%PLATFORM%" == "" ( IF /i "%CPU%" == "i386" ( SET PLATFORM=Win32 ) ELSE ( IF /i "%CPU%" == "AMD64" ( SET PLATFORM=x64 ) ELSE ( ECHO Failed to determine CPU type, please set PLATFORM=Win32 or PLATFORM=x64 EXIT /b 1 ) ) ) :: Get any missing source code archives. IF NOT EXIST %APR_ARCHIVE% WGET %APR_MIRROR%/%APR_ARCHIVE% || (ECHO Failed to download APR archive & EXIT /b 1) IF NOT EXIST %APU_ARCHIVE% WGET %APR_MIRROR%/%APU_ARCHIVE% || (ECHO Failed to download APR-util archive & EXIT /b 1) IF NOT EXIST %API_ARCHIVE% WGET %APR_MIRROR%/%API_ARCHIVE% || (ECHO Failed to download APR-iconv archive & EXIT /b 1) IF NOT EXIST %APQ_ARCHIVE% WGET %APQ_MIRROR%/%APQ_ARCHIVE% || (ECHO Failed to download libapreq2 archive & EXIT /b 1) IF NOT EXIST %SQLITE_ARCHIVE% WGET %SQLITE_SITE%/%SQLITE_ARCHIVE% || (ECHO Failed to download SQLite3 archive & EXIT /b 1) :: Create the directory where the resulting binaries are stored. IF NOT EXIST binaries MKDIR binaries || (ECHO Failed to create binaries directory & EXIT /b 1) :: Unpack the source code archives. IF NOT EXIST apr ( UNZIP -qo %APR_ARCHIVE% || (ECHO Failed to unpack APR archive & EXIT /b 1) MOVE apr-%APR_VERSION% apr || (ECHO Failed to rename APR directory & EXIT /b 1) :: I haven't a clue why this is needed, but it certainly helps :-) TYPE apr\include\apr.hw > apr\apr.h TYPE apr\include\apr.hw > apr\include\apr.h ) IF NOT EXIST apr-util ( UNZIP -qo %APU_ARCHIVE% || (ECHO Failed to unpack APR-util archive & EXIT /b 1) MOVE apr-util-%APU_VERSION% apr-util || (ECHO Failed to rename APR-util directory & EXIT /b 1) ) IF NOT EXIST apr-iconv ( UNZIP -qo %API_ARCHIVE% || (ECHO Failed to unpack APR-iconv archive & EXIT /b 1) MOVE apr-iconv-%API_VERSION% apr-iconv || (ECHO Failed to rename APR-iconv directory & EXIT /b 1) ) IF NOT EXIST libapreq2 ( COPY %APQ_ARCHIVE% %APQ_ARCHIVE%.tmp GUNZIP -f %APQ_ARCHIVE% || (ECHO Failed to decompress libapreq2 archive & EXIT /b 1) MOVE %APQ_ARCHIVE%.tmp %APQ_ARCHIVE% TAR xf *.tar || (ECHO Failed to unpack libapreq2 archive & EXIT /b 1) DEL libapreq2-*.tar MOVE libapreq2-%APQ_VERSION% libapreq2 || (ECHO Failed to rename libapreq2 directory & EXIT /b 1) ) IF NOT EXIST sqlite3 ( UNZIP -qo %SQLITE_ARCHIVE% || (ECHO Failed to unpack SQLite3 archive & EXIT /b 1) MOVE sqlite-amalgamation-%SQLITE_VERSION% sqlite3 || (ECHO Failed to rename SQLite3 directory & EXIT /b 1) :: Copy sqlite3.h (needed to build apr_dbd_sqlite3-1.dll). COPY /Y sqlite3\sqlite3.h apr-util\include || (ECHO Failed to copy sqlite3.h & EXIT /b 1) ) :: APR creates 32 bit builds in the "Debug" and "Release" directories :: but 64 bit builds in the "x64\Debug" or "x64\Release" directories. SET BUILD_DIR=%BUILD_MODE% IF %PLATFORM% == x64 SET BUILD_DIR=x64\%BUILD_DIR% :: Build the APR library. PUSHD apr NMAKE /nologo /f libapr.mak CFG="libapr - %PLATFORM% %BUILD_MODE%" || (POPD & ECHO Failed to build APR library & EXIT /b 1) POPD COPY apr\%BUILD_DIR%\libapr-1.dll binaries || (ECHO Failed to copy APR binary & EXIT /b 1) IF EXIST apr\%BUILD_DIR%\libapr-1.pdb COPY apr\%BUILD_DIR%\libapr-1.pdb binaries :: Build the APR-iconv library. PUSHD apr-iconv NMAKE /nologo /f libapriconv.mak CFG="libapriconv - %PLATFORM% %BUILD_MODE%" || (POPD & ECHO Failed to build APR-iconv library & EXIT /b 1) POPD :: Workaround for "LINK : fatal error LNK1181: cannot open input file ..\Debug\libapriconv-1.lib". IF %PLATFORM% == x64 XCOPY /Y apr-iconv\x64\%BUILD_MODE% apr-iconv COPY apr-iconv\%BUILD_DIR%\libapriconv-1.dll binaries IF EXIST apr-iconv\%BUILD_DIR%\libapriconv-1.pdb COPY apr-iconv\%BUILD_DIR%\libapriconv-1.pdb binaries :: TODO I'm not sure how or why but apparently the above does not build the :: *.so files, instead they are built by the apr-util section below. This is :: why the *.so files are copied after building apr-util instead of here... :: Build the APR-util library. IF "%PLATFORM%" == "x64" ( :: I haven't a clue why this is needed, but it certainly helps :-) TYPE apr-util\include\apu.hw > apr-util\include\apu.h ) PUSHD apr-util NMAKE /nologo /f libaprutil.mak CFG="libaprutil - %PLATFORM% %BUILD_MODE%" || (POPD & ECHO Failed to build APR-util library & EXIT /b 1) POPD COPY apr-util\%BUILD_DIR%\libaprutil-1.dll binaries IF EXIST apr-util\%BUILD_DIR%\libaprutil-1.pdb COPY apr-util\%BUILD_DIR%\libaprutil-1.pdb binaries :: TODO As explained above, apr-util builds the apr-iconv *.so files... IF NOT EXIST binaries\iconv MKDIR binaries\iconv COPY apr-iconv\%BUILD_MODE%\iconv\*.so binaries\iconv COPY apr-iconv\%BUILD_MODE%\iconv\*.pdb binaries\iconv :: Build the SQLite3 database driver. PUSHD sqlite3 CL /LD /D"SQLITE_API=__declspec(dllexport)" sqlite3.c || (POPD & ECHO Failed to build SQLite3 library & EXIT /b 1) POPD COPY /Y sqlite3\sqlite3.dll binaries || (POPD & ECHO Failed to copy sqlite3.dll & EXIT /b 1) COPY /Y sqlite3\sqlite3.lib apr-util\dbd || (POPD & ECHO Failed to copy sqlite3.lib & EXIT /b 1) PUSHD apr-util\dbd NMAKE /nologo /f apr_dbd_sqlite3.mak CFG="apr_dbd_sqlite3 - %PLATFORM% %BUILD_MODE%" || (POPD & ECHO Failed to build SQLite3 driver & EXIT /b 1) POPD COPY apr-util\dbd\%BUILD_MODE%\apr_dbd_sqlite3-1.dll binaries IF EXIST apr-util\dbd\%BUILD_MODE%\apr_dbd_sqlite3-1.pdb COPY apr-util\dbd\%BUILD_MODE%\apr_dbd_sqlite3-1.pdb binaries :: Build the libapreq2 library. SET ROOT="%CD%" :: The makefile included with libapreq2 assumes it's build as part of Apache. :: We replace it with a custom makefile that doesn't include the Apache glue. TYPE libapreq2.mak > libapreq2\win32\libapreq2.mak PUSHD libapreq2 NMAKE /nologo /f win32\libapreq2.mak CFG="libapreq2 - %PLATFORM% %BUILD_MODE%" ROOT="%ROOT%" APR_LIB="%ROOT%\apr\%BUILD_DIR%\libapr-1.lib" APU_LIB="%ROOT%\apr-util\%BUILD_DIR%\libaprutil-1.lib" || (POPD & ECHO Failed to build libapreq2 library & EXIT /b 1) POPD COPY libapreq2\win32\libs\libapreq2.dll binaries IF EXIST libapreq2\win32\libs\libapreq2.pdb COPY libapreq2\win32\libs\libapreq2.pdb binaries lua-apr-0.23.2.dfsg/etc/wrap.lua000066400000000000000000000060431220664456000163200ustar00rootroot00000000000000--[[ Markdown processor for the Lua/APR binding. Author: Peter Odding Last Change: December 3, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This Lua script takes two arguments, the first is the pathname of an existing Markdown document and the second is the name of an HTML file to generate. The script will transform the Markdown to HTML, syntax highlight snippets of Lua source code using my LXSH module and wrap the output in a page template. ]] -- Get the names of the input and output file. local infile, outfile = unpack(arg, 1, 2) assert(infile, "Missing source Markdown file as 1st argument") assert(outfile, "Missing target HTML file as 2nd argument") -- Load Markdown module (lua-discount or markdown.lua) local status, markdown = pcall(require, 'discount') if not status then status, markdown = pcall(require, 'markdown') end if not status then io.stderr:write("Markdown not installed, can't update HTML files!\n") os.exit() end -- Parse and convert the markdown to HTML. assert(io.input(infile)) local input = assert(io.read '*all') local title = assert(input:match '^%s*#%s*([^\r\n]+)', "Failed to match page title") local content = markdown(input) -- Workaround for bug in Discount :-( content = content:gsub('', '-') -- If my LXSH module is installed we will use it to syntax highlight -- the snippets of Lua source code in the Lua/APR documentation. local status, highlighter = pcall(require, 'lxsh.highlighters.lua') if status and highlighter then local html_entities = { amp = '&', lt = '<', gt = '>' } content = content:gsub('
(.-)
', function(block) block = block:match '^(.-)$' or block block = block:gsub('&(%w+);', html_entities) return highlighter(block, { encodews = true, formatter = lxsh.formatters.html, }) end) end -- Wrap the HTML in a standardized template. assert(io.output(outfile)) io.write([[ ]], title, [[ ]], content, [[ ]]) lua-apr-0.23.2.dfsg/examples/000077500000000000000000000000001220664456000157045ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/examples/async-webserver.lua000066400000000000000000000115631220664456000215340ustar00rootroot00000000000000--[[ Example: Asynchronous webserver Author: Peter Odding Last Change: November 6, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT We can do even better than the performance of the multi threaded webserver by using the [APR pollset module] [pollset_module]. The following webserver uses asynchronous network communication to process requests from multiple clients 'in parallel' without using multiple threads or processes. Here is a benchmark of the asynchronous code listed below (again using [ApacheBench] [ab] with the `-c` argument): $ CONCURRENCY=4 $ POLLSET_SIZE=10 $ lua examples/async-webserver.lua $POLLSET_SIZE 8080 cheat & $ ab -qt5 -c$CONCURRENCY http://localhost:8080/ | grep 'Requests per second\|Transfer rate' Requests per second: 11312.64 [#/sec] (mean) Transfer rate: 6219.74 [Kbytes/sec] received The [single threaded webserver] [simple_server] handled 3670 requests per second, the [multi threaded webserver] [threaded_server] handled 9210 requests per second and the asynchronous webserver below can handle 11310 requests per second. Actually in the above benchmark I may have cheated a bit (depending on whether your goal is correct usage or performance). When I started writing this asynchronous server example I didn't bother to add writable sockets to the pollset, instead I handled the request and response once the client socket was reported as readable by the pollset. Later on I changed the code to handle writing using the pollset and I noticed that the performance dropped. This is probably because the example is so contrived. Anyway here's the performance without cheating: $ lua examples/async-webserver.lua $POLLSET_SIZE 8080 & $ ab -qt5 -c$CONCURRENCY http://localhost:8888/ | grep 'Requests per second\|Transfer rate' Requests per second: 9867.17 [#/sec] (mean) Transfer rate: 5425.03 [Kbytes/sec] received Now follows the implementation of the asynchronous webserver example: [pollset_module]: #pollset [ab]: http://en.wikipedia.org/wiki/ApacheBench [simple_server]: #example_single_threaded_webserver [threaded_server]: #example_multi_threaded_webserver ]] local pollset_size = tonumber(arg[1]) or 10 local port_number = tonumber(arg[2]) or 8080 local cheat = arg[3] == 'cheat' -- cheat to make it faster? local template = [[ Hello from Lua/APR!

Hello from Lua/APR!

The headers provided by your web browser:

%s
]] -- Load the Lua/APR binding. local apr = require 'apr' -- Initialize the server socket. local server = assert(apr.socket_create()) assert(server:bind('*', port_number)) assert(server:listen(pollset_size)) -- Create the pollset. local pollset = assert(apr.pollset(pollset_size)) assert(pollset:add(server, 'input')) -- Use a table indexed with socket objects to keep track of "sessions". local sessions = setmetatable({}, {__mode='k'}) -- Enter the I/O loop. print("Running webserver on http://localhost:" .. port_number .. " ..") while true do local readable, writable = assert(pollset:poll(-1)) -- Process requests. for _, socket in ipairs(readable) do if socket == server then local client = assert(server:accept()) assert(pollset:add(client, 'input')) else local request = assert(socket:read(), "Failed to receive request from client!") local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)') local headers = {} for line in socket:lines() do local name, value = line:match '^(%S+):%s+(.-)$' if not name then break end table.insert(headers, '
' .. name .. ':
' .. value .. '
') end table.sort(headers) local content = template:format(table.concat(headers)) assert(socket:write( protocol, ' 200 OK\r\n', 'Content-Type: text/html\r\n', 'Content-Length: ', #content, '\r\n', 'Connection: close\r\n', '\r\n')) if cheat then assert(socket:write(content)) assert(pollset:remove(socket)) assert(socket:close()) else sessions[socket] = content assert(pollset:remove(socket)) assert(pollset:add(socket, 'output')) end end end if not cheat then -- Process responses. for _, socket in ipairs(writable) do assert(socket:write(sessions[socket])) -- I don't like that when I switch the order of these -- calls, it breaks... Seems like a fairly big gotcha. assert(pollset:remove(socket)) assert(socket:close()) end end end -- vim: ts=2 sw=2 et lua-apr-0.23.2.dfsg/examples/download.lua000066400000000000000000000050241220664456000202170ustar00rootroot00000000000000--[[ Example: HTTP client Author: Peter Odding Last Change: December 30, 2010 Homepage: http://peterodding.com/code/lua/apr/ License: MIT The following Lua script implements a minimal [HTTP client] [http] which can be used to download a given [URL] [url] on the command line (comparable to [wget] [wget] and [curl] [curl]): $ FILE=lua-5.1.4.tar.gz $ URL=http://www.lua.org/ftp/$FILE $ time curl -s $URL > $FILE 0,01s user 0,02s system 6% cpu 0,465 total $ time lua examples/download.lua $URL > $FILE 0,03s user 0,02s system 9% cpu 0,549 total Note that this script and Lua/APR in general are a bit handicapped in that they don't support [HTTPS] [https] because the Apache Portable Runtime does not support encrypted network communication. [url]: http://en.wikipedia.org/wiki/Uniform_Resource_Locator [wget]: http://en.wikipedia.org/wiki/wget [curl]: http://en.wikipedia.org/wiki/cURL [https]: http://en.wikipedia.org/wiki/HTTPS ]] local apr = require 'apr' -- Report errors without stack traces. local function assert(...) local status, message = ... if not status then io.stderr:write('Error: ', message or '(no message)', '\n') os.exit(1) end return ... end local function getpage(url) local components = assert(apr.uri_parse(url)) assert(components.scheme == 'http', "invalid protocol!") local port = assert(components.port or apr.uri_port_of_scheme(components.scheme)) local socket = assert(apr.socket_create()) assert(socket:connect(components.hostname, port)) local pathinfo = assert(apr.uri_unparse(components, 'pathinfo')) assert(socket:write('GET ', pathinfo, ' HTTP/1.0\r\n', 'Host: ', components.hostname, '\r\n', '\r\n')) local statusline = assert(socket:read(), 'HTTP response missing status line!') local protocol, statuscode, reason = assert(statusline:match '^(%S+)%s+(%S+)%s+(.-)$') local redirect = statuscode:find '^30[123]$' for line in socket:lines() do local name, value = line:match '^(%S+):%s+(.-)\r?$' if name and value then if redirect and name:lower() == 'location' then io.stderr:write("Following redirect to ", value, " ..\n") return getpage(value) end else return (assert(socket:read '*a', 'HTTP response missing body?!')) end end if statuscode ~= '200' then error(reason) end end local usage = "Please provide a URL to download as argument" io.write(getpage(assert(arg and arg[1], usage))) -- vim: ts=2 sw=2 et lua-apr-0.23.2.dfsg/examples/threaded-webserver.lua000066400000000000000000000104011220664456000221650ustar00rootroot00000000000000--[[ Example: Multi threaded webserver Author: Peter Odding Last Change: November 6, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT Thanks to the [multi threading] [threading_module] and [thread queue] [thread_queues] modules in the Apache Portable Runtime it is possible to improve the performance of the [single threaded webserver] [simple_server] from the previous example. Here is a benchmark of the multi threaded code listed below (again using [ApacheBench] [ab], but now with the `-c` argument): $ CONCURRENCY=4 $ lua examples/threaded-webserver.lua $CONCURRENCY & $ ab -qt5 -c$CONCURRENCY http://localhost:8080/ | grep 'Requests per second\|Transfer rate' Requests per second: 9210.72 [#/sec] (mean) Transfer rate: 5594.79 [Kbytes/sec] received Comparing these numbers to the benchmark of the [single threaded webserver] [simple_server] we can see that the number of requests per second went from 3670 to 9210, more than doubling the throughput of the webserver on a dual core processor. If you want to know how we can make it even faster, have a look at the [asynchronous webserver] [async_server] example. [threading_module]: #multi_threading [thread_queues]: #thread_queues [simple_server]: #example_single_threaded_webserver [ab]: http://en.wikipedia.org/wiki/ApacheBench [thread_pool]: http://en.wikipedia.org/wiki/Thread_pool_pattern [async_server]: #example_asynchronous_webserver ]] local num_threads = tonumber(arg[1]) or 2 local port_number = tonumber(arg[2]) or 8080 local template = [[ Hello from Lua/APR!

Hello from Lua/APR!

This web page was served by worker %i.

The headers provided by your web browser:

%s
]] -- Load the Lua/APR binding. local apr = require 'apr' -- Initialize the server socket. local server = assert(apr.socket_create()) assert(server:bind('*', port_number)) assert(server:listen(num_threads * 2)) print("Running webserver with " .. num_threads .. " client threads on http://localhost:" .. port_number .. " ..") -- Create the thread queue (used to pass sockets between threads). local queue = apr.thread_queue(num_threads) -- Define the function to execute in each child thread. function worker(thread_id, queue, template) pcall(require, 'luarocks.require') local apr = require 'apr' while true do local client, msg, code = queue:pop() assert(client or code == 'EINTR', msg) if client then local status, message = pcall(function() local request = assert(client:read(), "Failed to receive request from client!") local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)') local headers = {} for line in client:lines() do local name, value = line:match '^(%S+):%s+(.-)$' if not name then break end table.insert(headers, '
' .. name .. ':
' .. value .. '
') end table.sort(headers) local content = template:format(thread_id, table.concat(headers)) client:write(protocol, ' 200 OK\r\n', 'Content-Type: text/html\r\n', 'Content-Length: ' .. #content .. '\r\n', 'Connection: close\r\n', '\r\n', content) assert(client:close()) end) if not status then print('Error while serving request:', message) end end end end -- Create the child threads and keep them around in a table (so that they are -- not garbage collected while we are still using them). local pool = {} for i = 1, num_threads do table.insert(pool, apr.thread(worker, i, queue, template)) end -- Enter the accept() loop in the parent thread. while true do local status, message = pcall(function() local client = assert(server:accept()) assert(queue:push(client)) end) if not status then print('Error while serving request:', message) end end -- vim: ts=2 sw=2 et lua-apr-0.23.2.dfsg/examples/webserver.lua000066400000000000000000000065601220664456000204220ustar00rootroot00000000000000--[[ Example: Single threaded webserver Author: Peter Odding Last Change: November 6, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT The following script implements a minimalistic webserver on top of Lua/APR [network sockets] [socket_module]. It should work out of the box on Windows and UNIX, although you might get a prompt from your firewall. Once the server is running you can open in your web browser to see the server in action. Because the server is single threaded I was curious how bad it would perform, so I tested it with [ApacheBench] [ab]: $ lua examples/webserver.lua & $ ab -qt5 http://localhost:8080/ | grep 'Requests per second\|Transfer rate' Requests per second: 3672.19 [#/sec] (mean) Transfer rate: 2201.88 [Kbytes/sec] received That's not too bad for 40 lines of code! For more complex webservers see the [multi threaded] [threaded_server] and [asynchronous] [async_server] webserver examples. *Note that all benchmarks are run on my Compaq Presario CQ60 laptop (which features an Intel Core 2 Duo T5800 processor clocked at 2 GHz and 3 GB of RAM) and that the Lua/APR binding was compiled without debugging symbols.* [socket_module]: #network_i_o_handling [ab]: http://en.wikipedia.org/wiki/ApacheBench [threaded_server]: #example_multi_threaded_webserver [async_server]: #example_asynchronous_webserver ]] local port_number = tonumber(arg[1]) or 8080 local bind_address = arg[2] or '*' -- Load the Lua/APR binding. local apr = require 'apr' -- Initialize the server socket. local server = assert(apr.socket_create()) assert(server:bind(bind_address, port_number)) assert(server:listen(1)) print("Running webserver on http://" .. bind_address .. ":" .. port_number .. " ..") -- Wait for clients to serve. local visitor = 1 local template = [[ Hello from Lua/APR!

Hello from Lua/APR!

You are visitor number %010i.

The headers provided by your web browser:

%s
]] while true do local status, message = pcall(function() local client = assert(server:accept()) -- Read the HTTP request so that the client can receive data. local request = assert(client:read(), "Failed to receive request from client!") local method, location, protocol = assert(request:match '^(%w+)%s+(%S+)%s+(%S+)') local headers = {} for line in client:lines() do local name, value = line:match '^(%S+):%s+(.-)$' if not name then break end table.insert(headers, '
' .. name .. ':
' .. value .. '
') end -- Generate the HTTP response. table.sort(headers) content = template:format(visitor, table.concat(headers)) client:write(protocol, ' 200 OK\r\n', 'Content-Type: text/html\r\n', 'Content-Length: ' .. #content .. '\r\n', 'Connection: close\r\n', '\r\n', content) assert(client:close()) visitor = visitor + 1 end) if not status then print('Error while serving request:', message) end end -- vim: ts=2 sw=2 et lua-apr-0.23.2.dfsg/make.cmd000066400000000000000000000003161220664456000154700ustar00rootroot00000000000000@ECHO OFF REM On Windows the Lua/APR binding is compiled using NMAKE /f Makefile.win. REM This batch script makes it possible to just type MAKE and be done with it. NMAKE /nologo /f Makefile.win %* lua-apr-0.23.2.dfsg/src/000077500000000000000000000000001220664456000146555ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/src/apr.lua000066400000000000000000000267141220664456000161540ustar00rootroot00000000000000--[[ Lua source code for the Lua/APR binding. Author: Peter Odding Last Change: December 7, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This Lua script is executed on require("apr"), loads the binary module using require("apr.core"), defines several library functions implemented on top of the binary module and returns the module table as the result of require(). --]] local apr = require 'apr.core' apr._VERSION = '0.23.2' local function executable(type, user, group, protection) if type == 'file' and user and group and protection then local current_user, current_group = assert(apr.user_get()) return (protection:find '^(r.x)(...)(...)$' and user == current_user) or (protection:find '^(...)(r.x)(...)$' and group == current_group) or (protection:find '^(...)(...)(r.[xt])$' and user ~= current_user and group ~= current_group) end return false end -- apr.md5(input [, binary]) -> digest {{{1 -- -- Calculate the [MD5] [md5] message digest of the string @input. On success -- the digest is returned as a string of 32 hexadecimal characters, or a string -- of 16 bytes if @binary evaluates to true. Otherwise a nil followed by an -- error message is returned. -- -- *This function is binary safe.* -- -- Part of the "Cryptography routines" module. function apr.md5(input, binary) assert(type(input) == 'string', "bad argument #1 to apr.md5() (string expected)") local context, digest, status, errmsg, errcode context, errmsg, errcode = apr.md5_init() if context then status, errmsg, errcode = context:update(input) if status then digest, errmsg, errcode = context:digest(binary) if digest then return digest end end end return nil, errmsg, errcode end -- apr.sha1(input [, binary]) -> digest {{{1 -- -- Calculate the [SHA1] [sha1] message digest of the string @input. On success -- the digest is returned as a string of 40 hexadecimal characters, or a string -- of 20 bytes if @binary evaluates to true. Otherwise a nil followed by an -- error message is returned. -- -- *This function is binary safe.* -- -- Part of the "Cryptography routines" module. function apr.sha1(input, binary) assert(type(input) == 'string', "bad argument #1 to apr.sha1() (string expected)") local context, digest, status, errmsg, errcode context, errmsg, errcode = apr.sha1_init() if context then status, errmsg, errcode = context:update(input) if status then digest, errmsg, errcode = context:digest(binary) if digest then return digest end end end return nil, errmsg, errcode end -- apr.file_truncate(path [, offset]) -> status {{{1 -- -- Truncate the file's length to the specified @offset (defaults to 0). On -- success true is returned, otherwise a nil followed by an error message is -- returned. -- -- Part of the "File I/O handling" module. function apr.file_truncate(path, offset) local status = nil local handle, errmsg, errcode = apr.file_open(path, 'r+') if handle then status, errmsg, errcode = handle:truncate(offset or 0) if status then return handle:close() end handle:close() end return status, errmsg, errcode end -- apr.filepath_which(program [, find_all]) -> pathname {{{1 -- -- Find the full pathname of @program by searching the directories in the -- [$PATH] [path_var] environment variable and return the pathname of the -- first program that's found. If @find_all is true then a list with the -- pathnames of all matching programs is returned instead. -- -- [path_var]: http://en.wikipedia.org/wiki/PATH_%28variable%29 -- -- Part of the "File path manipulation" module. function apr.filepath_which(program, find_all) local split = apr.filepath_list_split local is_windows = apr.platform_get() == 'WIN32' local extensions = is_windows and split(apr.env_get 'PATHEXT') local results = find_all and {} for _, directory in ipairs(split(apr.env_get 'PATH')) do local candidate = apr.filepath_merge(directory, program) local t, u, g, p = apr.stat(candidate, 'type', 'user', 'group', 'protection') if t == 'file' and is_windows or executable(t, u, g, p) then if not find_all then return candidate end results[#results + 1] = candidate end if is_windows and #extensions >= 1 then for _, extension in ipairs(extensions) do candidate = apr.filepath_merge(directory, program .. extension) if apr.stat(candidate, 'type') == 'file' then if not find_all then return candidate end results[#results + 1] = candidate end end end end return results end -- apr.filepath_executable(path) -> is_executable {{{1 -- -- Check whether the file pointed to by @path is executable. -- Returns true when the file is executable, false otherwise. -- -- Part of the "File path manipulation" module. function apr.filepath_executable(path) return executable(apr.stat(path, 'type', 'user', 'group', 'protection')) end -- apr.glob(pattern [, ignorecase]) -> iterator {{{1 -- -- Split @pattern into a directory path and a filename pattern and return an -- iterator which returns all filenames in the directory that match the -- extracted filename pattern. The `apr.fnmatch()` function is used for -- filename matching so the documentation there applies. -- -- *This function is not binary safe.* -- -- Part of the "Filename matching" module. function apr.glob(pattern, ignorecase) local fnmatch = apr.fnmatch local yield = coroutine.yield local directory, pattern = apr.filepath_parent(pattern) local handle = assert(apr.dir_open(directory)) return coroutine.wrap(function() for path, name in handle:entries('path', 'name') do if fnmatch(pattern, name, ignorecase) then yield(path) end end handle:close() end) end -- apr.getopt(usage [, config ]) -> options, arguments {{{1 -- -- Parse the [command line arguments] [cmdargs] according to the option letters -- and/or long options defined in the string @usage (see the example below) and -- return a table with the matched options and a table with any remaining -- positional arguments. When an option is matched multiple times, the -- resulting value in @options depends on the following context: -- -- * If the option doesn't take an argument, the value will be a number -- indicating the number of times that the option was matched -- -- * If the option takes an argument and only one option/argument pair is -- matched, the value will be the argument (a string). When more than one -- pair is matched for the same option letter/name, the values will be -- collected in a table -- -- The optional @config table can be used to change the following defaults: -- -- * When @usage mentions `-h` or `--help` and either of these options is -- matched in the arguments, `apr.getopt()` will print the usage message -- and call `os.exit()`. To avoid this set `config.show_usage` to false -- (not nil!) -- -- * When an error is encountered during argument parsing, `apr.getopt()` will -- print a warning about the invalid argument and call `os.exit()`. To avoid -- this set `config.handle_errors` to false (not nil!) -- -- * By default the arguments in the global variable [arg] [arg-global] will -- be used, but you can set `config.args` to a table of arguments to be -- used instead -- -- Here is a short example of a valid Lua script that doesn't really do -- anything useful but demonstrates the use of `apr.getopt()`: -- -- apr = require 'apr' -- opts, args = apr.getopt [[ -- Usage: echo.lua [OPTIONS] ARG... -- -h, --help show this message and exit -- -v, --verbose make more noise -- --version print version and exit -- ]] -- if opts.version then -- print "This is version 0.1" -- else -- if opts.verbose then -- print("Got", #args, "arguments") -- end -- if opts.verbose >= 2 then -- print "Here they are:" -- end -- for i = 1, #args do print(args[i]) end -- end -- -- The `apr.getopt()` function is very similar to [Lapp] [lapp] by Steve -- Donovan although Lapp is more full featured, for example it validates and -- converts argument types. -- -- [cmdargs]: http://en.wikipedia.org/wiki/Command-line_argument -- [arg-global]: http://www.lua.org/manual/5.1/manual.html#6 -- [lapp]: http://lua-users.org/wiki/LappFramework -- -- Part of the "Command argument parsing" module. -- Match an option letter or a long option at the start of the line. local function match_arg(table, key, line, pattern) local opt, remainder = line:match(pattern) if opt and remainder then local name, args = opt:match '^(.-)=(.-)$' if name and args then table[key] = name table.has_arg = true else if key == 'optch' then opt = opt:gsub(',$', '') end table[key] = opt end return remainder end return line end local function parse_usage(usage) local optdefs = {} -- Parse the usage message into a nested table structure. for line in usage:gmatch '[^\n]+' do local t = {} line = match_arg(t, 'optch', line, '^%s*%-([^-]%S*)(.-)$') line = match_arg(t, 'name', line, '^%s*%-%-(%S+)(.-)$') t.description = line:match '^%s*(.-)%s*$' optdefs[#optdefs + 1] = t if t.optch then optdefs[t.optch] = t end if t.name then optdefs[t.name] = t end end -- Generate any missing "optch" values. for i, t in ipairs(optdefs) do if t.name and not t.optch then for i = 1, 255 do local c = string.char(i) if not optdefs[c] then t.optch = c t.fake_optch = true optdefs[c] = t break end end end end return optdefs end local real_getopt = apr.getopt function apr.getopt(usage, config) -- Validate arguments. assert(type(usage) == 'string') if config then assert(type(config) == 'table') else config = {} end local arguments = config.args or _G.arg assert(type(arguments) == 'table', "No arguments to parse!") assert(arguments[0], "Program name missing from arguments!") -- Get the option definitions from the usage message. local optdefs = parse_usage(usage) -- Parse the Lua script's arguments using the definitions. local opts, args, code = real_getopt(optdefs, arguments, config.handle_errors == false) -- Handle errors during command argument parsing. if not (opts and args) then if config.handle_errors ~= false then os.exit(1) else local msg = args return nil, msg, code end end -- Copy option letter values to long option aliases. for i, t in ipairs(optdefs) do if t.optch and t.name then opts[t.name] = opts[t.optch] end if t.fake_optch then opts[t.optch] = nil end end -- Print usage message or return results. if config.show_usage ~= false and (opts.h or opts.help) then io.write(usage) os.exit(0) else return opts, args end end -- apr.serialize(...) -> string {{{1 -- -- Serialize any number of Lua values (a tuple) into a source code string. When -- passed to `apr.unserialize()` this string results in a tuple of values that -- is structurally identical to the original tuple. -- -- Part of the "Serialization" module. function apr.serialize(...) return require 'apr.serialize' ({ n = select('#', ...), ... }) end -- apr.unserialize(string) -> ... {{{1 -- -- Unserialize a source code string into one or more Lua values. -- -- Part of the "Serialization" module. function apr.unserialize(data) local tuple = loadstring(data)() return unpack(tuple, 1, tuple.n) end -- }}}1 return apr -- vim: ts=2 sw=2 et tw=79 fen fdm=marker lua-apr-0.23.2.dfsg/src/base64.c000066400000000000000000000112071220664456000161060ustar00rootroot00000000000000/* Base64 encoding module for the Lua/APR binding. * * Author: Peter Odding * Last Change: January 2, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The functions in this module can be used to encode strings in base64 and to * decode base64 encoded strings. The base64 format uses the printable * characters `A-Z`, `a-z`, `0-9`, `+` and `/` to encode binary data. This can * be useful when your data is used in a context that isn't 8-bit clean, for * example in e-mail attachments and [data:] [data_uris] URLs. You can read * more about base64 encoding in [this] [base64] Wikipedia article. * * [base64]: http://en.wikipedia.org/wiki/Base64 * [data_uris]: http://en.wikipedia.org/wiki/Data_URI_scheme */ #include "lua_apr.h" #include /* apr.base64_encode(plain) -> coded {{{1 * * Encode the string @plain using base64 encoding. On success the coded string * is returned, otherwise a nil followed by an error message is returned. As an * example, here is how to convert an image file into a [data: URL] * [data_uris]: * * > image = io.open 'lua-logo.png' * > encoded_data = apr.base64_encode(image:read '*a') * > data_url = 'data:image/png;base64,' .. encoded_data * > = 'Lua logo' * Lua logo * * This is what the result looks like (might not work in older web browsers): * Lua logo */ int lua_apr_base64_encode(lua_State *L) { size_t plain_len, coded_len; apr_pool_t *memory_pool; const char *plain; char *coded; memory_pool = to_pool(L); plain = luaL_checklstring(L, 1, &plain_len); coded_len = apr_base64_encode_len(plain_len); coded = apr_palloc(memory_pool, coded_len); if (coded == NULL) return push_error_memory(L); coded_len = apr_base64_encode(coded, plain, plain_len); if (coded_len > 0 && coded[coded_len - 1] == '\0') coded_len--; lua_pushlstring(L, coded, coded_len); return 1; } /* apr.base64_decode(coded) -> plain {{{1 * * Decode the base64 encoded string @coded. On success the decoded string is * returned, otherwise a nil followed by an error message is returned. */ int lua_apr_base64_decode(lua_State *L) { size_t plain_len, coded_len; apr_pool_t *memory_pool; const char *coded; char *plain; memory_pool = to_pool(L); coded = luaL_checklstring(L, 1, &coded_len); plain_len = apr_base64_decode_len(coded); plain = apr_palloc(memory_pool, plain_len); if (plain == NULL) return push_error_memory(L); plain_len = apr_base64_decode(plain, coded); if (plain_len > 0 && plain[plain_len - 1] == '\0') plain_len--; lua_pushlstring(L, plain, plain_len); return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/buffer.c000066400000000000000000000344201220664456000162750ustar00rootroot00000000000000/* Buffered I/O interface for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 6, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Notes: * - Since the addition of the buffer.unmanaged property for shared memory * segments, "buffered I/O interface" has really become a misnomer :-) * - The read_*() functions keep their own relative `offset' instead of * advancing buffer.index because reading might fail and fill_buffer() * invalidates absolute buffer indexes when it shifts down the buffer. * - read_buffer() was based on the following references: * - http://www.lua.org/source/5.1/liolib.c.html#g_read * - http://www.lua.org/manual/5.1/manual.html#pdf-file:read * * Status: * I don't like this code at all but it's a core part of the value in the * Lua/APR binding! The code is quite confusing though and new bugs keep * cropping up. Things that should at least be fixed: * * TODO Binary to text translation is currently impossible in unmanaged * buffers (shared memory). Decide whether to document or fix this issue? * * TODO The various read functions don't return immediately when status != * (APR_SUCCESS, APR_EOF) while they probably should? */ #include "lua_apr.h" #include /* Subtract a from b without producing negative values. */ #define SAFE_SUB(a, b) ((a) <= (b) ? (b) - (a) : 0) /* The size of the static buffer used to convert strings to numbers. */ #define LUA_APR_MAXSTR2NUM (LUAI_MAXNUMBER2STR * 2) #define CURSOR(B) (&B->data[B->index]) #define AVAIL(B) SAFE_SUB(B->index, B->limit) #define SPACE(B) (B->unmanaged ? SAFE_SUB(B->index, B->size) : SAFE_SUB(B->limit, B->size)) #define SUCCESS_OR_EOF(B, S) ((S) == APR_SUCCESS || CHECK_FOR_EOF(B, S)) #define CHECK_FOR_EOF(B, S) (APR_STATUS_IS_EOF(S) || (B)->unmanaged) #define DEBUG_BUFFER(B) do { \ LUA_APR_DBG("buffer.index = %i", (B)->index); \ LUA_APR_DBG("buffer.limit = %i", (B)->limit); \ LUA_APR_DBG("buffer.size = %i (really %i)", (B)->size, (B)->size); \ } while (0) /* Internal functions. {{{1 */ /* find_win32_eol() {{{2 */ static int find_win32_eol(lua_apr_buffer *B, size_t offset, size_t *result) { char *match, *cursor = CURSOR(B) + offset; size_t avail = AVAIL(B) - offset; match = memchr(cursor, '\r', avail); if (match != NULL) { size_t test = match - cursor; if (test < avail && *(match + 1) == '\n') { *result = test; return 1; } } return 0; } /* binary_to_text() {{{2 */ static void binary_to_text(lua_apr_buffer *B) { size_t offset = 0, test; while (find_win32_eol(B, offset, &test)) { /* TODO binary_to_text() is very inefficient */ size_t i = B->index + offset + test; char *p = &B->data[i]; memmove(p, p + 1, B->limit - i); offset += test; B->limit--; } } /* shift_buffer() {{{2 */ static void shift_buffer(lua_apr_buffer *B) { if (B->index > 0 && AVAIL(B) > 0) { memmove(B->data, CURSOR(B), AVAIL(B)); B->limit = AVAIL(B); B->index = 0; } else if (AVAIL(B) == 0) { B->index = 0; B->limit = 0; } } /* grow_buffer() {{{2 */ static apr_status_t grow_buffer(lua_apr_buffer *B) { apr_status_t status = APR_SUCCESS; size_t newsize = LUA_APR_BUFSIZE; char *newdata; /* Don't do anything for unmanaged buffers. */ if (B->unmanaged) return status; if (B->size >= newsize) newsize = B->size / 2 * 3; newdata = realloc(B->data, newsize); if (newdata != NULL) { B->data = newdata; B->size = newsize; /* TODO Initialize new space to all zero bytes to make Valgrind happy? memset(&B->data[B->limit + 1], 0, B->size - B->limit - 1); */ } else { status = APR_ENOMEM; } return status; } /* fill_buffer() {{{2 */ static apr_status_t fill_buffer(lua_apr_readbuf *input, apr_size_t len) { lua_apr_buffer *B = &input->buffer; apr_status_t status = APR_SUCCESS; /* Don't do anything for unmanaged buffers. */ if (B->unmanaged) return status; /* Shift the buffer's contents down? */ shift_buffer(B); /* Try to grow the buffer? */ if (!(B->limit < B->size)) status = grow_buffer(B); /* Add more data to buffer. */ len -= AVAIL(B); if (len > SPACE(B)) len = SPACE(B); status = input->read(input->object, &B->data[B->limit], &len); if (status == APR_SUCCESS) B->limit += len; return status; } /* read_line() {{{2 */ static apr_status_t read_line(lua_State *L, lua_apr_readbuf *input) { lua_apr_buffer *B = &input->buffer; apr_status_t status = APR_SUCCESS; size_t offset = 0, length; int skip_crlf; char *match; do { /* Scan buffered input for line feed (LF) character. */ match = memchr(CURSOR(B) + offset, '\n', AVAIL(B) - offset); if (match != NULL) { /* Found a line feed character! */ length = match - CURSOR(B); /* Check for preceding carriage return (CR) character. */ skip_crlf = (input->text_mode && length >= 1 && *(match - 1) == '\r'); lua_pushlstring(L, CURSOR(B), skip_crlf ? length - 1 : length); B->index += length + 1; break; } else if (CHECK_FOR_EOF(&input->buffer, status)) { /* Got EOF while searching for end of line? */ if (AVAIL(B) >= 1) { lua_pushlstring(L, CURSOR(B), AVAIL(B)); B->index += AVAIL(B); } else lua_pushnil(L); break; } /* Skip scanned input on next iteration. */ offset = AVAIL(B); /* Get more input. */ status = fill_buffer(input, LUA_APR_BUFSIZE); } while (SUCCESS_OR_EOF(&input->buffer, status)); return status; } /* read_number() {{{2 */ static apr_status_t read_number(lua_State *L, lua_apr_readbuf *input) { char buffer[LUA_APR_MAXSTR2NUM + 1]; lua_apr_buffer *B = &input->buffer; apr_status_t status = APR_SUCCESS; size_t offset = 0, test; lua_Number value; char *endptr; do { /* Skip any leading whitespace in the buffered input. */ while (offset < AVAIL(B) && apr_isspace(*(CURSOR(B) + offset))) offset++; /* Calculate available bytes but guard against overflow. */ test = SAFE_SUB(offset, AVAIL(B)); /* Make sure enough input remains to read full number [or we got EOF]. */ if (test >= LUA_APR_MAXSTR2NUM || CHECK_FOR_EOF(B, status)) { if (test > 0) { /* lua_str2number() needs a terminating nul byte. */ if (test > LUA_APR_MAXSTR2NUM) test = LUA_APR_MAXSTR2NUM; memset(buffer, 0, LUA_APR_MAXSTR2NUM + 1); memcpy(buffer, CURSOR(B) + offset, test); endptr = &buffer[0]; /* Try to parse number at selected position. */ value = lua_str2number(buffer, &endptr); if (endptr > buffer) { lua_pushnumber(L, value); B->index += offset + (endptr - &buffer[0]); break; } } lua_pushnil(L); break; } /* Get more input. */ status = fill_buffer(input, LUA_APR_BUFSIZE); } while (SUCCESS_OR_EOF(&input->buffer, status)); return status; } /* read_chars() {{{2 */ static apr_status_t read_chars(lua_State *L, lua_apr_readbuf *input, apr_size_t n) { lua_apr_buffer *B = &input->buffer; apr_status_t status = APR_SUCCESS; int cornercase; for (;;) { /* Return nil on EOF (this only makes sense after the 1st iteration). */ if (CHECK_FOR_EOF(B, status) && AVAIL(B) == 0) { lua_pushnil(L); break; } /* Check if we have enough input or reached EOF with buffered input. */ cornercase = input->text_mode && B->data[SAFE_SUB(1, AVAIL(B))] == '\r'; if ((n <= AVAIL(B) && !cornercase) || CHECK_FOR_EOF(B, status)) { if (n > AVAIL(B)) n = AVAIL(B); lua_pushlstring(L, CURSOR(B), n); B->index += n; break; } /* Get more input? */ if (!B->unmanaged) { status = fill_buffer(input, n + cornercase); if (!SUCCESS_OR_EOF(B, status)) break; if (input->text_mode) /* && (n + cornercase) > 0 */ binary_to_text(B); } } return status; } /* read_all() {{{2 */ static apr_status_t read_all(lua_State *L, lua_apr_readbuf *input) { lua_apr_buffer *B = &input->buffer; apr_status_t status = APR_SUCCESS; if (!B->unmanaged) { do { status = fill_buffer(input, APR_SIZE_MAX); } while (status == APR_SUCCESS); if (input->text_mode) binary_to_text(B); } lua_pushlstring(L, CURSOR(B), AVAIL(B)); B->index = B->limit + 1; return status; } /* read_lines_cb() {{{2 */ static int read_lines_cb(lua_State *L) { lua_apr_readbuf *B; apr_status_t status; B = lua_touserdata(L, lua_upvalueindex(1)); status = read_line(L, B); if (status == APR_SUCCESS) return 1; else if (CHECK_FOR_EOF(&B->buffer, status)) return 0; else return push_error_status(L, status); } /* init_buffers() {{{1 */ void init_buffers(lua_State *L, lua_apr_readbuf *input, lua_apr_writebuf *output, void *object, int text_mode, lua_apr_buf_rf read, lua_apr_buf_wf write, lua_apr_buf_ff flush) { #if !defined(WIN32) && !defined(OS2) && !defined(NETWARE) text_mode = 0; #endif /* Initialize the input buffer structure. */ input->text_mode = text_mode; input->object = object; input->read = read; input->buffer.unmanaged = 0; input->buffer.data = NULL; input->buffer.index = 0; input->buffer.limit = 0; input->buffer.size = 0; /* Initialize the output buffer structure. */ output->text_mode = text_mode; output->object = object; output->write = write; output->flush = flush; output->buffer.unmanaged = 0; output->buffer.data = NULL; output->buffer.index = 0; output->buffer.limit = 0; output->buffer.size = 0; } /* init_unmanaged_buffers() {{{1 */ void init_unmanaged_buffers(lua_State *L, lua_apr_readbuf *input, lua_apr_writebuf *output, char *data, size_t size) { /* Initialize the input buffer structure. */ input->text_mode = 0; input->object = NULL; input->read = NULL; input->buffer.unmanaged = 1; input->buffer.data = data; input->buffer.index = 0; input->buffer.limit = size; input->buffer.size = size; /* Initialize the output buffer structure. */ output->text_mode = 0; output->object = NULL; output->write = NULL; output->flush = NULL; output->buffer.unmanaged = 1; output->buffer.data = data; output->buffer.index = 0; output->buffer.limit = 0; output->buffer.size = size; } /* free_buffer() {{{1 */ void free_buffer(lua_State *L, lua_apr_buffer *B) { if (!B->unmanaged && B->data != NULL) { free(B->data); B->data = NULL; B->index = 0; B->limit = 0; B->size = 0; } } /* read_lines() {{{1 */ int read_lines(lua_State *L, lua_apr_readbuf *B) { /* Return the iterator function. */ lua_pushlightuserdata(L, B); lua_pushcclosure(L, read_lines_cb, 1); return 1; } /* read_buffer() {{{1 */ int read_buffer(lua_State *L, lua_apr_readbuf *B) { apr_status_t status = APR_SUCCESS; int n, top, nresults = 0; top = lua_gettop(L); if (top == 1) { status = read_line(L, B); nresults = 1; } else { luaL_checkstack(L, top - 1, "too many arguments"); for (n = 2; n <= top && status == APR_SUCCESS; n++) { if (lua_type(L, n) == LUA_TNUMBER) { /* read given number of bytes */ status = read_chars(L, B, (apr_size_t)lua_tointeger(L, n)); nresults++; } else { const char *p = lua_tostring(L, n); luaL_argcheck(L, p && p[0] == '*', n, "invalid option"); switch (p[1]) { case 'n': /* read number */ status = read_number(L, B); nresults++; break; case 'l': /* read line */ status = read_line(L, B); nresults++; break; case 'a': /* read remaining data */ status = read_all(L, B); nresults++; break; default: return luaL_argerror(L, n, "invalid format"); } } } } if (!SUCCESS_OR_EOF(&B->buffer, status)) { /* Replace results with (nil, message, code). */ lua_settop(L, 1); nresults = push_error_status(L, status); } return nresults; } /* write_buffer() {{{1 */ int write_buffer(lua_State *L, lua_apr_writebuf *output) { lua_apr_buffer *B = &output->buffer; apr_status_t status = APR_SUCCESS; int i, add_eol, n = lua_gettop(L); size_t length, size; const char *data; char *match; if (B->data == NULL) { /* allocate write buffer on first use */ B->data = malloc(LUA_APR_BUFSIZE); if (B->data == NULL) return APR_ENOMEM; B->size = LUA_APR_BUFSIZE; } for (i = 2; i <= n && status == APR_SUCCESS; i++) { data = luaL_checklstring(L, i, &length); while (length > 0 && status == APR_SUCCESS) { if (SPACE(B) > 0) { /* copy range of bytes to buffer? */ size = length; add_eol = 0; if (size > SPACE(B)) { /* never write past end of buffer */ size = SPACE(B); } if (output->text_mode) { /* copy no more than one line in text mode */ match = memchr(data, '\n', size); if (match != NULL) { size = match - data; /* don't copy EOL directly */ if (size + 2 <= SPACE(B)) add_eol = 1; /* append EOL after copying line? */ } } if (size > 0) { /* copy range of bytes to buffer! */ memcpy(&B->data[B->limit], data, size); B->limit += size; data += size; length -= size; } if (add_eol) { /* add end of line sequence to buffer? */ memcpy(&B->data[B->limit], "\r\n", 2); B->limit += 2; data += 1; length -= 1; } } if (AVAIL(B) > 0 && SPACE(B) <= 1) /* flush buffer contents? */ status = flush_buffer(L, output, 1); } } return push_status(L, status); } /* flush_buffer() {{{1 */ apr_status_t flush_buffer(lua_State *L, lua_apr_writebuf *output, int soft) { lua_apr_buffer *B = &output->buffer; apr_status_t status = APR_SUCCESS; apr_size_t len; /* Don't do anything for unmanaged buffers. */ if (output->buffer.unmanaged) return status; /* Flush the internal write buffer. */ while ((len = AVAIL(B)) > 0 && status == APR_SUCCESS) { status = output->write(output->object, CURSOR(B), &len); B->index += len; } /* Shift any remaining data down. */ shift_buffer(B); /* Not sure whether deeper layers perform buffering of their own?! */ if (status == APR_SUCCESS && !soft) status = output->flush(output->object); return status; } lua-apr-0.23.2.dfsg/src/crypt.c000066400000000000000000000330751220664456000161720ustar00rootroot00000000000000/* Cryptography routines module for the Lua/APR binding. * * Author: Peter Odding * Last Change: June 30, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * These functions support the [MD5] [md5] and [SHA1] [sha1] cryptographic hash * functions. You can also use them to encrypt plain text passwords using a * [salt] [salt], validate plain text passwords against their encrypted, salted * digest and read passwords from standard input while masking the characters * typed by the user. * * The MD5 and SHA1 functions can be used to hash binary data. This is useful * because the hash is only 16 or 32 bytes long, yet it still changes * significantly when the binary data changes by just one byte. * * If that doesn't look useful consider the following scenario: The Lua authors * have just finished a new release of Lua and are about to publish the source * code on . Before they publish the [tarball] [tar] they first * calculate its MD5 and SHA1 hashes. They then publish the archive and hashes * on the [downloads page] [lua_downloads]. When a user downloads the tarball * they can verify whether it was corrupted or manipulated since it was * published on by comparing the published hash against the * hash of the tarball they just downloaded: * * > handle = io.open('lua-5.1.4.tar.gz', 'rb') * > data = handle:read('*a'); handle:close() * > = apr.md5(data) == 'd0870f2de55d59c1c8419f36e8fac150' * true * > = apr.sha1(data) == '2b11c8e60306efb7f0734b747588f57995493db7' * true * * [md5]: http://en.wikipedia.org/wiki/MD5 * [sha1]: http://en.wikipedia.org/wiki/SHA1 * [salt]: http://en.wikipedia.org/wiki/Salt_(cryptography) * [tar]: http://en.wikipedia.org/wiki/Tar_(file_format) * [lua_downloads]: http://www.lua.org/ftp/ */ #include "lua_apr.h" #include #include #include /* Internal functions {{{1 */ /* The APR cryptography functions zero buffers before returning and the Lua/APR * binding does the same thing so that it doesn't negate the effort of APR. */ #define clear_mem(p, l) memset(p, 42, l) #define clear_stack(b) clear_mem(b, sizeof(b)) typedef struct lua_apr_md5_ctx { lua_apr_refobj header; apr_md5_ctx_t context; int finalized; } lua_apr_md5_ctx; typedef struct lua_apr_sha1_ctx { lua_apr_refobj header; apr_sha1_ctx_t context; int finalized; } lua_apr_sha1_ctx; static int format_digest(char *formatted, const unsigned char *digest, int length) { int i; for (i = 0; i < length; i++) if (2 != sprintf(&formatted[i*2], "%02x", digest[i])) return 0; return 1; } static lua_apr_md5_ctx *md5_check(lua_State *L, int idx, int valid) { lua_apr_md5_ctx *context; context = check_object(L, idx, &lua_apr_md5_type); if (valid && context->finalized) luaL_error(L, "attempt to use a finalized MD5 context"); return context; } static lua_apr_sha1_ctx *sha1_check(lua_State *L, int idx, int valid) { lua_apr_sha1_ctx *context; context = check_object(L, idx, &lua_apr_sha1_type); if (valid && context->finalized) luaL_error(L, "attempt to use a finalized SHA1 context"); return context; } /* apr.md5_encode(password, salt) -> digest {{{1 * * Encode the string @password using the [MD5] [md5] algorithm and a [salt] * [salt] string. On success the digest is returned, otherwise a nil followed * by an error message is returned. */ int lua_apr_md5_encode(lua_State *L) { const char *password, *salt; apr_status_t status; char digest[120]; int pushed; password = luaL_checkstring(L, 1); salt = luaL_checkstring(L, 2); status = apr_md5_encode(password, salt, digest, count(digest)); if (status != APR_SUCCESS) { pushed = push_error_status(L, status); } else { lua_pushstring(L, digest); pushed = 1; } clear_stack(digest); return pushed; } /* apr.password_validate(password, digest) -> valid {{{1 * * Validate the string @password against a @digest created by one of the * APR-supported algorithms ([MD5] [md5] and [SHA1] [sha1]). On success true is * returned, otherwise a nil followed by an error message is returned. * * Hashes created by crypt are supported only on platforms that provide * [crypt(3)] [crypt_fun], so don't rely on that function unless you know that * your application will be run only on platforms that support it. On platforms * that don't support crypt(3), this falls back to a clear text string * comparison. * * [crypt_fun]: http://linux.die.net/man/3/crypt */ int lua_apr_password_validate(lua_State *L) { const char *password, *digest; apr_status_t status; password = luaL_checkstring(L, 1); digest = luaL_checkstring(L, 2); status = apr_password_validate(password, digest); return push_status(L, status); } /* apr.password_get(prompt) -> password {{{1 * * Display the string @prompt on the command-line prompt and read in a password * from standard input. If your platform allows it, the typed password will be * masked by a placeholder like `*`. On success the password is returned, * otherwise a nil followed by an error message is returned. */ int lua_apr_password_get(lua_State *L) { apr_status_t status; const char *prompt; char password[256]; /* arbitrary limit */ apr_size_t length = count(password); int pushed; prompt = luaL_checkstring(L, 1); /* Note that apr_password_get() does NOT modify length! :-S */ status = apr_password_get(prompt, password, &length); if (status != APR_SUCCESS) { pushed = push_error_status(L, status); } else { lua_pushstring(L, password); pushed = 1; } clear_stack(password); return pushed; } /* apr.md5_init() -> md5_context {{{1 * * Create and return an object that can be used to calculate [MD5] [md5] * message digests in steps. If an error occurs a nil followed by an error * message is returned. This can be useful when you want to calculate message * digests of large inputs, for example files like [ISO images] [isoimg] and * backups: * * > function md5_file(path, binary) * >> local handle = assert(io.open(path, 'rb')) * >> local context = assert(apr.md5_init()) * >> while true do * >> local block = handle:read(1024 * 1024) * >> if not block then break end * >> assert(context:update(block)) * >> end * >> return context:digest(binary) * >> end * > * > md5_file 'ubuntu-10.04-desktop-i386.iso' * 'd044a2a0c8103fc3e5b7e18b0f7de1c8' * * [isoimg]: http://en.wikipedia.org/wiki/ISO_image */ int lua_apr_md5_init(lua_State *L) { apr_status_t status; lua_apr_md5_ctx *object; object = new_object(L, &lua_apr_md5_type); if (object == NULL) return push_error_memory(L); status = apr_md5_init(&object->context); if (status != APR_SUCCESS) return push_error_status(L, status); return 1; } /* md5_context:update(input) -> status {{{1 * * Continue an [MD5] [md5] message digest operation by processing another * message block and updating the context. On success true is returned, * otherwise a nil followed by an error message is returned. */ static int md5_update(lua_State *L) { apr_status_t status; lua_apr_md5_ctx *object; const char *input; size_t length; object = md5_check(L, 1, 1); input = luaL_checklstring(L, 2, &length); status = apr_md5_update(&object->context, input, length); return push_status(L, status); } /* md5_context:digest([binary]) -> digest {{{1 * * End an [MD5] [md5] message digest operation. On success the digest is * returned as a string of 32 hexadecimal characters, or a string of 16 bytes * if @binary evaluates to true. Otherwise a nil followed by an error message * is returned. * * If you want to re-use the context object after calling this method * see `md5_context:reset()`. */ static int md5_digest(lua_State *L) { apr_status_t status; lua_apr_md5_ctx *object; unsigned char digest[APR_MD5_DIGESTSIZE]; char formatted[APR_MD5_DIGESTSIZE*2 + 1]; int binary, pushed = 1; object = md5_check(L, 1, 1); binary = lua_toboolean(L, 2); status = apr_md5_final(digest, &object->context); if (status != APR_SUCCESS) { pushed = push_error_status(L, status); } else if (binary) { lua_pushlstring(L, (const char *)digest, count(digest)); } else if (format_digest(formatted, digest, count(digest))) { lua_pushlstring(L, (const char *)formatted, count(formatted) - 1); clear_stack(formatted); } else { pushed = push_error_message(L, "could not format MD5 digest"); } clear_stack(digest); object->finalized = 1; return pushed; } /* md5_context:reset() -> status {{{1 * * Use this method to reset the context after calling `md5_context:digest()`. * This enables you to re-use the same context to perform another message * digest calculation. On success true is returned, otherwise a nil followed by * an error message is returned. */ static int md5_reset(lua_State *L) { apr_status_t status; lua_apr_md5_ctx *object; object = md5_check(L, 1, 0); status = apr_md5_init(&object->context); if (status == APR_SUCCESS) object->finalized = 0; return push_status(L, status); } /* md5_context:__tostring() {{{1 */ static int md5_tostring(lua_State *L) { lua_apr_md5_ctx *object; object = md5_check(L, 1, 0); if (!object->finalized) lua_pushfstring(L, "%s (%p)", lua_apr_md5_type.friendlyname, object); else lua_pushfstring(L, "%s (closed)", lua_apr_md5_type.friendlyname); return 1; } /* md5_context:__gc() {{{1 */ static int md5_gc(lua_State *L) { lua_apr_md5_ctx *object = md5_check(L, 1, 0); release_object((lua_apr_refobj*)object); return 1; } /* apr.sha1_init() -> sha1_context {{{1 * * Create and return an object that can be used to calculate [SHA1] [sha1] * message digests in steps. See also the example for `apr.md5_init()`. */ int lua_apr_sha1_init(lua_State *L) { lua_apr_sha1_ctx *object; object = new_object(L, &lua_apr_sha1_type); if (object == NULL) return push_error_memory(L); apr_sha1_init(&object->context); return 1; } /* sha1_context:update(input) -> status {{{1 * * Continue an [SHA1] [sha1] message digest operation by processing another * message block and updating the context. */ static int sha1_update(lua_State *L) { lua_apr_sha1_ctx *object; const char *input; size_t length; object = sha1_check(L, 1, 1); input = luaL_checklstring(L, 2, &length); apr_sha1_update(&object->context, input, length); return push_status(L, APR_SUCCESS); } /* sha1_context:digest([binary]) -> digest {{{1 * * End an [SHA1] [sha1] message digest operation. On success the digest is * returned as a string of 40 hexadecimal characters, or a string of 20 bytes * if @binary evaluates to true. Otherwise a nil followed by an error message * is returned. * * If you want to re-use the context object after calling this method * see `sha1_context:reset()`. */ static int sha1_digest(lua_State *L) { lua_apr_sha1_ctx *object; unsigned char digest[APR_SHA1_DIGESTSIZE]; char formatted[APR_SHA1_DIGESTSIZE*2 + 1]; int binary, pushed = 1; object = sha1_check(L, 1, 1); binary = lua_toboolean(L, 2); apr_sha1_final(digest, &object->context); if (binary) { lua_pushlstring(L, (const char *)digest, count(digest)); } else if (format_digest(formatted, digest, count(digest))) { lua_pushlstring(L, (const char *)formatted, count(formatted) - 1); clear_stack(formatted); } else { pushed = push_error_message(L, "could not format SHA1 digest"); } clear_stack(digest); object->finalized = 1; return pushed; } /* sha1_context:reset() -> status {{{1 * * Use this method to reset the context after calling `sha1_context:digest()`. * This enables you to re-use the same context to perform another message * digest calculation. */ static int sha1_reset(lua_State *L) { lua_apr_sha1_ctx *object; object = sha1_check(L, 1, 0); apr_sha1_init(&object->context); object->finalized = 0; return push_status(L, APR_SUCCESS); } /* sha1_context:__tostring() {{{1 */ static int sha1_tostring(lua_State *L) { lua_apr_sha1_ctx *object; object = sha1_check(L, 1, 0); if (!object->finalized) lua_pushfstring(L, "%s (%p)", lua_apr_sha1_type.friendlyname, object); else lua_pushfstring(L, "%s (closed)", lua_apr_sha1_type.friendlyname); return 1; } /* sha1_context:__gc() {{{1 */ static int sha1_gc(lua_State *L) { lua_apr_sha1_ctx *object = sha1_check(L, 1, 0); release_object((lua_apr_refobj*)object); return 1; } /* }}}1 */ static luaL_reg md5_methods[] = { { "reset", md5_reset }, { "update", md5_update }, { "digest", md5_digest }, { NULL, NULL }, }; static luaL_reg md5_metamethods[] = { { "__tostring", md5_tostring }, { "__eq", objects_equal }, { "__gc", md5_gc }, { NULL, NULL }, }; lua_apr_objtype lua_apr_md5_type = { "lua_apr_md5_ctx*", /* metatable name in registry */ "md5 context", /* friendly object name */ sizeof(lua_apr_md5_ctx), /* structure size */ md5_methods, /* methods table */ md5_metamethods /* metamethods table */ }; static luaL_reg sha1_methods[] = { { "reset", sha1_reset }, { "update", sha1_update }, { "digest", sha1_digest }, { NULL, NULL }, }; static luaL_reg sha1_metamethods[] = { { "__tostring", sha1_tostring }, { "__eq", objects_equal }, { "__gc", sha1_gc }, { NULL, NULL }, }; lua_apr_objtype lua_apr_sha1_type = { "lua_apr_sha1_ctx*", /* metatable name in registry */ "sha1 context", /* friendly object name */ sizeof(lua_apr_sha1_ctx), /* structure size */ sha1_methods, /* methods table */ sha1_metamethods /* metamethods table */ }; /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/date.c000066400000000000000000000055261220664456000157460ustar00rootroot00000000000000/* Date parsing module for the Lua/APR binding. * * Author: Peter Odding * Last Change: February 13, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include /* apr.date_parse_http(string) -> time {{{1 * * Parses an [HTTP] [http] date in one of three standard forms: * * - `'Sun, 06 Nov 1994 08:49:37 GMT'` - [RFC 822] [rfc822], updated by [RFC 1123][rfc1123] * - `'Sunday, 06-Nov-94 08:49:37 GMT'` - [RFC 850] [rfc850], obsoleted by [RFC 1036][rfc1036] * - `'Sun Nov 6 08:49:37 1994'` - ANSI C's [asctime()] [asctime] format * * On success the date is returned as a number like documented under [time * routines](#time_routines). If the date string is out of range or invalid nil * is returned. * * [http]: http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol * [rfc822]: http://tools.ietf.org/html/rfc822 * [rfc1123]: http://tools.ietf.org/html/rfc1123 * [rfc850]: http://tools.ietf.org/html/rfc850 * [rfc1036]: http://tools.ietf.org/html/rfc1036 * [asctime]: http://linux.die.net/man/3/asctime */ int lua_apr_date_parse_http(lua_State *L) { const char *input; apr_time_t result; input = luaL_checkstring(L, 1); result = apr_date_parse_http(input); if (result == 0) return 0; time_put(L, result); return 1; } /* apr.date_parse_rfc(string) -> time {{{1 * * Parses a string resembling an [RFC 822] [rfc822] date. This is meant to be * lenient in its parsing of dates and hence will parse a wider range of dates * than `apr.date_parse_http()`. * * The prominent mailer (or poster, if mailer is unknown) that has been seen in * the wild is included for the unknown formats: * * - `'Sun, 06 Nov 1994 08:49:37 GMT'` - [RFC 822] [rfc822], updated by [RFC 1123] [rfc1123] * - `'Sunday, 06-Nov-94 08:49:37 GMT'` - [RFC 850] [rfc850], obsoleted by [RFC 1036] [rfc1036] * - `'Sun Nov 6 08:49:37 1994'` - ANSI C's [asctime()] [asctime] format * - `'Sun, 6 Nov 1994 08:49:37 GMT'` - [RFC 822] [rfc822], updated by [RFC 1123] [rfc1123] * - `'Sun, 06 Nov 94 08:49:37 GMT'` - [RFC 822] [rfc822] * - `'Sun, 6 Nov 94 08:49:37 GMT'` - [RFC 822] [rfc822] * - `'Sun, 06 Nov 94 08:49 GMT'` - Unknown [drtr@ast.cam.ac.uk] * - `'Sun, 6 Nov 94 08:49 GMT'` - Unknown [drtr@ast.cam.ac.uk] * - `'Sun, 06 Nov 94 8:49:37 GMT'` - Unknown [Elm 70.85] * - `'Sun, 6 Nov 94 8:49:37 GMT'` - Unknown [Elm 70.85] * * On success the date is returned as a number like documented under [time * routines](#time_routines). If the date string is out of range or invalid nil * is returned. */ int lua_apr_date_parse_rfc(lua_State *L) { const char *input; apr_time_t result; input = luaL_checkstring(L, 1); result = apr_date_parse_rfc(input); if (result == 0) return 0; time_put(L, result); return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/dbd.c000066400000000000000000001051001220664456000155470ustar00rootroot00000000000000/* Relational database drivers module for the Lua/APR binding. * * Authors: * - zhiguo zhao * - Peter Odding * Last Change: November 6, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The APR DBD module makes it possible to query relational database engines * like [SQLite] [sqlite], [MySQL] [mysql], [PostgreSQL] [pgsql], [Oracle] * [oracle], [ODBC] [odbc] and [FreeTDS] [freetds]. This module currently has * some drawbacks which appear to be unavoidable given the design of the Apache * Portable Runtime DBD framework: * * - Booleans and numbers are returned as strings because result set types are * not known to the Lua/APR binding (and type guessing is too error prone) * * - String arguments and results are not binary safe, this means they will * be truncated at the first zero byte (see the [apr-dev mailing list] * [apr_dev] thread ["current dbd initiatives"] [dbd_binary_discuss] for * discussion about this limitation of APR) * * Note that if you control the data going into the database you can overcome * the second limitation by using APR's built in support for * [Base64 encoding](#base64_encoding). * * ### Installing drivers * * On Debian/Ubuntu Linux you can install one or more of the following packages * to enable support for the corresponding database driver (dependencies will * be installed automatically by the package management system): * * - [libaprutil1-dbd-sqlite3][sqlite3_pkg] * - [libaprutil1-dbd-mysql](http://packages.ubuntu.com/lucid/libaprutil1-dbd-mysql) * - [libaprutil1-dbd-pgsql](http://packages.ubuntu.com/lucid/libaprutil1-dbd-pgsql) * - [libaprutil1-dbd-odbc](http://packages.ubuntu.com/lucid/libaprutil1-dbd-odbc) * - [libaprutil1-dbd-freetds](http://packages.ubuntu.com/lucid/libaprutil1-dbd-freetds) * * ### Debugging "DSO load failed" errors * * In my initial tests on Ubuntu I installed [libaprutil1-dbd-sqlite3] * [sqlite3_pkg] but kept getting an error when trying to load the driver: * * $ lua -e "print(require('apr').dbd('sqlite3'))" * nil DSO load failed EDSOOPEN * * After a while I found the problem using [LD_DEBUG] [ld_debug]: * * $ LD_DEBUG=libs lua -e "require('apr').dbd('sqlite3')" 2>&1 | grep undefined * /usr/lib/apr-util-1/apr_dbd_sqlite3-1.so: error: symbol lookup error: undefined symbol: apr_pool_cleanup_null (fatal) * * Having identified the problem, finding a workaround was easy: * * $ export LD_PRELOAD='/usr/lib/libapr-1.so.0:/usr/lib/libaprutil-1.so.0' * $ lua -e "print(require('apr').dbd('sqlite3'))" * database driver (0x853bdfc) * * [sqlite]: http://en.wikipedia.org/wiki/SQLite * [mysql]: http://en.wikipedia.org/wiki/MySQL * [pgsql]: http://en.wikipedia.org/wiki/PostgreSQL * [oracle]: http://en.wikipedia.org/wiki/Oracle_Database * [odbc]: http://en.wikipedia.org/wiki/ODBC * [freetds]: http://en.wikipedia.org/wiki/FreeTDS * [apr_dev]: http://apr.apache.org/mailing-lists.html * [dbd_binary_discuss]: http://marc.info/?l=apr-dev&m=114969441721086&w=2 * [sqlite3_pkg]: http://packages.ubuntu.com/lucid/libaprutil1-dbd-sqlite3 * [ld_debug]: http://www.wlug.org.nz/LD_DEBUG */ #include "lua_apr.h" #include /* Enable compatibility with APR 1.2? (which doesn't * have named columns and explicit transaction modes) */ #define LUA_APR_DBD_COMPAT (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION <= 2) /* Lua object structures. {{{1 */ /* Driver objects. */ typedef struct { lua_apr_refobj header; int generation; apr_pool_t *pool; const apr_dbd_driver_t *driver; apr_dbd_t *handle; apr_dbd_transaction_t *trans; } lua_apr_dbd_object; /* XXX The result set object's memory pool must be the same memory pool used * for the driver object, otherwise the SQLite backend will error out on the * second SELECT query executed. I can't find any documentation on this and it * seems counterintuitive: why require a memory pool in the apr_dbd_select() * argument list when it must be the same memory pool as that of the driver * anyway?! (which is also in the argument list) */ /* Reference to driver object stored in result set or prepared statement. */ typedef struct { lua_apr_dbd_object *driver; int generation; } lua_apr_dbd_reference; /* Result set objects. */ typedef struct { lua_apr_refobj header; lua_apr_dbd_reference parent; apr_dbd_results_t *results; int random_access, rownum; } lua_apr_dbr_object; /* Prepared statement objects. */ typedef struct { lua_apr_refobj header; lua_apr_dbd_reference parent; apr_dbd_prepared_t *statement; int random_access; } lua_apr_dbp_object; /* Internal functions. {{{1 */ /* check_dbd() {{{2 */ static lua_apr_dbd_object *check_dbd(lua_State *L, int idx, int connected, int transaction) { lua_apr_dbd_object *object; object = check_object(L, idx, &lua_apr_dbd_type); if (connected && object->handle == NULL) luaL_error(L, "attempt to use a closed database driver"); else if (transaction && object->trans == NULL) luaL_error(L, "this operation only works when a transaction is active"); return object; } static void *check_subobj(lua_State *L, int idx, lua_apr_objtype *type, size_t offset) /* {{{2 */ { void *object; lua_apr_dbd_reference *reference; object = check_object(L, idx, type); if (object != NULL) { reference = (void*)((char*)object + offset); if (reference->generation != reference->driver->generation) luaL_error(L, "database driver has been reinitialized"); } return object; } /* check_dbr() {{{2 */ static lua_apr_dbr_object *check_dbr(lua_State *L, int idx) { return check_subobj(L, idx, &lua_apr_dbr_type, offsetof(lua_apr_dbr_object, parent)); } /* check_dbp() {{{2 */ static lua_apr_dbp_object *check_dbp(lua_State *L, int idx) { return check_subobj(L, idx, &lua_apr_dbp_type, offsetof(lua_apr_dbp_object, parent)); } /* new_subobj() {{{2 */ static void *new_subobj(lua_State *L, lua_apr_objtype *type, int idx, lua_apr_dbd_object *driver, size_t offset) { lua_apr_dbd_reference *reference; void *object = new_object(L, type); reference = (void*)((char*)object + offset); reference->driver = driver; reference->generation = driver->generation; /* Let Lua's garbage collector know we want the driver to stay alive. */ object_env_private(L, -1); /* get result set environment */ lua_pushvalue(L, idx); /* copy driver object reference */ lua_setfield(L, -2, "driver"); /* store reference to driver */ lua_pop(L, 1); /* remove environment from stack */ return object; } /* new_resultset() {{{2 */ static lua_apr_dbr_object *new_resultset(lua_State *L, int idx, lua_apr_dbd_object *driver, int random_access) { lua_apr_dbr_object *object; object = new_subobj(L, &lua_apr_dbr_type, idx, driver, offsetof(lua_apr_dbr_object, parent)); if (object != NULL) object->random_access = random_access; return object; } /* new_statement() {{{2 */ static lua_apr_dbp_object *new_statement(lua_State *L, int idx, lua_apr_dbd_object *driver, int random_access) { lua_apr_dbp_object *statement; statement = new_subobj(L, &lua_apr_dbp_type, idx, driver, offsetof(lua_apr_dbp_object, parent)); statement->random_access = random_access; return statement; } /* check_dbd_value() {{{2 */ static const char *check_dbd_value(lua_State *L, int idx, int origidx, int i) { int type = lua_type(L, idx); if (type == LUA_TNIL || type == LUA_TNONE) return NULL; else if (type == LUA_TBOOLEAN) /* Not sure if this is standard but SQLite and MySQL do it like this. */ return lua_toboolean(L, idx) ? "1" : "0"; else if (type == LUA_TNUMBER || type == LUA_TSTRING) return lua_tostring(L, idx); else if (origidx == 0) /* Let the user know we were expecting a string argument. */ luaL_checkstring(L, idx); else /* Let the user know which value in the table was invalid. */ luaL_argcheck(L, 0, origidx, lua_pushfstring(L, "invalid value at index %d", i)); return NULL; } /* check_dbd_values() {{{2 */ static void check_dbd_values(lua_State *L, int idx, int *nargs, const char ***values) { /* I'm a three star programmer ;-) http://c2.com/cgi/wiki?ThreeStarProgrammer */ int i, is_table = lua_istable(L, idx); *nargs = is_table ? lua_objlen(L, idx) : (lua_gettop(L) - idx + 1); *values = malloc(sizeof(**values) * *nargs); if (*nargs > 0 && *values == NULL) raise_error_memory(L); if (is_table) { for (i = 0; i < *nargs; i++) { lua_pushinteger(L, i + 1); lua_gettable(L, 2); (*values)[i] = check_dbd_value(L, -1, idx, i + 1); lua_pop(L, 1); } } else { for (i = 0; i < *nargs; i++) (*values)[i] = check_dbd_value(L, idx + i, 0, 0); } } /* push_dbd_value() {{{2 */ static int push_dbd_value(lua_State *L, const char *value) { lua_pushstring(L, value); return 1; } /* push_dbd_error() {{{2 */ static int push_dbd_error(lua_State *L, lua_apr_dbd_object *object, int status) { const char *message; message = apr_dbd_error(object->driver, object->handle, status); lua_pushnil(L); lua_pushstring(L, message); return 2; } /* push_dbd_status() {{{2 */ static int push_dbd_status(lua_State *L, lua_apr_dbd_object *object, int status) { if (status != 0) return push_dbd_error(L, object, status); lua_pushboolean(L, 1); return 1; } /* dbd_error() {{{2 */ static int dbd_error(lua_State *L) { const lua_apr_dbd_object *object = check_dbd(L, 1, 0, 0); int err = luaL_checkint(L, 2); lua_pushstring(L, apr_dbd_error(object->driver, object->handle, err)); return 1; } /* dbd_escape() {{{2 */ static int dbd_escape(lua_State *L) { const lua_apr_dbd_object *object = check_dbd(L, 1, 1, 0); const char *string = luaL_checkstring(L, 2); lua_pushstring(L, apr_dbd_escape(object->driver, object->pool, string, object->handle)); return 1; } /* push_query_result() {{{2 */ static int push_query_result(lua_State *L, lua_apr_dbd_object *object, int nrows, int status) { push_dbd_status(L, object, status); if (status == 0) lua_pushinteger(L, nrows); return 2; } /* next_record() {{{2 */ typedef int (*push_row_cb)(lua_State*, lua_apr_dbr_object*, apr_dbd_row_t*); static int next_record(lua_State *L, push_row_cb push_row) { lua_apr_dbd_object *driver; lua_apr_dbr_object *results; apr_dbd_row_t *row; int status, iterator, rownum; if (lua_isuserdata(L, lua_upvalueindex(1))) { iterator = 1; results = lua_touserdata(L, lua_upvalueindex(1)); rownum = -1; /* iterators keep their own row numbers */ } else { iterator = 0; results = check_dbr(L, 1); /* results->rownum is initialized to 0 by memset() */ rownum = luaL_optint(L, 2, results->rownum + 1); } driver = results->parent.driver; status = apr_dbd_get_row(driver->driver, driver->pool, results->results, &row, rownum); if (status == -1) { /* rownum out of range or data finished */ return 0; } else if (status != 0) { /* undocumented error? */ push_dbd_error(L, driver, status); if (iterator) lua_error(L); return 2; } else { if (rownum != -1) results->rownum = rownum; else rownum = ++results->rownum; return push_row(L, results, row); } } /* dbr_tuple_cb() {{{2 */ static int dbr_tuple_cb(lua_State *L, lua_apr_dbr_object *results, apr_dbd_row_t *row) { const char *value; int i = 0; while ((value = apr_dbd_get_entry(results->parent.driver->driver, row, i++)) != NULL) push_dbd_value(L, value); return i - 1; } /* dbr_row_cb() {{{2 */ #if !LUA_APR_DBD_COMPAT static int dbr_row_cb(lua_State *L, lua_apr_dbr_object *results, apr_dbd_row_t *row) { lua_apr_dbd_object *driver; int i = 0, is_pairs; const char *name; driver = results->parent.driver; is_pairs = lua_toboolean(L, lua_upvalueindex(2)); if (is_pairs) lua_pushinteger(L, results->rownum); lua_newtable(L); while ((name = apr_dbd_get_name(driver->driver, results->results, i)) != NULL) { push_dbd_value(L, apr_dbd_get_entry(driver->driver, row, i++)); lua_setfield(L, -2, name); } return is_pairs ? 2 : 1; } #endif /* dbd_close_impl() {{{2 */ static apr_status_t dbd_close_impl(lua_apr_dbd_object *driver) { apr_status_t status = APR_SUCCESS; if (driver->handle != NULL) { status = apr_dbd_close(driver->driver, driver->handle); if (status == APR_SUCCESS) { driver->handle = NULL; driver->generation++; } } return status; } /* apr.dbd(name) -> driver {{{1 * * Create a database driver object. The string @name decides which database * engine to use. On success the driver object is returned, otherwise a nil * followed by an error message is returned. Currently supported engines * include: * * - `'mysql'` * - `'pgsql'` * - `'sqlite3'` * - `'sqlite2'` * - `'oracle'` * - `'freetds'` * - `'odbc'` * * Note that in its default configuration the Apache Portable Runtime uses * dynamic loading to load database drivers which means `apr.dbd()` can fail * because a driver can't be loaded. */ int lua_apr_dbd(lua_State *L) { static int ginit = 0; apr_status_t status; lua_apr_dbd_object *driver; apr_pool_t *pool; const char *name; pool = to_pool(L); name = luaL_checkstring(L, 1); if (ginit == 0) { status = apr_dbd_init(pool); if (status != APR_SUCCESS) return push_error_status(L, status); ginit++; } driver = new_object(L, &lua_apr_dbd_type); if (driver == NULL) return push_error_memory(L); /* FIXME I'm not sure whether these pools should be related! */ status = apr_pool_create_ex(&driver->pool, pool, NULL, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); status = apr_dbd_get_driver(driver->pool, name, &driver->driver); if (status != APR_SUCCESS) return push_error_status(L, status); return 1; } /* driver:open(params) -> status {{{1 * * Open a connection to a backend. The string @params contains the arguments to * the driver (implementation-dependent). On success true is returned, * otherwise a nil followed by an error message is returned. The syntax of * @params is as follows: * * - __PostgreSQL:__ @params is passed directly to the [PQconnectdb()] * [pqconnectdb] function, check the PostgreSQL documentation for more * details on the syntax * * - __SQLite2:__ @params is split on a colon, with the first part used as the * filename and the second part converted to an integer and used as the file * mode * * - __SQLite3:__ @params is passed directly to the [sqlite3_open()] * [sqlite3_open] function as a filename to be opened, check the SQLite3 * documentation for more details (hint: if @params is `':memory:'` a * private, temporary in-memory database is created for the connection) * * - __Oracle:__ @params can have 'user', 'pass', 'dbname' and 'server' keys, * each followed by an equal sign and a value. Such key/value pairs can be * delimited by space, CR, LF, tab, semicolon, vertical bar or comma * * - __MySQL:__ @params can have 'host', 'port', 'user', 'pass', 'dbname', * 'sock', 'flags' 'fldsz', 'group' and 'reconnect' keys, each followed by * an equal sign and a value. Such key/value pairs can be delimited by * space, CR, LF, tab, semicolon, vertical bar or comma. For now, 'flags' * can only recognize `CLIENT_FOUND_ROWS` (check MySQL manual for details). * The value associated with 'fldsz' determines maximum amount of memory (in * bytes) for each of the fields in the result set of prepared statements. * By default, this value is 1 MB. The value associated with 'group' * determines which group from configuration file to use (see * `MYSQL_READ_DEFAULT_GROUP` option of [mysql_options()] [mysql_options] in * MySQL manual). Reconnect is set to 1 by default (i.e. true) * * - __FreeTDS:__ @params can have 'username', 'password', 'appname', * 'dbname', 'host', 'charset', 'lang' and 'server' keys, each followed by * an equal sign and a value * * [pqconnectdb]: http://www.postgresql.org/docs/current/interactive/libpq-connect.html#LIBPQ-PQCONNECTDB * [sqlite3_open]: http://www.sqlite.org/c3ref/open.html * [mysql_options]: http://dev.mysql.com/doc/refman/5.5/en/mysql-options.html */ static int dbd_open(lua_State *L) { lua_apr_dbd_object *driver; # if LUA_APR_DBD_COMPAT const char *params; # else const char *params, *error; # endif apr_status_t status; driver = check_dbd(L, 1, 0, 0); params = luaL_checkstring(L, 2); if (driver->handle != NULL) { /* XXX It's not clear whether apr_dbd_close() returns proper apr_status_t * values or not... Looking at the SQLite3 and MySQL backends any errors * are silently ignored?! */ status = apr_dbd_close(driver->driver, driver->handle); if (status != APR_SUCCESS) return push_error_status(L, status); driver->generation++; driver->handle = NULL; } # if LUA_APR_DBD_COMPAT status = apr_dbd_open(driver->driver, driver->pool, params, &driver->handle); if (status != APR_SUCCESS) return push_error_status(L, status); # else status = apr_dbd_open_ex(driver->driver, driver->pool, params, &driver->handle, &error); if (status != APR_SUCCESS) { lua_pushnil(L); lua_pushstring(L, error); status_to_name(L, status); return 3; } # endif lua_pushboolean(L, 1); return 1; } /* driver:dbname(name) -> status {{{1 * * Select the database @name. On succes true is returned, otherwise a nil * followed by an error message is returned. Not supported for all drivers * (e.g. SQLite by definition only knows a single database). */ static int dbd_dbname(lua_State *L) { lua_apr_dbd_object *object; const char *name; int status; object = check_dbd(L, 1, 1, 0); name = luaL_checkstring(L, 2); status = apr_dbd_set_dbname(object->driver, object->pool, object->handle, name); return push_dbd_status(L, object, status); } /* driver:driver() -> name {{{1 * * Get the name of the database driver. Returns one of the strings listed for * `apr.dbd()`. */ static int dbd_driver(lua_State *L) { lua_apr_dbd_object *object = check_dbd(L, 1, 0, 0); lua_pushstring(L, apr_dbd_name(object->driver)); return 1; } /* driver:check() -> status {{{1 * * Check the status of the database connection. When the connection is still * alive true is returned, otherwise a nil followed by an error message is * returned. */ static int dbd_check_conn(lua_State *L) { lua_apr_dbd_object *object; int status; object = check_dbd(L, 1, 1, 0); status = apr_dbd_check_conn(object->driver, object->pool, object->handle); return push_dbd_status(L, object, status); } /* driver:query(sql) -> status, affected_rows {{{1 * * Execute an SQL query that doesn't return a result set. On success true * followed by the number of affected rows is returned, otherwise a nil * followed by an error message is returned. */ static int dbd_query(lua_State *L) { lua_apr_dbd_object *object; const char *statement; int status, nrows = 0; object = check_dbd(L, 1, 1, 0); statement = luaL_checkstring(L, 2); status = apr_dbd_query(object->driver, object->handle, &nrows, statement); return push_query_result(L, object, nrows, status); } /* driver:select(sql [, random_access]) -> result_set {{{1 * * Execute an SQL query that returns a result set. On success a result set * object is returned, otherwise a nil followed by an error message is * returned. To enable support for random access you can pass the optional * argument @random_access as true. */ static int dbd_select(lua_State *L) { lua_apr_dbd_object *driver; lua_apr_dbr_object *results; const char *statement; int random_access, status; driver = check_dbd(L, 1, 1, 0); statement = luaL_checkstring(L, 2); random_access = lua_toboolean(L, 3); results = new_resultset(L, 1, driver, random_access); status = apr_dbd_select(driver->driver, driver->pool, driver->handle, &results->results, statement, random_access); if (status != 0) return push_dbd_error(L, driver, status); return 1; } /* Transactions. {{{1 */ /* driver:transaction_start() -> status {{{2 * * Start a transaction. May be a no-op. On success true is returned, otherwise * a nil followed by an error message is returned. * * Note that transaction modes, set by calling `driver:transaction_mode()`, * will affect all query/select calls within a transaction. By default, any * error in query/select during a transaction will cause the transaction to * inherit the error code and any further query/select calls will fail * immediately. Put transaction in `'ignore-errors'` mode to avoid that. Use * `'rollback'` mode to do explicit rollback. * * TODO Support for transaction objects that have query(), select(), prepare() methods? */ static int dbd_transaction_start(lua_State *L) { lua_apr_dbd_object *object; apr_status_t status; object = check_dbd(L, 1, 1, 0); status = apr_dbd_transaction_start(object->driver, object->pool, object->handle, &object->trans); return push_status(L, status); } /* driver:transaction_end() -> status {{{2 * * End a transaction (commit on success, rollback on error). May be a no-op. On * success true is returned, otherwise a nil followed by an error message is * returned. */ static int dbd_transaction_end(lua_State *L) { lua_apr_dbd_object *object; apr_status_t status; object = check_dbd(L, 1, 1, 1); status = apr_dbd_transaction_end(object->driver, object->pool, object->trans); return push_status(L, status); } #if !LUA_APR_DBD_COMPAT /* driver:transaction_mode([mode]) -> mode {{{2 * * Get or set the transaction mode, one of: * * - `'commit'`: commit the transaction * - `'rollback'`: rollback the transaction * - `'ignore-errors'`: ignore transaction errors * * On success the new transaction mode is returned, otherwise a nil followed by * an error message is returned. */ static int dbd_transaction_mode(lua_State *L) { const char *options[] = { "commit", "rollback", "ignore-errors", NULL }; const int values[] = { APR_DBD_TRANSACTION_COMMIT, APR_DBD_TRANSACTION_ROLLBACK, APR_DBD_TRANSACTION_IGNORE_ERRORS }; int i, mode; lua_apr_dbd_object *object; object = check_dbd(L, 1, 1, 1); if (!lua_isnoneornil(L, 2)) { mode = values[luaL_checkoption(L, 2, NULL, options)]; mode = apr_dbd_transaction_mode_set(object->driver, object->trans, mode); } else { mode = apr_dbd_transaction_mode_get(object->driver, object->trans); } for (i = 0; i < count(values); i++) if (mode == values[i]) { lua_pushstring(L, options[i]); return 1; } assert(0); return 0; } #endif /* Prepared statements. {{{1 */ /* driver:prepare(sql [, random_access]) -> prepared_statement {{{2 * * Prepare an SQL statement. On success a prepared statement object is * returned, otherwise a nil followed by an error message is returned. The * string @sql gives the query to prepare. If the optional argument * @random_access is true, result sets created by the prepared statement will * support random access. * * To specify parameters of the prepared query, use `%s`, `%d` etc. (see below * for full list) in place of database specific parameter syntax (e.g. for * PostgreSQL, this would be `$1`, `$2`, for SQLite3 this would be `?`, etc.). * For instance: `SELECT name FROM customers WHERE name = %s` would be a query * that this function understands. Here is the list of supported format * specifiers and what they map to in SQL (generally you'll only need the types * marked in bold text): * * - `%hhd`: TINY INT * - `%hhu`: UNSIGNED TINY INT * - `%hd`: SHORT * - `%hu`: UNSIGNED SHORT * - __`%d`: INT__ * - __`%u`: UNSIGNED INT__ * - `%ld`: LONG * - `%lu`: UNSIGNED LONG * - `%lld`: LONG LONG * - `%llu`: UNSIGNED LONG LONG * - __`%f`: FLOAT, REAL__ * - __`%lf`: DOUBLE PRECISION__ * - __`%s`: VARCHAR__ * - __`%pDt`: TEXT__ * - `%pDi`: TIME * - `%pDd`: DATE * - `%pDa`: DATETIME * - `%pDs`: TIMESTAMP * - `%pDz`: TIMESTAMP WITH TIME ZONE * - `%pDn`: NULL */ static int dbd_prepare(lua_State *L) { lua_apr_dbd_object *driver; lua_apr_dbp_object *statement; const char *query; apr_status_t status; int random_access; driver = check_dbd(L, 1, 1, 0); query = luaL_checkstring(L, 2); random_access = lua_toboolean(L, 3); statement = new_statement(L, 1, driver, random_access); status = apr_dbd_prepare(driver->driver, driver->pool, driver->handle, query, NULL, &statement->statement); if (status != APR_SUCCESS) return push_dbd_error(L, driver, status); return 1; } /* prepared_statement:query(...) -> status {{{2 * * Using a prepared statement, execute an SQL query that doesn't return a * result set. On success true followed by the number of affected rows is * returned, otherwise a nil followed by an error message is returned. * * If you pass a list then the values in the list become query parameters, * otherwise all function arguments become query parameters. * * *This function is not binary safe.* */ static int dbp_query(lua_State *L) { lua_apr_dbd_object *driver; lua_apr_dbp_object *statement; int nargs, status, nrows = 0; const char **values; statement = check_dbp(L, 1); driver = statement->parent.driver; check_dbd_values(L, 2, &nargs, &values); status = apr_dbd_pquery(driver->driver, driver->pool, driver->handle, &nrows, statement->statement, nargs, values); free((void*) values); /* make MSVC++ 2010 happy */ return push_query_result(L, driver, nrows, status); } /* prepared_statement:select(...) -> result_set {{{2 * * Using a prepared statement, execute an SQL query that returns a result set. * On success a result set object is returned, otherwise a nil followed by an * error message is returned. To enable support for random access pass * @random_access as true, otherwise pass it as false. * * If you pass a list then the values in the list become query parameters, * otherwise all function arguments after @random_access become query * parameters. * * *This function is not binary safe.* */ static int dbp_select(lua_State *L) { lua_apr_dbd_object *driver; lua_apr_dbp_object *statement; lua_apr_dbr_object *results; const char **values; int nargs, status; statement = check_dbp(L, 1); driver = statement->parent.driver; check_dbd_values(L, 2, &nargs, &values); results = new_resultset(L, 1, driver, statement->random_access); status = apr_dbd_pselect(driver->driver, driver->pool, driver->handle, &results->results, statement->statement, statement->random_access, nargs, values); free((void*) values); /* make MSVC++ 2010 happy */ if (status != 0) return push_dbd_error(L, driver, status); return 1; } /* tostring(prepared_statement) -> string {{{2 */ static int dbp_tostring(lua_State *L) { lua_apr_dbp_object *object; object = check_dbp(L, 1); lua_pushfstring(L, "%s (%p)", lua_apr_dbp_type.friendlyname, object); return 1; } /* prepared_statement:__gc() {{{2 */ static int dbp_gc(lua_State *L) { lua_apr_dbp_object *object = check_dbp(L, 1); release_object((lua_apr_refobj*)object); return 0; } /* Result sets. {{{1 */ #if !LUA_APR_DBD_COMPAT /* result_set:columns([num]) -> name [, ...] {{{2 * * If no arguments are given return the names of all columns in the result set, * otherwise return the name of the column with index @num (counting from one). * For example: * * > driver = assert(apr.dbd 'sqlite3') * > assert(driver:open ':memory:') * > results = assert(driver:select [[ SELECT 1 AS col1, 2 AS col2 ]]) * > = assert(results:columns()) * { 'col1', 'col2' } */ static int dbr_columns(lua_State *L) { lua_apr_dbd_object *driver; lua_apr_dbr_object *results; const char *name; int i = 0; results = check_dbr(L, 1); driver = results->parent.driver; if (lua_isnoneornil(L, 2)) { while ((name = apr_dbd_get_name(driver->driver, results->results, i++)) != NULL) lua_pushstring(L, name); return i - 1; } else { i = luaL_checkint(L, 2) - 1; name = apr_dbd_get_name(driver->driver, results->results, i); if (name != NULL) { lua_pushstring(L, name); return 1; } return 0; } } /* result_set:row(num) -> row {{{2 * * Return a table with named fields for the next row in the result set or the * row with index @rownum if given. When there are no more rows nothing is * returned, in case of an error a nil followed by an error message is * returned. * * *This function is not binary safe.* */ static int dbr_row(lua_State *L) { return next_record(L, dbr_row_cb); } /* result_set:rows() -> iterator {{{2 * * Return an iterator that produces a table with named fields for each * (remaining) row in the result set. * * In Lua 5.2 you can also use `pairs(result_set)`. * * *This function is not binary safe.* */ static int dbr_rows(lua_State *L) { check_dbr(L, 1); lua_settop(L, 1); lua_pushcclosure(L, dbr_row, 1); lua_insert(L, 1); return 1; } #endif /* result_set:tuple([rownum]) -> value [, ...] {{{2 * * Return a tuple for the next row in the result set or the row with index * @rownum if given. If more than one value is returned, the return values will * be in the same order as the column list in the SQL query. When there are no * more rows nothing is returned, in case of an error a nil followed by an * error message is returned. * * *This function is not binary safe.* */ static int dbr_tuple(lua_State *L) { return next_record(L, dbr_tuple_cb); } /* result_set:tuples() -> iterator {{{2 * * Return an iterator that produces a tuple for each (remaining) row in the * result set. The tuples produced by the iterator are in the same order as the * column list in the SQL query, for example: * * > driver = assert(apr.dbd 'sqlite3') * > assert(driver:open 'quotes.sqlite3') * > results = assert(driver:select [[ SELECT author, quote FROM quotes ]]) * > for author, quote in results:tuples() do * >> print(author, 'wrote:') * >> print(quote) * >> print() * >> end * * *This function is not binary safe.* */ static int dbr_tuples(lua_State *L) { check_dbr(L, 1); lua_settop(L, 1); lua_pushcclosure(L, dbr_tuple, 1); lua_insert(L, 1); return 1; } #if !LUA_APR_DBD_COMPAT /* result_set:pairs() -> iterator {{{2 * * Return an iterator that produces a row number and a table with named fields * for each (remaining) row in the result set. * * In Lua 5.2 you can also use `ipairs(result_set)`. * * *This function is not binary safe.* */ static int dbr_pairs(lua_State *L) { check_dbr(L, 1); lua_settop(L, 1); lua_pushboolean(L, 2); lua_pushcclosure(L, dbr_row, 2); lua_insert(L, 1); return 1; } #endif /* #result_set -> num_tuples {{{2 * * Get the number of rows in a result set of a synchronous select. If the * results are asynchronous -1 is returned. */ static int dbr_len(lua_State *L) { lua_apr_dbd_object *driver; lua_apr_dbr_object *results; int num_tuples; results = check_dbr(L, 1); driver = results->parent.driver; num_tuples = apr_dbd_num_tuples(driver->driver, results->results); lua_pushinteger(L, num_tuples); return 1; } /* tostring(result_set) -> string {{{2 */ static int dbr_tostring(lua_State *L) { lua_apr_dbr_object *object; object = check_dbr(L, 1); lua_pushfstring(L, "%s (%p)", lua_apr_dbr_type.friendlyname, object); return 1; } /* result_set:__gc() {{{2 */ static int dbr_gc(lua_State *L) { lua_apr_dbr_object *object = check_dbr(L, 1); release_object((lua_apr_refobj*)object); return 0; } /* driver:close() -> status {{{1 * * Close a connection to a backend. */ static int dbd_close(lua_State *L) { lua_apr_dbd_object *object; apr_status_t status; object = check_dbd(L, 1, 1, 0); status = dbd_close_impl(object); return push_status(L, status); } /* tostring(driver) -> string {{{1 */ static int dbd_tostring(lua_State *L) { lua_apr_dbd_object *object; object = check_dbd(L, 1, 0, 0); if (object->handle != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_dbd_type.friendlyname, object); else lua_pushfstring(L, "%s (closed)", lua_apr_dbd_type.friendlyname); return 1; } /* driver:__gc() {{{1 */ static int dbd_gc(lua_State *L) { lua_apr_dbd_object *driver = check_dbd(L, 1, 0, 0); if (object_collectable((lua_apr_refobj*)driver)) dbd_close_impl(driver); release_object((lua_apr_refobj*)driver); return 0; } /* Internal object definitions. {{{1 */ /* Database driver objects. {{{2 */ static luaL_reg dbd_metamethods[] = { { "__tostring", dbd_tostring }, { "__eq", objects_equal }, { "__gc", dbd_gc }, { NULL, NULL } }; static luaL_reg dbd_methods[] = { /* Generic methods. */ { "open", dbd_open }, { "dbname", dbd_dbname }, { "driver", dbd_driver }, { "check", dbd_check_conn }, { "query", dbd_query }, { "select", dbd_select }, { "prepare", dbd_prepare }, { "error", dbd_error }, { "escape", dbd_escape }, { "close", dbd_close }, { "transaction_start", dbd_transaction_start }, { "transaction_end", dbd_transaction_end }, # if !LUA_APR_DBD_COMPAT { "transaction_mode", dbd_transaction_mode }, # endif { NULL, NULL } }; lua_apr_objtype lua_apr_dbd_type = { "lua_apr_dbd_object*", /* metatable name in registry */ "database driver", /* friendly object name */ sizeof(lua_apr_dbd_object), /* structure size */ dbd_methods, /* methods table */ dbd_metamethods /* metamethods table */ }; /* Result set objects. {{{2 */ static luaL_reg dbr_metamethods[] = { { "__len", dbr_len }, { "__tostring", dbr_tostring }, { "__eq", objects_equal }, { "__gc", dbr_gc }, # if LUA_VERSION_NUM >= 502 && !LUA_APR_DBD_COMPAT { "__pairs", dbr_rows }, { "__ipairs", dbr_pairs }, # endif { NULL, NULL } }; static luaL_reg dbr_methods[] = { # if !LUA_APR_DBD_COMPAT { "columns", dbr_columns }, # endif { "tuple", dbr_tuple }, { "tuples", dbr_tuples }, # if !LUA_APR_DBD_COMPAT { "row", dbr_row }, { "rows", dbr_rows }, { "pairs", dbr_pairs }, # endif { NULL, NULL } }; lua_apr_objtype lua_apr_dbr_type = { "lua_apr_dbr_object*", /* metatable name in registry */ "result set", /* friendly object name */ sizeof(lua_apr_dbr_object), /* structure size */ dbr_methods, /* methods table */ dbr_metamethods /* metamethods table */ }; /* Prepared statement objects. {{{2 */ static luaL_reg dbp_metamethods[] = { { "__tostring", dbp_tostring }, { "__eq", objects_equal }, { "__gc", dbp_gc }, { NULL, NULL } }; static luaL_reg dbp_methods[] = { { "query", dbp_query }, { "select", dbp_select }, { NULL, NULL } }; lua_apr_objtype lua_apr_dbp_type = { "lua_apr_dbp_object*", /* metatable name in registry */ "prepared statement", /* friendly object name */ sizeof(lua_apr_dbp_object), /* structure size */ dbp_methods, /* methods table */ dbp_metamethods /* metamethods table */ }; /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/dbm.c000066400000000000000000000234341220664456000155710ustar00rootroot00000000000000/* DBM routines module for the Lua/APR binding. * * Author: Peter Odding * Last Change: June 16, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * This module enables the creation and manipulation of [dbm] [dbm] databases. * If you've never heard of dbm before you can think of it as a Lua table that * only supports string keys and values but is backed by a file, so that you * can stop and restart your application and find the exact same contents. * This module supports the following libraries/implementations: * * - `'db'` for [Berkeley DB] [bdb] files * - `'gdbm'` for GDBM files * - `'ndbm'` for NDBM files * - `'sdbm'` for SDBM files (the default) * * The SDBM format is the default database format for Lua/APR because APR has * built-in support for SDBM while the other libraries need to be separately * installed. This is why not all types may be available at run time. * * [dbm]: http://en.wikipedia.org/wiki/dbm * [bdb]: http://en.wikipedia.org/wiki/Berkeley_DB */ #include "lua_apr.h" #include /* XXX Default to sdbm because it's always available. */ #define LUA_APR_DBM_DEFAULT "sdbm" /* Structure for DBM objects. */ typedef struct { lua_apr_refobj header; apr_pool_t *pool; apr_dbm_t *handle; const char *path; } lua_apr_dbm; /* Internal functions {{{1 */ /* dbm_check(L, i, open) -- get dbm object from Lua stack {{{2 */ static lua_apr_dbm *dbm_check(lua_State *L, int i, int open) { lua_apr_dbm *dbm = check_object(L, i, &lua_apr_dbm_type); if (open && dbm->handle == NULL) luaL_error(L, "attempt to use a closed dbm handle"); return dbm; } /* dbmtype_check(L, i) -- {{{2 */ static const char *dbmtype_check(lua_State *L, int i) { const char *options[] = { "db", "gdbm", "ndbm", "sdbm", NULL }; return options[luaL_checkoption(L, i, LUA_APR_DBM_DEFAULT, options)]; } /* datum_check(L, i, datum) -- get datum object from Lua stack {{{2 */ static void datum_check(lua_State *L, int i, apr_datum_t *d) { size_t size; /* XXX I assume key datums are never modified by callees?! */ d->dptr = (char*)luaL_checklstring(L, i, &size); d->dsize = size; } /* dbm_close_impl(L, dbm) -- close dbm handle {{{2 */ static void dbm_close_impl(lua_State *L, lua_apr_dbm *dbm) { if (dbm->handle != NULL) { apr_dbm_close(dbm->handle); dbm->handle = NULL; } if (dbm->pool != NULL) { apr_pool_destroy(dbm->pool); dbm->pool = NULL; } } /* apr.dbm_open(path [, mode [, permissions [, type ]]]) -> dbm object {{{1 * * Open a [dbm] [dbm] file by @path. On success a database object is returned, * otherwise a nil followed by an error message is returned. The following * @mode strings are supported: * * - `'r'` to open an existing database for reading only (this is the default) * - `'w'` to open an existing database for reading and writing * - `'c'` to open a database for reading and writing, creating it if it * doesn't exist * - `'n'` to open a database for reading and writing, truncating it if it * already exists * * The @permissions string is documented elsewhere. Valid values for @type are * listed in the introductory text for this module. Also note that the @path * string may not be a real file name, as many [dbm] [dbm] packages append * suffixes for separate data and index files (see also * `apr.dbm_getnames()`). */ int lua_apr_dbm_open(lua_State *L) { const char *options[] = { "r", "w", "c", "n" }; const apr_int32_t values[] = { APR_DBM_READONLY, APR_DBM_READWRITE, APR_DBM_RWCREATE, APR_DBM_RWTRUNC }; const char *path, *type; apr_int32_t mode; apr_fileperms_t perm; lua_apr_dbm *object; apr_status_t status; path = luaL_checkstring(L, 1); mode = values[luaL_checkoption(L, 2, "r", options)]; perm = check_permissions(L, 3, 1); type = dbmtype_check(L, 4); object = new_object(L, &lua_apr_dbm_type); object->path = path; status = apr_pool_create(&object->pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); status = apr_dbm_open_ex(&object->handle, type, path, mode, perm, object->pool); if (status != APR_SUCCESS) return push_error_status(L, status); return 1; } /* apr.dbm_getnames(path [, type]) -> used1 [, used2] {{{1 * * If the specified @path were passed to `apr.dbm_open()`, return the actual * pathnames which would be (created and) used. At most, two files may be used; * @used2 is nil if only one file is used. The [dbm] [dbm] file(s) don't need * to exist because this function only manipulates the pathnames. Valid values * for @type are listed in the introductory text for this module. */ int lua_apr_dbm_getnames(lua_State *L) { apr_pool_t *pool; const char *path, *type, *used1 = NULL, *used2 = NULL; apr_status_t status; pool = to_pool(L); path = luaL_checkstring(L, 1); type = dbmtype_check(L, 2); /* XXX Use apr_dbm_get_usednames_ex() instead of apr_dbm_get_usednames() * because the latter returns void while in reality it can fail and not set * the used1 variable! :-\ */ status = apr_dbm_get_usednames_ex(pool, type, path, &used1, &used2); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, used1); if (used2 == NULL) return 1; lua_pushstring(L, used2); return 2; } /* dbm:exists(key) -> status {{{1 * * Check whether the [dbm] [dbm] record with the given string @key exists. */ int dbm_exists(lua_State *L) { lua_apr_dbm *object; apr_datum_t key; object = dbm_check(L, 1, 1); datum_check(L, 2, &key); lua_pushboolean(L, apr_dbm_exists(object->handle, key)); return 1; } /* dbm:fetch(key) -> value {{{1 * * Fetch the [dbm] [dbm] record with the given string @key. On success the * fetched value is returned as a string, if the key doesn't exist nothing is * returned and on error a nil followed by an error message is returned. */ int dbm_fetch(lua_State *L) { lua_apr_dbm *object; apr_datum_t key, val; apr_status_t status; object = dbm_check(L, 1, 1); datum_check(L, 2, &key); status = apr_dbm_fetch(object->handle, key, &val); if (status != APR_SUCCESS) return push_error_status(L, status); else if (val.dsize == 0) return 0; lua_pushlstring(L, val.dptr, val.dsize); return 1; } /* dbm:store(key, value) -> status {{{1 * * Store the [dbm] [dbm] record @value (a string) by the given string @key. On * success true is returned, otherwise a nil followed by an error message is * returned. */ int dbm_store(lua_State *L) { lua_apr_dbm *object; apr_datum_t key, val; apr_status_t status; object = dbm_check(L, 1, 1); datum_check(L, 2, &key); datum_check(L, 3, &val); status = apr_dbm_store(object->handle, key, val); return push_status(L, status); } /* dbm:delete(key) -> status {{{1 * * Delete the [dbm] [dbm] record with the given string @key. On success true is * returned, otherwise a nil followed by an error message is returned. */ int dbm_delete(lua_State *L) { lua_apr_dbm *object; apr_datum_t key; apr_status_t status; object = dbm_check(L, 1, 1); datum_check(L, 2, &key); status = apr_dbm_delete(object->handle, key); return push_status(L, status); } /* dbm:firstkey() -> key {{{1 * * Retrieve the first record key from a [dbm] [dbm]. On success the first key * is returned as a string, when there are no keys nothing is returned. In case * of error a nil followed by an error message is returned. */ int dbm_firstkey(lua_State *L) { lua_apr_dbm *object; apr_datum_t key; apr_status_t status; object = dbm_check(L, 1, 1); status = apr_dbm_firstkey(object->handle, &key); if (status != APR_SUCCESS) return push_error_status(L, status); else if (key.dsize == 0) return 0; lua_pushlstring(L, key.dptr, key.dsize); return 1; } /* dbm:nextkey(key1) -> key2 {{{1 * * Retrieve the next record key from a [dbm] [dbm]. This function works just * like Lua's `next()` function: On success the next key is returned as a * string, when there are no more keys nothing is returned. In case of error a * nil followed by an error message is returned. */ int dbm_nextkey(lua_State *L) { lua_apr_dbm *object; apr_datum_t key; apr_status_t status; object = dbm_check(L, 1, 1); datum_check(L, 2, &key); status = apr_dbm_nextkey(object->handle, &key); if (status != APR_SUCCESS) return push_error_status(L, status); else if (key.dsize == 0) return 0; lua_pushlstring(L, key.dptr, key.dsize); return 1; } /* dbm:close() -> status {{{1 * * Close a [dbm] [dbm] database handle and return true (this can't fail). */ int dbm_close(lua_State *L) { lua_apr_dbm *dbm; dbm = dbm_check(L, 1, 1); dbm_close_impl(L, dbm); lua_pushboolean(L, 1); return 1; } /* dbm:__tostring() {{{1 */ int dbm_tostring(lua_State *L) { lua_apr_dbm *dbm; dbm = dbm_check(L, 1, 0); if (dbm->handle != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_dbm_type.friendlyname, dbm->handle); else lua_pushfstring(L, "%s (closed)", lua_apr_dbm_type.friendlyname); return 1; } /* dbm:__gc() {{{1 */ int dbm_gc(lua_State *L) { lua_apr_dbm *dbm = dbm_check(L, 1, 0); if (object_collectable((lua_apr_refobj*)dbm)) dbm_close_impl(L, dbm); release_object((lua_apr_refobj*)dbm); return 0; } /* }}} */ luaL_reg dbm_methods[] = { { "close", dbm_close }, { "delete", dbm_delete }, { "exists", dbm_exists }, { "fetch", dbm_fetch }, { "firstkey", dbm_firstkey }, { "nextkey", dbm_nextkey }, { "store", dbm_store }, { NULL, NULL }, }; luaL_reg dbm_metamethods[] = { { "__tostring", dbm_tostring }, { "__eq", objects_equal }, { "__gc", dbm_gc }, { NULL, NULL }, }; lua_apr_objtype lua_apr_dbm_type = { "lua_apr_dbm*", /* metatable name in registry */ "dbm", /* friendly object name */ sizeof(lua_apr_dbm), /* structure size */ dbm_methods, /* methods table */ dbm_metamethods /* metamethods table */ }; lua-apr-0.23.2.dfsg/src/env.c000066400000000000000000000047161220664456000156210ustar00rootroot00000000000000/* Environment manipulation module for the Lua/APR binding. * * Author: Peter Odding * Last Change: September 19, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Operating systems organize tasks into processes. One of the simplest means * of communication between processes is the use of environment variables. If * you're not familiar with environment variables, picture every process on * your computer having an associated Lua table with string key/value pairs. * When a process creates or overwrites a key/value pair only the table of that * process changes. When the process spawns a child process the child gets a * copy of the table which from that point onwards is no longer associated with * the parent process. */ #include "lua_apr.h" #include /* apr.env_get(name) -> value {{{1 * * Get the value of the environment variable @name. On success the string value * is returned. If the variable does not exist nothing is returned. Otherwise a * nil followed by an error message is returned. */ int lua_apr_env_get(lua_State *L) { apr_pool_t *memory_pool; apr_status_t status; const char *name; char *value; memory_pool = to_pool(L); name = luaL_checkstring(L, 1); status = apr_env_get(&value, name, memory_pool); if (APR_STATUS_IS_ENOENT(status)) { return 0; } else if (status != APR_SUCCESS) { return push_error_status(L, status); } else { lua_pushstring(L, value); return 1; } } /* apr.env_set(name, value) -> status {{{1 * * Set the value of the environment variable @name to the string @value. On * success true is returned, otherwise a nil followed by an error message is * returned. */ int lua_apr_env_set(lua_State *L) { const char *name, *value; apr_pool_t *memory_pool; apr_status_t status; memory_pool = to_pool(L); name = luaL_checkstring(L, 1); value = luaL_checkstring(L, 2); status = apr_env_set(name, value, memory_pool); return push_status(L, status); } /* apr.env_delete(name) -> status {{{1 * * Delete the environment variable @name. On success true is returned, * otherwise a nil followed by an error message is returned. */ int lua_apr_env_delete(lua_State *L) { apr_pool_t *memory_pool; apr_status_t status; const char *name; memory_pool = to_pool(L); name = luaL_checkstring(L, 1); status = apr_env_delete(name, memory_pool); return push_status(L, status); } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/errno.c000066400000000000000000000511631220664456000161540ustar00rootroot00000000000000/* Error handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 07, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Most functions in the Lua/APR binding follow the Lua idiom of returning nil * followed by an error message string. These functions also return a third * argument which is the symbolic name of the error (or the error code in case * a symbolic name cannot be determined). The following symbolic names are * currently defined (there's actually a lot more but they shouldn't be * relevant when working in Lua): * * - `'ENOSTAT'`: APR was unable to perform a stat on the file * - `'EBADDATE'`: APR was given an invalid date * - `'EINVALSOCK'`: APR was given an invalid socket * - `'ENOPROC'`: APR was not given a process structure * - `'ENOTIME'`: APR was not given a time structure * - `'ENODIR'`: APR was not given a directory structure * - `'ENOTHREAD'`: APR was not given a thread structure * - `'EBADIP'`: the specified IP address is invalid * - `'EBADMASK'`: the specified netmask is invalid * - `'EDSOOPEN'`: APR was unable to open the DSO object * - `'EABSOLUTE'`: the given path was absolute * - `'ERELATIVE'`: the given path was relative * - `'EINCOMPLETE'`: the given path was neither relative nor absolute * - `'EABOVEROOT'`: the given path was above the root path * - `'EBADPATH'`: the given path was bad * - `'EPATHWILD'`: the given path contained wildcards * - `'ESYMNOTFOUND'`: could not find the requested symbol * - `'EPROC_UNKNOWN'`: the given process was not recognized by APR * - `'ENOTENOUGHENTROPY'`: APR could not gather enough [entropy] [entropy] to continue * - `'TIMEUP'`: the operation did not finish before the timeout * - `'INCOMPLETE'`: the operation was incomplete although some processing was performed and the results are partially valid * - `'EOF'`: APR has encountered the end of the file * - `'ENOTIMPL'`: the APR function has not been implemented on this platform, either because nobody has gotten to it yet, or the function is impossible on this platform * - `'EMISMATCH'`: two passwords do not match * - `'EACCES'`: permission denied * - `'EEXIST'`: file exists * - `'ENAMETOOLONG'`: path name is too long * - `'ENOENT'`: no such file or directory * - `'ENOTDIR'`: not a directory * - `'ENOSPC'`: no space left on device * - `'ENOMEM'`: not enough memory * - `'EMFILE'`: too many open files * - `'ENFILE'`: file table overflow * - `'EBADF'`: bad file number * - `'EINVAL'`: invalid argument * - `'ESPIPE'`: illegal seek * - `'EAGAIN'`: operation would block * - `'EINTR'`: interrupted system call * - `'ENOTSOCK'`: socket operation on a non-socket * - `'ECONNREFUSED'`: connection refused * - `'EINPROGRESS'`: operation now in progress * - `'ECONNABORTED'`: software caused connection abort * - `'ECONNRESET'`: connection Reset by peer * - `'ETIMEDOUT'`: operation timed out (deprecated) * - `'EHOSTUNREACH'`: no route to host * - `'ENETUNREACH'`: network is unreachable * - `'EFTYPE'`: inappropriate file type or format * - `'EPIPE'`: broken pipe * - `'EXDEV'`: cross device link * - `'ENOTEMPTY'`: directory not empty * - `'EAFNOSUPPORT'`: address family not supported * * Note that the error descriptions above were copied verbatim from [apr_errno.h] [errno]. * * [entropy]: http://en.wikipedia.org/wiki/Entropy_%28computing%29 * [errno]: http://svn.apache.org/viewvc/apr/apr/trunk/include/apr_errno.h?view=markup */ #include "lua_apr.h" #include void status_to_name(lua_State *L, apr_status_t status) { /* Use a switch statement for fast number to string mapping: */ switch (status) { # ifdef APR_ANONYMOUS case APR_ANONYMOUS: lua_pushliteral(L, "ANONYMOUS"); return; # endif # ifdef APR_BADARG case APR_BADARG: lua_pushliteral(L, "BADARG"); return; # endif # ifdef APR_BADCH case APR_BADCH: lua_pushliteral(L, "BADCH"); return; # endif # ifdef APR_DETACH case APR_DETACH: lua_pushliteral(L, "DETACH"); return; # endif # ifdef APR_EABOVEROOT case APR_EABOVEROOT: lua_pushliteral(L, "EABOVEROOT"); return; # endif # ifdef APR_EABSOLUTE case APR_EABSOLUTE: lua_pushliteral(L, "EABSOLUTE"); return; # endif # ifdef APR_EACCES case APR_EACCES: lua_pushliteral(L, "EACCES"); return; # endif # ifdef APR_EAFNOSUPPORT case APR_EAFNOSUPPORT: lua_pushliteral(L, "EAFNOSUPPORT"); return; # endif # ifdef APR_EAGAIN case APR_EAGAIN: lua_pushliteral(L, "EAGAIN"); return; # endif # ifdef APR_EBADDATE case APR_EBADDATE: lua_pushliteral(L, "EBADDATE"); return; # endif # ifdef APR_EBADF case APR_EBADF: lua_pushliteral(L, "EBADF"); return; # endif # ifdef APR_EBADIP case APR_EBADIP: lua_pushliteral(L, "EBADIP"); return; # endif # ifdef APR_EBADMASK case APR_EBADMASK: lua_pushliteral(L, "EBADMASK"); return; # endif # ifdef APR_EBADPATH case APR_EBADPATH: lua_pushliteral(L, "EBADPATH"); return; # endif # ifdef APR_EBUSY case APR_EBUSY: lua_pushliteral(L, "EBUSY"); return; # endif # ifdef APR_ECONNABORTED case APR_ECONNABORTED: lua_pushliteral(L, "ECONNABORTED"); return; # endif # ifdef APR_ECONNREFUSED case APR_ECONNREFUSED: lua_pushliteral(L, "ECONNREFUSED"); return; # endif # ifdef APR_ECONNRESET case APR_ECONNRESET: lua_pushliteral(L, "ECONNRESET"); return; # endif # ifdef APR_EDSOOPEN case APR_EDSOOPEN: lua_pushliteral(L, "EDSOOPEN"); return; # endif # ifdef APR_EEXIST case APR_EEXIST: lua_pushliteral(L, "EEXIST"); return; # endif # ifdef APR_EFTYPE case APR_EFTYPE: lua_pushliteral(L, "EFTYPE"); return; # endif # ifdef APR_EGENERAL case APR_EGENERAL: lua_pushliteral(L, "EGENERAL"); return; # endif # ifdef APR_EHOSTUNREACH case APR_EHOSTUNREACH: lua_pushliteral(L, "EHOSTUNREACH"); return; # endif # ifdef APR_EINCOMPLETE case APR_EINCOMPLETE: lua_pushliteral(L, "EINCOMPLETE"); return; # endif # ifdef APR_EINIT case APR_EINIT: lua_pushliteral(L, "EINIT"); return; # endif # ifdef APR_EINPROGRESS case APR_EINPROGRESS: lua_pushliteral(L, "EINPROGRESS"); return; # endif # ifdef APR_EINTR case APR_EINTR: lua_pushliteral(L, "EINTR"); return; # endif # ifdef APR_EINVAL case APR_EINVAL: lua_pushliteral(L, "EINVAL"); return; # endif # ifdef APR_EINVALSOCK case APR_EINVALSOCK: lua_pushliteral(L, "EINVALSOCK"); return; # endif # ifdef APR_EMFILE case APR_EMFILE: lua_pushliteral(L, "EMFILE"); return; # endif # ifdef APR_EMISMATCH case APR_EMISMATCH: lua_pushliteral(L, "EMISMATCH"); return; # endif # ifdef APR_ENAMETOOLONG case APR_ENAMETOOLONG: lua_pushliteral(L, "ENAMETOOLONG"); return; # endif # ifdef APR_ENETUNREACH case APR_ENETUNREACH: lua_pushliteral(L, "ENETUNREACH"); return; # endif # ifdef APR_ENFILE case APR_ENFILE: lua_pushliteral(L, "ENFILE"); return; # endif # ifdef APR_ENODIR case APR_ENODIR: lua_pushliteral(L, "ENODIR"); return; # endif # ifdef APR_ENOENT case APR_ENOENT: lua_pushliteral(L, "ENOENT"); return; # endif # ifdef APR_ENOLOCK case APR_ENOLOCK: lua_pushliteral(L, "ENOLOCK"); return; # endif # ifdef APR_ENOMEM case APR_ENOMEM: lua_pushliteral(L, "ENOMEM"); return; # endif # ifdef APR_ENOPOLL case APR_ENOPOLL: lua_pushliteral(L, "ENOPOLL"); return; # endif # ifdef APR_ENOPOOL case APR_ENOPOOL: lua_pushliteral(L, "ENOPOOL"); return; # endif # ifdef APR_ENOPROC case APR_ENOPROC: lua_pushliteral(L, "ENOPROC"); return; # endif # ifdef APR_ENOSHMAVAIL case APR_ENOSHMAVAIL: lua_pushliteral(L, "ENOSHMAVAIL"); return; # endif # ifdef APR_ENOSOCKET case APR_ENOSOCKET: lua_pushliteral(L, "ENOSOCKET"); return; # endif # ifdef APR_ENOSPC case APR_ENOSPC: lua_pushliteral(L, "ENOSPC"); return; # endif # ifdef APR_ENOSTAT case APR_ENOSTAT: lua_pushliteral(L, "ENOSTAT"); return; # endif # ifdef APR_ENOTDIR case APR_ENOTDIR: lua_pushliteral(L, "ENOTDIR"); return; # endif # ifdef APR_ENOTEMPTY case APR_ENOTEMPTY: lua_pushliteral(L, "ENOTEMPTY"); return; # endif # ifdef APR_ENOTENOUGHENTROPY case APR_ENOTENOUGHENTROPY: lua_pushliteral(L, "ENOTENOUGHENTROPY"); return; # endif # ifdef APR_ENOTHDKEY case APR_ENOTHDKEY: lua_pushliteral(L, "ENOTHDKEY"); return; # endif # ifdef APR_ENOTHREAD case APR_ENOTHREAD: lua_pushliteral(L, "ENOTHREAD"); return; # endif # ifdef APR_ENOTIME case APR_ENOTIME: lua_pushliteral(L, "ENOTIME"); return; # endif # ifdef APR_ENOTIMPL case APR_ENOTIMPL: lua_pushliteral(L, "ENOTIMPL"); return; # endif # ifdef APR_ENOTSOCK case APR_ENOTSOCK: lua_pushliteral(L, "ENOTSOCK"); return; # endif # ifdef APR_EOF case APR_EOF: lua_pushliteral(L, "EOF"); return; # endif # ifdef APR_EPATHWILD case APR_EPATHWILD: lua_pushliteral(L, "EPATHWILD"); return; # endif # ifdef APR_EPIPE case APR_EPIPE: lua_pushliteral(L, "EPIPE"); return; # endif # ifdef APR_EPROC_UNKNOWN case APR_EPROC_UNKNOWN: lua_pushliteral(L, "EPROC_UNKNOWN"); return; # endif # ifdef APR_ERELATIVE case APR_ERELATIVE: lua_pushliteral(L, "ERELATIVE"); return; # endif # ifdef APR_ESPIPE case APR_ESPIPE: lua_pushliteral(L, "ESPIPE"); return; # endif # ifdef APR_ESYMNOTFOUND case APR_ESYMNOTFOUND: lua_pushliteral(L, "ESYMNOTFOUND"); return; # endif # ifdef APR_ETIMEDOUT case APR_ETIMEDOUT: lua_pushliteral(L, "ETIMEDOUT"); return; # endif # ifdef APR_EXDEV case APR_EXDEV: lua_pushliteral(L, "EXDEV"); return; # endif # ifdef APR_FILEBASED case APR_FILEBASED: lua_pushliteral(L, "FILEBASED"); return; # endif # ifdef APR_INCHILD case APR_INCHILD: lua_pushliteral(L, "INCHILD"); return; # endif # ifdef APR_INCOMPLETE case APR_INCOMPLETE: lua_pushliteral(L, "INCOMPLETE"); return; # endif # ifdef APR_INPARENT case APR_INPARENT: lua_pushliteral(L, "INPARENT"); return; # endif # ifdef APR_KEYBASED case APR_KEYBASED: lua_pushliteral(L, "KEYBASED"); return; # endif # ifdef APR_NOTDETACH case APR_NOTDETACH: lua_pushliteral(L, "NOTDETACH"); return; # endif # ifdef APR_NOTFOUND case APR_NOTFOUND: lua_pushliteral(L, "NOTFOUND"); return; # endif # ifdef APR_SUCCESS case APR_SUCCESS: lua_pushliteral(L, "SUCCESS"); return; # endif # ifdef APR_TIMEUP case APR_TIMEUP: lua_pushliteral(L, "TIMEUP"); return; # endif } /* If the switch statement fails we fall back to the following monstrosity :-) */ if (0) ; # ifdef APR_STATUS_IS_ANONYMOUS else if (APR_STATUS_IS_ANONYMOUS(status)) { lua_pushliteral(L, "ANONYMOUS"); return; } # endif # ifdef APR_STATUS_IS_BADARG else if (APR_STATUS_IS_BADARG(status)) { lua_pushliteral(L, "BADARG"); return; } # endif # ifdef APR_STATUS_IS_BADCH else if (APR_STATUS_IS_BADCH(status)) { lua_pushliteral(L, "BADCH"); return; } # endif # ifdef APR_STATUS_IS_DETACH else if (APR_STATUS_IS_DETACH(status)) { lua_pushliteral(L, "DETACH"); return; } # endif # ifdef APR_STATUS_IS_EABOVEROOT else if (APR_STATUS_IS_EABOVEROOT(status)) { lua_pushliteral(L, "EABOVEROOT"); return; } # endif # ifdef APR_STATUS_IS_EABSOLUTE else if (APR_STATUS_IS_EABSOLUTE(status)) { lua_pushliteral(L, "EABSOLUTE"); return; } # endif # ifdef APR_STATUS_IS_EACCES else if (APR_STATUS_IS_EACCES(status)) { lua_pushliteral(L, "EACCES"); return; } # endif # ifdef APR_STATUS_IS_EAFNOSUPPORT else if (APR_STATUS_IS_EAFNOSUPPORT(status)) { lua_pushliteral(L, "EAFNOSUPPORT"); return; } # endif # ifdef APR_STATUS_IS_EAGAIN else if (APR_STATUS_IS_EAGAIN(status)) { lua_pushliteral(L, "EAGAIN"); return; } # endif # ifdef APR_STATUS_IS_EBADDATE else if (APR_STATUS_IS_EBADDATE(status)) { lua_pushliteral(L, "EBADDATE"); return; } # endif # ifdef APR_STATUS_IS_EBADF else if (APR_STATUS_IS_EBADF(status)) { lua_pushliteral(L, "EBADF"); return; } # endif # ifdef APR_STATUS_IS_EBADIP else if (APR_STATUS_IS_EBADIP(status)) { lua_pushliteral(L, "EBADIP"); return; } # endif # ifdef APR_STATUS_IS_EBADMASK else if (APR_STATUS_IS_EBADMASK(status)) { lua_pushliteral(L, "EBADMASK"); return; } # endif # ifdef APR_STATUS_IS_EBADPATH else if (APR_STATUS_IS_EBADPATH(status)) { lua_pushliteral(L, "EBADPATH"); return; } # endif # ifdef APR_STATUS_IS_EBUSY else if (APR_STATUS_IS_EBUSY(status)) { lua_pushliteral(L, "EBUSY"); return; } # endif # ifdef APR_STATUS_IS_ECONNABORTED else if (APR_STATUS_IS_ECONNABORTED(status)) { lua_pushliteral(L, "ECONNABORTED"); return; } # endif # ifdef APR_STATUS_IS_ECONNREFUSED else if (APR_STATUS_IS_ECONNREFUSED(status)) { lua_pushliteral(L, "ECONNREFUSED"); return; } # endif # ifdef APR_STATUS_IS_ECONNRESET else if (APR_STATUS_IS_ECONNRESET(status)) { lua_pushliteral(L, "ECONNRESET"); return; } # endif # ifdef APR_STATUS_IS_EDSOOPEN else if (APR_STATUS_IS_EDSOOPEN(status)) { lua_pushliteral(L, "EDSOOPEN"); return; } # endif # ifdef APR_STATUS_IS_EEXIST else if (APR_STATUS_IS_EEXIST(status)) { lua_pushliteral(L, "EEXIST"); return; } # endif # ifdef APR_STATUS_IS_EFTYPE else if (APR_STATUS_IS_EFTYPE(status)) { lua_pushliteral(L, "EFTYPE"); return; } # endif # ifdef APR_STATUS_IS_EGENERAL else if (APR_STATUS_IS_EGENERAL(status)) { lua_pushliteral(L, "EGENERAL"); return; } # endif # ifdef APR_STATUS_IS_EHOSTUNREACH else if (APR_STATUS_IS_EHOSTUNREACH(status)) { lua_pushliteral(L, "EHOSTUNREACH"); return; } # endif # ifdef APR_STATUS_IS_EINCOMPLETE else if (APR_STATUS_IS_EINCOMPLETE(status)) { lua_pushliteral(L, "EINCOMPLETE"); return; } # endif # ifdef APR_STATUS_IS_EINIT else if (APR_STATUS_IS_EINIT(status)) { lua_pushliteral(L, "EINIT"); return; } # endif # ifdef APR_STATUS_IS_EINPROGRESS else if (APR_STATUS_IS_EINPROGRESS(status)) { lua_pushliteral(L, "EINPROGRESS"); return; } # endif # ifdef APR_STATUS_IS_EINTR else if (APR_STATUS_IS_EINTR(status)) { lua_pushliteral(L, "EINTR"); return; } # endif # ifdef APR_STATUS_IS_EINVAL else if (APR_STATUS_IS_EINVAL(status)) { lua_pushliteral(L, "EINVAL"); return; } # endif # ifdef APR_STATUS_IS_EINVALSOCK else if (APR_STATUS_IS_EINVALSOCK(status)) { lua_pushliteral(L, "EINVALSOCK"); return; } # endif # ifdef APR_STATUS_IS_EMFILE else if (APR_STATUS_IS_EMFILE(status)) { lua_pushliteral(L, "EMFILE"); return; } # endif # ifdef APR_STATUS_IS_EMISMATCH else if (APR_STATUS_IS_EMISMATCH(status)) { lua_pushliteral(L, "EMISMATCH"); return; } # endif # ifdef APR_STATUS_IS_ENAMETOOLONG else if (APR_STATUS_IS_ENAMETOOLONG(status)) { lua_pushliteral(L, "ENAMETOOLONG"); return; } # endif # ifdef APR_STATUS_IS_ENETUNREACH else if (APR_STATUS_IS_ENETUNREACH(status)) { lua_pushliteral(L, "ENETUNREACH"); return; } # endif # ifdef APR_STATUS_IS_ENFILE else if (APR_STATUS_IS_ENFILE(status)) { lua_pushliteral(L, "ENFILE"); return; } # endif # ifdef APR_STATUS_IS_ENODIR else if (APR_STATUS_IS_ENODIR(status)) { lua_pushliteral(L, "ENODIR"); return; } # endif # ifdef APR_STATUS_IS_ENOENT else if (APR_STATUS_IS_ENOENT(status)) { lua_pushliteral(L, "ENOENT"); return; } # endif # ifdef APR_STATUS_IS_ENOLOCK else if (APR_STATUS_IS_ENOLOCK(status)) { lua_pushliteral(L, "ENOLOCK"); return; } # endif # ifdef APR_STATUS_IS_ENOMEM else if (APR_STATUS_IS_ENOMEM(status)) { lua_pushliteral(L, "ENOMEM"); return; } # endif # ifdef APR_STATUS_IS_ENOPOLL else if (APR_STATUS_IS_ENOPOLL(status)) { lua_pushliteral(L, "ENOPOLL"); return; } # endif # ifdef APR_STATUS_IS_ENOPOOL else if (APR_STATUS_IS_ENOPOOL(status)) { lua_pushliteral(L, "ENOPOOL"); return; } # endif # ifdef APR_STATUS_IS_ENOPROC else if (APR_STATUS_IS_ENOPROC(status)) { lua_pushliteral(L, "ENOPROC"); return; } # endif # ifdef APR_STATUS_IS_ENOSHMAVAIL else if (APR_STATUS_IS_ENOSHMAVAIL(status)) { lua_pushliteral(L, "ENOSHMAVAIL"); return; } # endif # ifdef APR_STATUS_IS_ENOSOCKET else if (APR_STATUS_IS_ENOSOCKET(status)) { lua_pushliteral(L, "ENOSOCKET"); return; } # endif # ifdef APR_STATUS_IS_ENOSPC else if (APR_STATUS_IS_ENOSPC(status)) { lua_pushliteral(L, "ENOSPC"); return; } # endif # ifdef APR_STATUS_IS_ENOSTAT else if (APR_STATUS_IS_ENOSTAT(status)) { lua_pushliteral(L, "ENOSTAT"); return; } # endif # ifdef APR_STATUS_IS_ENOTDIR else if (APR_STATUS_IS_ENOTDIR(status)) { lua_pushliteral(L, "ENOTDIR"); return; } # endif # ifdef APR_STATUS_IS_ENOTEMPTY else if (APR_STATUS_IS_ENOTEMPTY(status)) { lua_pushliteral(L, "ENOTEMPTY"); return; } # endif # ifdef APR_STATUS_IS_ENOTENOUGHENTROPY else if (APR_STATUS_IS_ENOTENOUGHENTROPY(status)) { lua_pushliteral(L, "ENOTENOUGHENTROPY"); return; } # endif # ifdef APR_STATUS_IS_ENOTHDKEY else if (APR_STATUS_IS_ENOTHDKEY(status)) { lua_pushliteral(L, "ENOTHDKEY"); return; } # endif # ifdef APR_STATUS_IS_ENOTHREAD else if (APR_STATUS_IS_ENOTHREAD(status)) { lua_pushliteral(L, "ENOTHREAD"); return; } # endif # ifdef APR_STATUS_IS_ENOTIME else if (APR_STATUS_IS_ENOTIME(status)) { lua_pushliteral(L, "ENOTIME"); return; } # endif # ifdef APR_STATUS_IS_ENOTIMPL else if (APR_STATUS_IS_ENOTIMPL(status)) { lua_pushliteral(L, "ENOTIMPL"); return; } # endif # ifdef APR_STATUS_IS_ENOTSOCK else if (APR_STATUS_IS_ENOTSOCK(status)) { lua_pushliteral(L, "ENOTSOCK"); return; } # endif # ifdef APR_STATUS_IS_EOF else if (APR_STATUS_IS_EOF(status)) { lua_pushliteral(L, "EOF"); return; } # endif # ifdef APR_STATUS_IS_EPATHWILD else if (APR_STATUS_IS_EPATHWILD(status)) { lua_pushliteral(L, "EPATHWILD"); return; } # endif # ifdef APR_STATUS_IS_EPIPE else if (APR_STATUS_IS_EPIPE(status)) { lua_pushliteral(L, "EPIPE"); return; } # endif # ifdef APR_STATUS_IS_EPROC_UNKNOWN else if (APR_STATUS_IS_EPROC_UNKNOWN(status)) { lua_pushliteral(L, "EPROC_UNKNOWN"); return; } # endif # ifdef APR_STATUS_IS_ERELATIVE else if (APR_STATUS_IS_ERELATIVE(status)) { lua_pushliteral(L, "ERELATIVE"); return; } # endif # ifdef APR_STATUS_IS_ESPIPE else if (APR_STATUS_IS_ESPIPE(status)) { lua_pushliteral(L, "ESPIPE"); return; } # endif # ifdef APR_STATUS_IS_ESYMNOTFOUND else if (APR_STATUS_IS_ESYMNOTFOUND(status)) { lua_pushliteral(L, "ESYMNOTFOUND"); return; } # endif # ifdef APR_STATUS_IS_ETIMEDOUT else if (APR_STATUS_IS_ETIMEDOUT(status)) { lua_pushliteral(L, "ETIMEDOUT"); return; } # endif # ifdef APR_STATUS_IS_EXDEV else if (APR_STATUS_IS_EXDEV(status)) { lua_pushliteral(L, "EXDEV"); return; } # endif # ifdef APR_STATUS_IS_FILEBASED else if (APR_STATUS_IS_FILEBASED(status)) { lua_pushliteral(L, "FILEBASED"); return; } # endif # ifdef APR_STATUS_IS_INCHILD else if (APR_STATUS_IS_INCHILD(status)) { lua_pushliteral(L, "INCHILD"); return; } # endif # ifdef APR_STATUS_IS_INCOMPLETE else if (APR_STATUS_IS_INCOMPLETE(status)) { lua_pushliteral(L, "INCOMPLETE"); return; } # endif # ifdef APR_STATUS_IS_INPARENT else if (APR_STATUS_IS_INPARENT(status)) { lua_pushliteral(L, "INPARENT"); return; } # endif # ifdef APR_STATUS_IS_KEYBASED else if (APR_STATUS_IS_KEYBASED(status)) { lua_pushliteral(L, "KEYBASED"); return; } # endif # ifdef APR_STATUS_IS_NOTDETACH else if (APR_STATUS_IS_NOTDETACH(status)) { lua_pushliteral(L, "NOTDETACH"); return; } # endif # ifdef APR_STATUS_IS_NOTFOUND else if (APR_STATUS_IS_NOTFOUND(status)) { lua_pushliteral(L, "NOTFOUND"); return; } # endif # ifdef APR_STATUS_IS_TIMEUP else if (APR_STATUS_IS_TIMEUP(status)) { lua_pushliteral(L, "TIMEUP"); return; } # endif lua_pushinteger(L, status); } lua-apr-0.23.2.dfsg/src/filepath.c000066400000000000000000000265771220664456000166360ustar00rootroot00000000000000/* File path manipulation module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 1, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include #include #include #include static apr_int32_t check_options(lua_State *L, int idx) /* {{{1 */ { const char *options[] = { "true-name", "native", NULL }; const apr_int32_t values[] = { APR_FILEPATH_TRUENAME, APR_FILEPATH_NATIVE }; apr_int32_t flags = 0; while (!lua_isnoneornil(L, idx)) flags |= values[luaL_checkoption(L, idx++, NULL, options)]; return flags; } /* apr.filepath_root(path [, option, ...]) -> root, path {{{1 * * Extract the root from the file path @path. On success the extracted root and * the relative path following the root are returned, otherwise a nil followed * by an error message is returned. Either or both of the following options may * be given after @path: * * - `'true-name'` verifies that the root exists and resolves its true case. * If the root does not exist, a nil followed by an error message is * returned * - `'native'` uses the file system's native path format (e.g. path delimiters * of `:` on MacOS9, \\ on Win32, etc.) in the resulting root * * These options only influence the resulting root. The path after the root is * returned as is. If you want to convert a whole file path to its true case * and/or native format use `apr.filepath_merge()` instead. */ int lua_apr_filepath_root(lua_State *L) { apr_pool_t *memory_pool; const char *root, *path; apr_status_t status; apr_int32_t flags; memory_pool = to_pool(L); path = luaL_checkstring(L, 1); flags = check_options(L, 2); status = apr_filepath_root(&root, &path, flags, memory_pool); if (status != APR_SUCCESS && !APR_STATUS_IS_INCOMPLETE(status)) return push_error_status(L, status); lua_pushstring(L, root); lua_pushstring(L, path); return 2; } /* apr.filepath_parent(path [, option, ...]) -> parent, filename {{{1 * * Split the file path @path into its parent path and filename. This function * supports the same options as `apr.filepath_root()`. If any options are given * they're applied to @path before it is split, so the options influence both * of the resulting values. If @path is a filename and the `'true-name'` option * isn't given then the returned parent path will be an empty string. */ int lua_apr_filepath_parent(lua_State *L) { apr_pool_t *memory_pool; apr_status_t status; apr_int32_t flags; const char *input, *root, *path, *name; size_t length; char *buffer; memory_pool = to_pool(L); input = path = luaL_checkstring(L, 1); flags = check_options(L, 2); /* Check if the path is rooted because we don't want to damage the root. */ status = apr_filepath_root(&root, &input, flags, memory_pool); if (status == APR_SUCCESS || APR_STATUS_IS_INCOMPLETE(status)) path = input; else root = NULL; /* Copy the path to a writable buffer. */ if (flags == 0) { buffer = apr_pstrdup(memory_pool, path); } else { /* In the process we normalize the path as well. */ status = apr_filepath_merge(&buffer, NULL, path, flags, memory_pool); if (status != APR_SUCCESS) return push_error_status(L, status); } /* Ignore empty trailing path segments so we don't return an empty name (2nd * return value) unless the 1st return value is a root path. On UNIX we don't * want to strip the leading "/" so the first character is ignored. */ length = strlen(buffer); while (length > 0) if (buffer[length - 1] == '/') length--; # ifdef WIN32 else if (buffer[length - 1] == '\\') length--; # endif else break; /* Recombine root and path. */ buffer[length] = '\0'; status = apr_filepath_merge(&buffer, root, buffer, flags, memory_pool); if (status != APR_SUCCESS) return push_error_status(L, status); /* Finally we're ready to get the parent path... */ name = apr_filepath_name_get(buffer); lua_pushlstring(L, buffer, name - buffer); lua_pushstring(L, name); return 2; } /* apr.filepath_name(path [, split]) -> filename [, extension] {{{1 * * Extract the filename (the final element) from the file path @path. If @split * evaluates true then the extension will be split from the filename and * returned separately. Some examples of what is considered a filename or an * extension: * * > -- regular file path * > = apr.filepath_name('/usr/bin/lua', true) * 'lua', '' * * > -- hidden file on UNIX * > = apr.filepath_name('/home/xolox/.vimrc', true) * '.vimrc', '' * * > -- multiple extensions * > = apr.filepath_name('index.html.en', true) * 'index.html', '.en' */ int lua_apr_filepath_name(lua_State *L) { const char *path, *name, *ext = NULL; path = luaL_checkstring(L, 1); name = apr_filepath_name_get(path); if (!lua_toboolean(L, 2)) { lua_pushstring(L, name); return 1; } else { ext = strrchr(name, '.'); if (!ext || ext == name) ext = name + strlen(name); lua_pushlstring(L, name, ext - name); lua_pushstring(L, ext); return 2; } } /* apr.filepath_merge(root, path [, option, ...]) -> merged {{{1 * * Merge the file paths @root and @path. On success the merged file path is * returned, otherwise a nil followed by an error message is returned. Any * combination of one or more of the following options may be given: * * - `'true-name'` resolves the true case of existing elements in @path, * resolving any aliases on Windows, and appends a trailing slash if the * final element is a directory * - `'native'` uses the file system's native path format (e.g. path delimiters * of `:` on MacOS9, \\ on Win32, etc.) * - `'not-above-root'` fails if @path is above @root, e.g. if @root is * `/foo/bar` and @path is `../baz` * - `'not-absolute'` fails if the merged path is absolute * - `'not-relative'` fails if the merged path is relative * - `'secure-root'` fails if @path is above @root, even given the @root * `/foo/bar` and the @path `../bar/bash` * * This function can be used to generate absolute file paths as follows: * * apr.filepath_merge('.', 'filepath.c', 'not-relative') * -- the above is equivalent to the below: * apr.filepath_merge(apr.filepath_get(), 'filepath.c', 'not-relative') * */ int lua_apr_filepath_merge(lua_State *L) { const char *options[] = { "true-name", "native", "not-above-root", "not-absolute", "not-relative", "secure-root", NULL }; const apr_int32_t values[] = { APR_FILEPATH_TRUENAME, APR_FILEPATH_NATIVE, APR_FILEPATH_NOTABOVEROOT, APR_FILEPATH_NOTABSOLUTE, APR_FILEPATH_NOTRELATIVE, APR_FILEPATH_SECUREROOT }; apr_pool_t *memory_pool; const char *root, *path; apr_status_t status; apr_int32_t flags; char *merged; int arg; memory_pool = to_pool(L); root = luaL_checkstring(L, 1); path = luaL_checkstring(L, 2); if (strcmp(root, ".") == 0) root = NULL; for (arg = 3, flags = 0; !lua_isnoneornil(L, arg); arg++) flags |= values[luaL_checkoption(L, arg, NULL, options)]; status = apr_filepath_merge(&merged, root, path, flags, memory_pool); if (status != APR_SUCCESS && !APR_STATUS_IS_EPATHWILD(status)) return push_error_status(L, status); lua_pushstring(L, merged); return 1; } /* apr.filepath_list_split(searchpath) -> components {{{1 * * Split a search path string into a table of separate components. On success * the table of components is returned, otherwise a nil followed by an error * message is returned. Empty elements do not become part of the returned * table. * * An example of a search path is the [$PATH] [path_var] environment variable * available in UNIX and Windows operating systems which controls the way * program names are resolved to absolute pathnames (see * `apr.filepath_which()`). * * [path_var]: http://en.wikipedia.org/wiki/PATH_(variable) */ int lua_apr_filepath_list_split(lua_State *L) { apr_array_header_t *array; apr_pool_t *memory_pool; apr_status_t status; const char *liststr; int i; memory_pool = to_pool(L); liststr = luaL_checkstring(L, 1); status = apr_filepath_list_split(&array, liststr, memory_pool); if (status != APR_SUCCESS) return push_error_status(L, status); /* The APR array type is documented to be opaque and the only function to get * values from it uses stack semantics so we (ab)use Lua's stack to reverse * the order of the strings in the list (since order is VERY significant) */ lua_createtable(L, 0, array->nelts); for (i = 0; i < array->nelts; i++) { lua_pushstring(L, ((char **)array->elts)[i]); lua_rawseti(L, -2, i + 1); } return 1; } /* apr.filepath_list_merge(components) -> searchpath {{{1 * * Merge a table of search path components into a single search path string. On * success the table of components is returned, otherwise a nil followed by an * error message is returned. */ int lua_apr_filepath_list_merge(lua_State *L) { apr_array_header_t *array; unsigned int i, count; apr_pool_t *memory_pool; apr_status_t status; char *list; memory_pool = to_pool(L); luaL_checktype(L, 1, LUA_TTABLE); count = (unsigned int) lua_objlen(L, 1); array = apr_array_make(memory_pool, count, sizeof(char *)); if (!array) return push_error_memory(L); for (i = 1; i <= count; i++) { lua_rawgeti(L, -1, i); if (!lua_isstring(L, -1)) { const char *fmt = "expected string value at index " LUA_QL("%i") ", got %s"; luaL_argerror(L, 1, lua_pushfstring(L, fmt, i, luaL_typename(L, -1))); } else { const char **top = apr_array_push(array); if (!top) return push_error_memory(L); *top = apr_pstrdup(memory_pool, lua_tostring(L, -1)); lua_pop(L, 1); } } status = apr_filepath_list_merge(&list, array, memory_pool); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, list ? list : ""); return 1; } /* apr.filepath_get([native]) -> path {{{1 * * Get the default filepath for relative filenames. If @native evaluates true * the file system's native path format is used. On success the filepath is * returned, otherwise a nil followed by an error message is returned. * * On at least Windows and UNIX the default file path for relative file names * is the current working directory. Because some operating systems supported * by APR don't use this convention Lua/APR uses the term 'default filepath' * instead. */ int lua_apr_filepath_get(lua_State *L) { apr_pool_t *memory_pool; apr_status_t status; apr_int32_t flags; char *path; memory_pool = to_pool(L); flags = lua_toboolean(L, 1) ? APR_FILEPATH_NATIVE : 0; status = apr_filepath_get(&path, flags, memory_pool); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, path); return 1; } /* apr.filepath_set(path) -> status {{{1 * * Set the default file path for relative file names to the string @path. On * success true is returned, otherwise a nil followed by an error message is * returned. Also see the notes for `apr.filepath_get()`. */ int lua_apr_filepath_set(lua_State *L) { apr_pool_t *memory_pool; apr_status_t status; const char *path; memory_pool = to_pool(L); path = luaL_checkstring(L, 1); status = apr_filepath_set(path, memory_pool); return push_status(L, status); } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/fnmatch.c000066400000000000000000000034771220664456000164540ustar00rootroot00000000000000/* Filename matching module for the Lua/APR binding. * * Author: Peter Odding * Last Change: January 2, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include /* apr.fnmatch(pattern, input [, ignorecase]) -> status {{{1 * * Try to match a string against a filename pattern. When the string matches * the pattern true is returned, otherwise false. The supported pattern items * are the following subset of shell wild cards: * * - `?` matches one character (any character) * - `*` matches zero or more characters (any character) * - `\x` escapes the special meaning of the character `x` * - `[set]` matches one character within set. A range of characters can be * specified by separating the characters of the range with a * - character * - `[^set]` matches the complement of set, where set is defined as above * * If the optional argument @ignorecase is true, characters are compared * case-insensitively. */ int lua_apr_fnmatch(lua_State *L) { apr_status_t status; const char *pattern, *input; int flags; pattern = luaL_checkstring(L, 1); input = luaL_checkstring(L, 2); flags = lua_toboolean(L, 3) ? APR_FNM_CASE_BLIND : 0; status = apr_fnmatch(pattern, input, flags); lua_pushboolean(L, APR_SUCCESS == status); return 1; } /* apr.fnmatch_test(pattern) -> status {{{1 * * Determine if a file path @pattern contains one or more of the wild cards * that are supported by `apr.fnmatch()`. On success true is returned, * otherwise false. */ int lua_apr_fnmatch_test(lua_State *L) { const char *string; int pattern = 0; string = luaL_checkstring(L, 1); pattern = apr_fnmatch_test(string); lua_pushboolean(L, pattern); return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/getopt.c000066400000000000000000000067671220664456000163430ustar00rootroot00000000000000/* Command argument parsing module for the Lua/APR binding. * * Author: Peter Odding * Last Change: February 25, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include int lua_apr_getopt(lua_State *L) { apr_status_t status; apr_pool_t *pool; apr_getopt_t *os; const char *s, **argv; apr_getopt_option_t *opts; int i, j, argc, optc, silent; /* XXX No data validation because only apr.lua calls us directly! */ silent = lua_toboolean(L, 3); lua_settop(L, 2); status = apr_pool_create(&pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); /* Copy options to array of apr_getopt_option_t structures. */ optc = lua_objlen(L, 1); opts = apr_palloc(pool, sizeof opts[0] * (optc + 1)); for (i = 1; i <= optc; i++) { lua_rawgeti(L, 1, i); lua_getfield(L, -1, "optch"); s = lua_tostring(L, -1); opts[i - 1].optch = s && s[0] ? s[0] : 256; lua_pop(L, 1); lua_getfield(L, -1, "name"); opts[i - 1].name = lua_tostring(L, -1); lua_pop(L, 1); lua_getfield(L, -1, "has_arg"); opts[i - 1].has_arg = lua_toboolean(L, -1); lua_pop(L, 1); lua_getfield(L, -1, "description"); opts[i - 1].description = lua_tostring(L, -1); lua_pop(L, 2); } /* Terminate the options array. */ opts[optc].optch = 0; /* Copy arguments to array of strings. */ argc = lua_objlen(L, 2) + 1; argv = apr_palloc(pool, sizeof argv[0] * argc); for (i = 0; i <= argc; i++) { lua_rawgeti(L, 2, i); argv[i] = lua_tostring(L, -1); lua_pop(L, 1); } /* Initialize arguments for parsing by apr_getopt_long(). */ status = apr_getopt_init(&os, pool, argc, argv); if (status != APR_SUCCESS) goto fail; os->interleave = 1; if (silent) os->errfn = NULL; /* Parse options, save matched options in table #1. */ lua_createtable(L, 0, optc); for (;;) { char buffer[2] = { '\0', '\0' }; i = 256; s = NULL; status = apr_getopt_long(os, opts, &i, &s); if (status == APR_EOF) break; else if (status != APR_SUCCESS) goto fail; assert(i != 256); buffer[0] = i; /* Get existing value(s) for option. */ lua_getfield(L, -1, buffer); if (s == NULL) { /* Options without arguments are counted. */ if (!lua_isnumber(L, -1)) lua_pushinteger(L, 1); else lua_pushinteger(L, lua_tointeger(L, -1) + 1); lua_setfield(L, -3, buffer); lua_pop(L, 1); /* existing value */ } else if (lua_istable(L, -1)) { /* Add argument to table of existing values. */ push_string_or_true(L, s); lua_rawseti(L, -2, lua_objlen(L, -2) + 1); lua_pop(L, 1); /* existing value */ } else if (!lua_isnil(L, -1)) { /* Combine 1st and 2nd argument in table. */ lua_newtable(L); lua_insert(L, -2); lua_rawseti(L, -2, 1); push_string_or_true(L, s); lua_rawseti(L, -2, 2); lua_setfield(L, -2, buffer); } else { /* Set 1st argument value. */ lua_pop(L, 1); /* pop nil result */ push_string_or_true(L, s); lua_setfield(L, -2, buffer); } } /* Save matched arguments in table #2. */ lua_createtable(L, argc - os->ind, 0); for (i = 1, j = os->ind; j < argc; i++, j++) { lua_pushstring(L, os->argv[j]); lua_rawseti(L, -2, i); } /* Destroy the memory pool and return the two tables. */ apr_pool_destroy(pool); return 2; fail: apr_pool_destroy(pool); return push_error_status(L, status); } lua-apr-0.23.2.dfsg/src/http.c000066400000000000000000000405521220664456000160060ustar00rootroot00000000000000/* HTTP request parsing module for the Lua/APR binding * * Author: Peter Odding * Last Change: November 6, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * This module is an experimental binding to the [apreq2] [apreq2] library * which enables [HTTP] [http] request parsing of [query strings] [qstrings], * [headers] [headers] and [multipart messages] [multipart]. Some general notes * about the functions in this module: * * - None of the extracted strings (except maybe for request bodies) are * binary safe because (AFAIK) HTTP headers are not binary safe * * - Parsed name/value pairs are converted to a Lua table using two rules: * names without a value get the value true and duplicate names result in a * table that collects all values for the given name * * - When a parse error is encountered after successfully parsing part of the * input, the results of the function are followed by an error message and * error code (see below) * * The functions in this module return three values on error: a nil followed by * an error message and an error code. This module defines the following error * codes (in addition to the [generic Lua/APR error codes](#error_handling)): * * - `'EBADARG'`: bad arguments * - `'GENERAL'`: internal apreq2 error * - `'TAINTED'`: attempted to perform unsafe action with tainted data * - `'INTERRUPT'`: parsing interrupted * - `'BADDATA'`: invalid input data * - `'BADCHAR'`: invalid character * - `'BADSEQ'`: invalid byte sequence * - `'BADATTR'`: invalid attribute * - `'BADHEADER'`: invalid header * - `'BADUTF8'`: invalid UTF-8 encoding * - `'NODATA'`: missing input data * - `'NOTOKEN'`: missing required token * - `'NOATTR'`: missing attribute * - `'NOHEADER'`: missing header * - `'NOPARSER'`: missing parser * - `'MISMATCH'`: conflicting information * - `'OVERLIMIT'`: exceeds configured maximum limit * - `'UNDERLIMIT'`: below configured minimum limit * - `'NOTEMPTY'`: setting already configured * * [apreq2]: http://httpd.apache.org/apreq/ * [http]: http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol * [qstrings]: http://en.wikipedia.org/wiki/Query_string * [headers]: http://en.wikipedia.org/wiki/List_of_HTTP_header_fields * [multipart]: http://en.wikipedia.org/wiki/MIME#Multipart_messages */ /* TODO Bind apreq_parse_urlencoded(), apreq_quote(), apreq_quote_once(), apreq_charset_divine()? */ #if LUA_APR_HAVE_APREQ #include "lua_apr.h" #include #include #include #include #include #define DEFAULT_TABLE_SIZE 10 #define MULTIPART_BRIGADE_LIMIT (1024 ^ 2) /* Internal functions. {{{1 */ typedef struct { lua_State *state; apr_pool_t *pool; apr_status_t status; } multipart_context; /* Return (partial) results (followed by error information). */ #define push_http_result(L, status, nres) \ (status == APR_SUCCESS ? nres : (nres + push_http_error(L, status, 0))) /* apreq_init() {{{2 */ static void apreq_init(lua_State *L, apr_pool_t *pool) { /* XXX No static variables here: The APREQ binding will be initialized once * for each Lua state that uses it, and this should be fine according to the * documentation for apreq_initialize(). Actually I'm not even sure we * actually need to initialize anything because we only use explicitly * initialized parsers. */ const char *key = "Lua/APR libapreq"; apr_status_t status; int initialized; lua_getfield(L, LUA_ENVIRONINDEX, key); initialized = lua_toboolean(L, -1); lua_pop(L, 1); if (!initialized) { status = apreq_initialize(pool); if (status != APR_SUCCESS) { raise_error_status(L, status); } else { lua_pushboolean(L, 1); lua_setfield(L, LUA_ENVIRONINDEX, key); } } } /* push_http_error() {{{2 */ static int push_http_error(lua_State *L, apr_status_t status, int pushnil) { char buffer[LUA_APR_MSGSIZE]; apreq_strerror(status, buffer, count(buffer)); if (pushnil) lua_pushnil(L); lua_pushstring(L, buffer); switch (status) { case APR_EBADARG: lua_pushstring(L, "EBADARG"); break; case APREQ_ERROR_GENERAL: lua_pushstring(L, "GENERAL"); break; case APREQ_ERROR_TAINTED: lua_pushstring(L, "TAINTED"); break; case APREQ_ERROR_INTERRUPT: lua_pushstring(L, "INTERRUPT"); break; case APREQ_ERROR_BADDATA: lua_pushstring(L, "BADDATA"); break; case APREQ_ERROR_BADCHAR: lua_pushstring(L, "BADCHAR"); break; case APREQ_ERROR_BADSEQ: lua_pushstring(L, "BADSEQ"); break; case APREQ_ERROR_BADATTR: lua_pushstring(L, "BADATTR"); break; case APREQ_ERROR_BADHEADER: lua_pushstring(L, "BADHEADER"); break; case APREQ_ERROR_BADUTF8: lua_pushstring(L, "BADUTF8"); break; case APREQ_ERROR_NODATA: lua_pushstring(L, "NODATA"); break; case APREQ_ERROR_NOTOKEN: lua_pushstring(L, "NOTOKEN"); break; case APREQ_ERROR_NOATTR: lua_pushstring(L, "NOATTR"); break; case APREQ_ERROR_NOHEADER: lua_pushstring(L, "NOHEADER"); break; case APREQ_ERROR_NOPARSER: lua_pushstring(L, "NOPARSER"); break; case APREQ_ERROR_MISMATCH: lua_pushstring(L, "MISMATCH"); break; case APREQ_ERROR_OVERLIMIT: lua_pushstring(L, "OVERLIMIT"); break; case APREQ_ERROR_UNDERLIMIT: lua_pushstring(L, "UNDERLIMIT"); break; case APREQ_ERROR_NOTEMPTY: lua_pushstring(L, "NOTEMPTY"); break; default: status_to_name(L, status); break; } return pushnil ? 3 : 2; } /* push_scalars() {{{2 */ static int push_scalars(void *state, const char *key, const char *value) { lua_State *L = state; /* Check whether we've seen the key before. */ lua_getfield(L, -1, key); if (lua_isnil(L, -1)) { /* 1st occurrence. */ push_string_or_true(L, value); lua_setfield(L, -3, key); } else if (lua_isstring(L, -1)) { /* 2nd occurrence. */ lua_newtable(L); /* push subtable */ lua_pushvalue(L, -1); /* push reference */ lua_setfield(L, -4, key); /* pop reference */ lua_insert(L, -2); /* move subtable before 1st value */ lua_rawseti(L, -2, 1); /* pop 1st value */ push_string_or_true(L, value); /* push 2nd value */ lua_rawseti(L, -2, 2); /* pop 2nd value */ } else { /* Later values. */ push_string_or_true(L, value); lua_rawseti(L, -2, lua_objlen(L, -2) + 1); } lua_pop(L, 1); /* pop nil or subtable */ return 1; } /* push_multipart_headers() {{{2 */ static int push_multipart_headers(void *state, const char *key, const char *value) { lua_State *L = state; push_string_or_true(L, value); lua_setfield(L, -2, key); return 1; } /* push_multipart_entry() {{{2 */ static int push_multipart_entry(multipart_context *context, const char *value) { apr_status_t status; apr_size_t len; lua_State *L = context->state; apreq_param_t *param = apreq_value_to_param(value); char *upload; lua_newtable(L); lua_pushstring(L, value); lua_rawseti(L, -2, 1); apr_table_do(push_multipart_headers, L, param->info, NULL); if (param->upload != NULL) { status = apr_brigade_pflatten(param->upload, &upload, &len, context->pool); if (status != APR_SUCCESS) { context->status = status; return 0; } lua_pushlstring(L, upload, len); lua_rawseti(L, -2, 2); } return 1; } /* push_multipart_entries() {{{2 */ static int push_multipart_entries(void *ctx, const char *key, const char *value) { multipart_context *context = ctx; lua_State *L = context->state; /* Check whether we've seen the key before. */ lua_getfield(L, -1, key); if (lua_isnil(L, -1)) { /* 1st occurrence. */ if (!push_multipart_entry(context, value)) return 0; lua_setfield(L, -3, key); } else if (lua_isstring(L, -1)) { /* 2nd occurrence. */ lua_newtable(L); /* push subtable */ lua_pushvalue(L, -1); /* push reference */ lua_setfield(L, -4, key); /* pop reference */ lua_insert(L, -2); /* move subtable before 1st value */ lua_rawseti(L, -2, 1); /* pop 1st value */ if (!push_multipart_entry(context, value)) /* push 2nd value */ return 0; lua_rawseti(L, -2, 2); /* pop 2nd value */ } else { /* Later values. */ if (!push_multipart_entry(context, value)) return 0; lua_rawseti(L, -2, lua_objlen(L, -2) + 1); } lua_pop(L, 1); /* pop nil or subtable */ return 1; } /* apr.parse_headers(request) -> headers, body {{{1 * * Parse the [headers] [headers] in a [HTTP] [http] request string according to * [RFC 822] [rfc822]. On success a table of header name/value pairs and the * request body string are returned, otherwise nil followed by an error message * is returned. * * There are some gotchas in using this function: * * - It will fail if anything comes before the headers, so be sure to strip * the status line from the request string before calling this function * * - If the request string doesn't contain an empty line to separate the * headers from the body, the last header might be silently discarded * * [rfc822]: http://tools.ietf.org/html/rfc822 */ int lua_apr_parse_headers(lua_State *L) { apr_bucket_alloc_t *allocator; apr_bucket_brigade *brigade; apr_pool_t *pool; apr_size_t bodysize; apr_status_t status, parser_status; apr_table_t *table; apreq_parser_t *parser; char *body; const char *request; size_t requestsize; pool = to_pool(L); apreq_init(L, pool); request = luaL_checklstring(L, 1, &requestsize); /* Create the parser and bucket brigade. */ allocator = apr_bucket_alloc_create(pool); parser = apreq_parser_make(pool, allocator, NULL, apreq_parse_headers, 0, NULL, NULL, NULL); brigade = apr_brigade_create(pool, allocator); /* Fill the bucket brigade with the request string. */ APR_BRIGADE_INSERT_HEAD(brigade, apr_bucket_immortal_create(request, requestsize, allocator)); APR_BRIGADE_INSERT_TAIL(brigade, apr_bucket_eos_create(allocator)); /* Run the parser. */ table = apr_table_make(pool, DEFAULT_TABLE_SIZE); parser_status = apreq_parser_run(parser, table, brigade); if (parser_status != APR_SUCCESS && apr_is_empty_table(table)) return push_http_error(L, parser_status, 1); /* Create the table with headers. */ lua_newtable(L); apr_table_do(push_scalars, L, table, NULL); /* Push the request body. */ status = apr_brigade_pflatten(brigade, &body, &bodysize, pool); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, body, bodysize); return push_http_result(L, parser_status, 2); } /* apr.parse_multipart(request, enctype [, limit [, tempdir]]) -> parts {{{1 * * Parse a [multipart/form-data] [mp_formdata] or [multipart/related] * [mp_related] HTTP request body according to [RFC 2388] [rfc2388] and the * boundary string in @enctype. On success the table with parameter name/value * pairs is returned, otherwise a nil followed by an error message is * returned. * * The optional number @limit gives the maximum in-memory bytes that the data * structure used to parse the request may use (it defaults to 1024 KB), but be * aware that because of internal copying `apr.parse_multipart()` can use more * than double this amount of memory while parsing a request. * * The optional string @tempdir is the directory used for temporary storage of * large uploads. * * [mp_formdata]: http://en.wikipedia.org/wiki/MIME#Form_Data * [mp_related]: http://en.wikipedia.org/wiki/MIME#Related * [rfc2388]: http://tools.ietf.org/html/rfc2388 */ int lua_apr_parse_multipart(lua_State *L) { apr_bucket_alloc_t *allocator; apr_bucket_brigade *brigade; apr_pool_t *pool; apr_size_t brigade_limit; apr_status_t status; apr_table_t *table; apreq_parser_t *parser; const char *request, *enctype, *tempdir; multipart_context context; size_t requestsize; pool = to_pool(L); apreq_init(L, pool); request = luaL_checklstring(L, 1, &requestsize); enctype = luaL_checkstring(L, 2); tempdir = luaL_optstring(L, 3, NULL); brigade_limit = luaL_optint(L, 4, MULTIPART_BRIGADE_LIMIT); /* Create the parser and bucket brigade. */ allocator = apr_bucket_alloc_create(pool); parser = apreq_parser_make(pool, allocator, enctype, apreq_parse_multipart, brigade_limit, tempdir, NULL, NULL); brigade = apr_brigade_create(pool, allocator); /* Fill the bucket brigade with the request string. */ APR_BRIGADE_INSERT_HEAD(brigade, apr_bucket_immortal_create(request, requestsize, allocator)); APR_BRIGADE_INSERT_TAIL(brigade, apr_bucket_eos_create(allocator)); /* Run the parser. */ table = apr_table_make(pool, DEFAULT_TABLE_SIZE); status = apreq_parser_run(parser, table, brigade); if (status != APR_SUCCESS && apr_is_empty_table(table)) return push_http_error(L, status, 1); /* Create the table with parameters. */ lua_newtable(L); context.state = L; context.pool = pool; if (!apr_table_do(push_multipart_entries, &context, table, NULL)) return push_http_error(L, context.status, 1); /* Return the parameters and error status (if any). */ return push_http_result(L, status, 1); } /* apr.parse_cookie_header(header) -> cookies {{{1 * * Parse a cookie header and store the cookies in a Lua table. On success the * table with cookie name/value pairs is returned, otherwise nil followed by an * error message and error code is returned. */ int lua_apr_parse_cookie_header(lua_State *L) { apr_status_t status; apr_pool_t *pool; apr_table_t *table; const char *header; pool = to_pool(L); header = luaL_checkstring(L, 1); table = apr_table_make(pool, DEFAULT_TABLE_SIZE); status = apreq_parse_cookie_header(pool, table, header); if (status != APR_SUCCESS && apr_is_empty_table(table)) return push_http_error(L, status, 1); lua_newtable(L); apr_table_do(push_scalars, L, table, NULL); return push_http_result(L, status, 1); } /* apr.parse_query_string(query_string) -> parameters {{{1 * * Parse a URL encoded string into a Lua table. On success the table with * parameter name/value pairs is returned, otherwise nil followed by an error * message and error code is returned. * * This function uses `&` and `;` as the set of tokens to delineate words, and * will treat a word without `=` as a name/value pair with the value true. */ int lua_apr_parse_query_string(lua_State *L) { apr_status_t status; apr_pool_t *pool; apr_table_t *table; const char *qs; pool = to_pool(L); qs = luaL_checkstring(L, 1); table = apr_table_make(pool, DEFAULT_TABLE_SIZE); status = apreq_parse_query_string(pool, table, qs); if (status != APR_SUCCESS && apr_is_empty_table(table)) return push_http_error(L, status, 1); lua_newtable(L); apr_table_do(push_scalars, L, table, NULL); return push_http_result(L, status, 1); } /* apr.header_attribute(header, name) -> value {{{1 * * Search a header string for the value of a particular named attribute. On * success the matched value is returned, otherwise nil followed by an error * message is returned. */ int lua_apr_header_attribute(lua_State *L) { apr_status_t status; const char *header, *name, *value; size_t namelen; apr_size_t valuelen; header = luaL_checkstring(L, 1); name = luaL_checklstring(L, 2, &namelen); status = apreq_header_attribute(header, name, namelen, &value, &valuelen); if (status != APR_SUCCESS) return push_http_error(L, status, 1); lua_pushlstring(L, value, valuelen); return 1; } /* apr.uri_encode(string) -> encoded {{{1 * * Encode unsafe bytes in @string using [percent-encoding] [percenc] so that * the string can be embedded in a [URI] [uri] query string. * * [percenc]: http://en.wikipedia.org/wiki/Percent-encoding */ int lua_apr_uri_encode(lua_State *L) { apr_pool_t *pool; const char *string, *encoded; size_t length; pool = to_pool(L); string = luaL_checklstring(L, 1, &length); encoded = apreq_escape(pool, string, length); lua_pushstring(L, encoded); return 1; } /* apr.uri_decode(encoded) -> string {{{1 * * Decode all [percent-encoded] [percenc] bytes in the string @encoded. */ int lua_apr_uri_decode(lua_State *L) { apr_status_t status; apr_pool_t *pool; const char *encoded; char *string; size_t enclen; apr_size_t strlen; pool = to_pool(L); encoded = luaL_checklstring(L, 1, &enclen); string = apr_palloc(pool, enclen + 1); if (string == NULL) return push_error_memory(L); memcpy(string, encoded, enclen); status = apreq_decode(string, &strlen, encoded, enclen); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, string, strlen); return 1; } #endif lua-apr-0.23.2.dfsg/src/io_dir.c000066400000000000000000000336031220664456000162730ustar00rootroot00000000000000/* Directory manipulation module for the Lua/APR binding. * * Author: Peter Odding * Last Change: June 16, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include #include #include #include /* Structure for directory objects. */ typedef struct { lua_apr_refobj header; apr_dir_t *handle; apr_pool_t *memory_pool; const char *filepath; } lua_apr_dir; /* Internal functions {{{1 */ static lua_apr_dir *checkdir(lua_State *L, int idx, int check_open) { lua_apr_dir *object; object = check_object(L, idx, &lua_apr_dir_type); if (check_open && object->handle == NULL) luaL_error(L, "attempt to use a closed directory"); return object; } /* apr.temp_dir_get() -> path {{{1 * * Find an existing directory suitable as a temporary storage location. On * success the directory file path is returned, otherwise a nil followed by an * error message is returned. */ int lua_apr_temp_dir_get(lua_State *L) { apr_pool_t* memory_pool; const char *filepath; apr_status_t status; memory_pool = to_pool(L); status = apr_temp_dir_get(&filepath, memory_pool); if (status != APR_SUCCESS) { return push_error_status(L, status); } else { lua_pushstring(L, filepath); return 1; } } /* apr.dir_make(path [, permissions]) -> status {{{1 * * Create the directory @path on the file system. On success true is returned, * otherwise a nil followed by an error message is returned. See the * documentation on @permissions for the optional second argument. */ int lua_apr_dir_make(lua_State *L) { apr_status_t status; apr_pool_t *memory_pool; const char *filepath; apr_fileperms_t permissions; memory_pool = to_pool(L); filepath = luaL_checkstring(L, 1); permissions = check_permissions(L, 2, 0); status = apr_dir_make(filepath, permissions, memory_pool); return push_status(L, status); } /* apr.dir_make_recursive(path [, permissions]) -> status {{{1 * * Create the directory @path on the file system, creating intermediate * directories as required. On success true is returned, otherwise a nil * followed by an error message is returned. See the documentation on * @permissions for the optional second argument. */ int lua_apr_dir_make_recursive(lua_State *L) { apr_status_t status; apr_pool_t *memory_pool; const char *filepath; apr_fileperms_t permissions; memory_pool = to_pool(L); filepath = luaL_checkstring(L, 1); permissions = check_permissions(L, 2, 0); status = apr_dir_make_recursive(filepath, permissions, memory_pool); return push_status(L, status); } /* apr.dir_remove(path) -> status {{{1 * * Remove the *empty* directory @path from the file system. On success true * is returned, otherwise a nil followed by an error message is returned. */ int lua_apr_dir_remove(lua_State *L) { apr_status_t status; apr_pool_t *memory_pool; const char *filepath; memory_pool = to_pool(L); filepath = luaL_checkstring(L, 1); status = apr_dir_remove(filepath, memory_pool); return push_status(L, status); } /* apr.dir_remove_recursive(path) -> status {{{1 * * Remove the directory @path *and all its contents* from the file system. * On success true is returned, otherwise a nil followed by an error message is * returned. * * Note: This function isn't part of the Apache Portable Runtime but has been * implemented on top of it by the author of the Lua/APR binding. *It also * hasn't been properly tested yet*. */ int lua_apr_dir_remove_recursive(lua_State *L) { apr_status_t status; apr_pool_t *outer_pool; /* used to store todo/done arrays and directory pathnames */ apr_pool_t *middle_pool; /* used to store directory handles (apr_dir_t structs) */ apr_pool_t *inner_pool; /* used to store pathnames of non-subdirectory entries */ apr_array_header_t *todo, *done; apr_dir_t *directory; apr_finfo_t info; char **top, *tmp; const char *filepath; int allocation_counter; directory = NULL; outer_pool = middle_pool = inner_pool = NULL; filepath = luaL_checkstring(L, 1); allocation_counter = 0; status = apr_pool_create(&outer_pool, NULL); if (APR_SUCCESS == status) status = apr_pool_create(&middle_pool, NULL); if (APR_SUCCESS == status) status = apr_pool_create(&inner_pool, NULL); if (APR_SUCCESS != status) goto cleanup; # define out_of_memory do { \ status = APR_ENOMEM; \ goto cleanup; \ } while (0) # define push_filepath(stack, filepath) do { \ const char **p = apr_array_push(stack); \ if (p != NULL) *p = filepath; else out_of_memory; \ } while (0) todo = apr_array_make(outer_pool, 0, sizeof filepath); done = apr_array_make(outer_pool, 0, sizeof filepath); if (todo == NULL || done == NULL) out_of_memory; push_filepath(todo, filepath); while ((top = apr_array_pop(todo))) { filepath = *(char**)top; apr_pool_clear(middle_pool); status = apr_dir_open(&directory, filepath, middle_pool); if (status != APR_SUCCESS) { directory = NULL; goto cleanup; } for (;;) { /* This is a compromise between having `inner_pool' grow almost unbounded * on very large directories (e.g. ~/Maildir/) and clearing it for every * non-subdirectory pathname that's allocated (very inefficient). */ if (allocation_counter % 1000 == 0) apr_pool_clear(inner_pool); /* FIXME?! apr_dir_read() uses directory->pool (middle_pool) for allocation */ status = apr_dir_read(&info, APR_FINFO_NAME|APR_FINFO_TYPE|APR_FINFO_LINK, directory); if (APR_STATUS_IS_ENOENT(status)) break; /* no more entries */ else if (status != APR_SUCCESS && status != APR_INCOMPLETE) goto cleanup; /* something went wrong */ else if (filename_symbolic(info.name)) continue; /* bogus entry */ else if (info.filetype == APR_DIR) { /* recurse into subdirectory */ status = apr_filepath_merge(&tmp, filepath, info.name, 0, outer_pool); if (status != APR_SUCCESS) goto cleanup; push_filepath(todo, tmp); } else { /* delete non-subdirectory entry */ status = apr_filepath_merge(&tmp, filepath, info.name, 0, inner_pool); allocation_counter++; if (APR_SUCCESS == status) status = apr_file_remove(tmp, inner_pool); if (APR_SUCCESS != status) goto cleanup; } } status = apr_dir_close(directory); directory = NULL; if (status != APR_SUCCESS) goto cleanup; push_filepath(done, filepath); } # undef out_of_memory # undef push_filepath while ((top = apr_array_pop(done))) { filepath = *(char**)top; if (allocation_counter++ % 100 == 0) apr_pool_clear(middle_pool); status = apr_dir_remove(filepath, middle_pool); if (status != APR_SUCCESS) goto cleanup; } cleanup: if (directory != NULL) apr_dir_close(directory); if (inner_pool != NULL) apr_pool_destroy(inner_pool); if (middle_pool != NULL) apr_pool_destroy(middle_pool); if (outer_pool != NULL) apr_pool_destroy(outer_pool); return push_status(L, status); } /* apr.dir_open(path) -> directory handle {{{1 * * Open the directory @path for reading. On success a directory object is * returned, otherwise a nil followed by an error message is returned. */ int lua_apr_dir_open(lua_State *L) { apr_status_t status; const char *filepath; lua_apr_dir *directory; filepath = luaL_checkstring(L, 1); directory = new_object(L, &lua_apr_dir_type); if (directory == NULL) return push_error_memory(L); /* Create a memory pool for the lifetime of the directory object. */ status = apr_pool_create(&directory->memory_pool, NULL); if (APR_SUCCESS != status) { directory->memory_pool = NULL; return push_error_status(L, status); } /* Try to open a handle to the directory. */ status = apr_dir_open(&directory->handle, filepath, directory->memory_pool); if (APR_SUCCESS != status) { directory->handle = NULL; return push_error_status(L, status); } /* Initialize and return the directory object. */ directory->filepath = apr_pstrdup(directory->memory_pool, filepath); return 1; } /* directory:read([property, ...]) -> value, ... {{{1 * * Return the requested properties for the next directory entry. On success the * requested properties are returned, otherwise a nil followed by an error * message is returned. This function implements the same interface as * `apr.stat()`. */ static int dir_read(lua_State *L) { apr_status_t status; lua_apr_dir *directory; lua_apr_stat_context *context, backup_ctx; int raise_errors; directory = checkdir(L, 1, 1); if (lua_isuserdata(L, lua_upvalueindex(1))) { /* Iterator for directory:entries() */ context = lua_touserdata(L, lua_upvalueindex(1)); raise_errors = 1; } else { /* Standalone call to directory:read() */ backup_ctx.firstarg = 2; backup_ctx.lastarg = lua_gettop(L); check_stat_request(L, &backup_ctx); context = &backup_ctx; raise_errors = 0; } for (;;) { status = apr_dir_read(&context->info, context->wanted, directory->handle); if (APR_SUCCESS == status || APR_STATUS_IS_INCOMPLETE(status)) { if (!(context->info.valid & APR_FINFO_NAME \ && filename_symbolic(context->info.name))) return push_stat_results(L, context, directory->filepath); } else if (APR_STATUS_IS_ENOENT(status)) { return 0; } else if (raise_errors) { return raise_error_status(L, status); } else { return push_error_status(L, status); } } } /* directory:rewind() -> status {{{1 * * Rewind the directory handle to start from the first entry. On success true * is returned, otherwise a nil followed by an error message is returned. */ static int dir_rewind(lua_State *L) { lua_apr_dir *directory; apr_status_t status; directory = checkdir(L, 1, 1); status = apr_dir_rewind(directory->handle); return push_status(L, status); } /* directory:entries([property, ...]) -> iterator, directory handle {{{1 * * Return a function that iterates over the (remaining) directory entries and * returns the requested properties for each entry. If you don't request any * properties, a table with the available properties will be returned for each * directory entry: * * > directory = apr.dir_open 'examples' * > for info in directory:entries() do print(info) end * { * type = 'file', name = 'webserver.lua', * user = 'peter', group = 'peter', protection = 'rw-r--r--', * size = 2789, csize = 4096, inode = 12455648, dev = 64514, nlink = 1, * path = '/home/peter/Development/Lua/APR/examples/webserver.lua', * mtime = 1293753884.3382, atime = 1293994993.3855, ctime = 1293753884.3382, * } * { * type = 'file', name = 'download.lua', * user = 'peter' group = 'peter', protection = 'rw-r--r--', * size = 2580, csize = 4096, inode = 12455598, dev = 64514, nlink = 1, * path = '/home/peter/Development/Lua/APR/examples/download.lua', * mtime = 1293753884.3382, atime = 1293994993.3855, ctime = 1293753884.3382, * } * * This function implements the same interface as `apr.stat()` with one * exception: If you pass property names to `directory:entries()` that are not * available they will be returned as false instead of nil because of a * technical limitation in the [Lua iterator protocol] [iterators]: * * > "On each iteration, the iterator function is called to * > produce a new value, stopping when this new value is nil." * * [iterators]: http://www.lua.org/manual/5.1/manual.html#2.4.5 */ static int dir_entries(lua_State *L) { lua_apr_stat_context *context; /* Check for a valid, open directory. */ checkdir(L, 1, 1); /* Copy the stat() arguments to a userdatum. */ context = lua_newuserdata(L, sizeof(*context)); context->firstarg = 2; /* after directory handle */ context->lastarg = lua_gettop(L) - 1; /* before stat context */ check_stat_request(L, context); /* Return the iterator function and directory object. */ lua_pushcclosure(L, dir_read, 1); lua_pushvalue(L, 1); return 2; } /* directory:close() -> status {{{1 * * Close the directory handle. On success true is returned, otherwise a nil * followed by an error message is returned. */ static int dir_close(lua_State *L) { lua_apr_dir *directory; apr_status_t status; directory = checkdir(L, 1, 1); status = apr_dir_close(directory->handle); if (status == APR_SUCCESS) directory->handle = NULL; return push_status(L, status); } /* directory:__tostring() {{{1 */ static int dir_tostring(lua_State *L) { lua_apr_dir *directory; directory = checkdir(L, 1, 0); if (directory->handle != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_dir_type.friendlyname, directory->handle); else lua_pushfstring(L, "%s (closed)", lua_apr_dir_type.friendlyname); return 1; } /* directory:__gc() {{{1 */ static int dir_gc(lua_State *L) { lua_apr_dir *directory = checkdir(L, 1, 0); if (object_collectable((lua_apr_refobj*)directory)) { if (directory->handle != NULL) { apr_dir_close(directory->handle); directory->handle = NULL; } if (directory->memory_pool != NULL) { apr_pool_destroy(directory->memory_pool); directory->memory_pool = NULL; } } release_object((lua_apr_refobj*)directory); return 0; } /* }}}1 */ static luaL_Reg dir_methods[] = { { "close", dir_close }, { "entries", dir_entries }, { "read", dir_read }, { "rewind", dir_rewind }, { NULL, NULL } }; static luaL_Reg dir_metamethods[] = { { "__tostring", dir_tostring }, { "__eq", objects_equal }, { "__gc", dir_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_dir_type = { "lua_apr_dir*", /* metatable name in registry */ "directory", /* friendly object name */ sizeof(lua_apr_dir), /* structure size */ dir_methods, /* methods table */ dir_metamethods /* metamethods table */ }; /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/io_file.c000066400000000000000000000642231220664456000164360ustar00rootroot00000000000000/* File I/O handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 6, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include #include #include #include #include #include /* TODO Bind apr_file_pipe_create_ex(), apr_file_sync(), apr_file_datasync() */ /* Internal functions. {{{1 */ /* file_alloc() {{{2 */ lua_apr_file *file_alloc(lua_State *L, const char *path, lua_apr_pool *refpool) { lua_apr_file *file; file = new_object(L, &lua_apr_file_type); if (refpool == NULL) refpool = refpool_alloc(L); else refpool_incref(refpool); file->pool = refpool; if (path != NULL) path = apr_pstrdup(file->pool->ptr, path); file->path = path; return file; } /* init_file_buffers() {{{2 */ void init_file_buffers(lua_State *L, lua_apr_file *file, int text_mode) { init_buffers(L, &file->input, &file->output, file->handle, text_mode, (lua_apr_buf_rf) apr_file_read, (lua_apr_buf_wf) apr_file_write, (lua_apr_buf_ff) apr_file_flush); } /* file_check() {{{2 */ lua_apr_file *file_check(lua_State *L, int i, int open) { lua_apr_file *file = check_object(L, i, &lua_apr_file_type); if (open && file->handle == NULL) luaL_error(L, "attempt to use a closed file"); return file; } /* file_close_impl() {{{2 */ apr_status_t file_close_impl(lua_State *L, lua_apr_file *file) { apr_status_t status = APR_SUCCESS; if (file->handle != NULL) { status = flush_buffer(L, &file->output, 1); if (status == APR_SUCCESS) status = apr_file_close(file->handle); else apr_file_close(file->handle); file->handle = NULL; refpool_decref(file->pool); free_buffer(L, &file->input.buffer); free_buffer(L, &file->output.buffer); } return status; } /* push_file_error() {{{2 */ static int push_file_error(lua_State *L, lua_apr_file *file, apr_status_t status) { char message[LUA_APR_MSGSIZE]; apr_strerror(status, message, count(message)); lua_pushnil(L); if (file->path != NULL) lua_pushfstring(L, "%s: %s", file->path, message); else lua_pushstring(L, message); status_to_name(L, status); return 3; } /* push_file_status() {{{2 */ static int push_file_status(lua_State *L, lua_apr_file *file, apr_status_t status) { if (status == APR_SUCCESS) { lua_pushboolean(L, 1); return 1; } else { return push_file_error(L, file, status); } } /* parse_mode_str() {{{2 */ static apr_int32_t parse_mode_str(const char *mode) { apr_int32_t flags = 0; if (*mode == 'r') { flags |= APR_FOPEN_READ, mode++; if (*mode == '+') flags |= APR_FOPEN_WRITE, mode++; if (*mode == 'b') flags |= APR_FOPEN_BINARY, mode++; if (*mode == '+') flags |= APR_FOPEN_WRITE; } else if (*mode == 'w') { flags |= APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE, mode++; if (*mode == '+') flags |= APR_FOPEN_READ, mode++; if (*mode == 'b') flags |= APR_FOPEN_BINARY, mode++; if (*mode == '+') flags |= APR_FOPEN_READ; } else if (*mode == 'a') { flags |= APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_APPEND, mode++; if (*mode == '+') flags |= APR_FOPEN_READ, mode++; if (*mode == 'b') flags |= APR_FOPEN_BINARY, mode++; if (*mode == '+') flags |= APR_FOPEN_READ; } /* Default to read mode just like Lua. */ if (!(flags & APR_FOPEN_WRITE)) flags |= APR_FOPEN_READ; return flags; } #if APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 4) /* apr.file_link(source, target) -> status {{{1 * * Create a [hard link] [hard_link] to the specified file. On success true is * returned, otherwise a nil followed by an error message is returned. Both * files must reside on the same device. * * Please note that this function will only be available when the Lua/APR * binding is compiled against APR 1.4 or newer because the [apr\_file\_link()] * [apr_file_link] function wasn't available in earlier releases. * * [hard_link]: http://en.wikipedia.org/wiki/Hard_link * [apr_file_link]: http://apr.apache.org/docs/apr/trunk/group__apr__file__io.html#ga7911275c0e97edc064b8167be658f9e */ int lua_apr_file_link(lua_State *L) { const char *source, *target; apr_status_t status; source = luaL_checkstring(L, 1); target = luaL_checkstring(L, 2); status = apr_file_link(source, target); return push_status(L, status); } #endif /* apr.file_copy(source, target [, permissions]) -> status {{{1 * * Copy the file @source to @target. On success true is returned, otherwise a * nil followed by an error message is returned. The @permissions argument is * documented elsewhere. The new file does not need to exist, it will be * created if required. If the new file already exists, its contents will be * overwritten. */ int lua_apr_file_copy(lua_State *L) { const char *source, *target; apr_fileperms_t permissions; apr_status_t status; source = luaL_checkstring(L, 1); target = luaL_checkstring(L, 2); permissions = check_permissions(L, 3, 1); status = apr_file_copy(source, target, permissions, to_pool(L)); return push_status(L, status); } /* apr.file_append(source, target [, permissions]) -> status {{{1 * * Append the file @source to @target. On success true is returned, otherwise a * nil followed by an error message is returned. The @permissions argument is * documented elsewhere. The new file does not need to exist, it will be * created if required. */ int lua_apr_file_append(lua_State *L) { const char *source, *target; apr_fileperms_t permissions; apr_status_t status; source = luaL_checkstring(L, 1); target = luaL_checkstring(L, 2); permissions = check_permissions(L, 3, 1); status = apr_file_append(source, target, permissions, to_pool(L)); return push_status(L, status); } /* apr.file_rename(source, target) -> status {{{1 * * Rename the file @source to @target. On success true is returned, otherwise a * nil followed by an error message is returned. If a file exists at the new * location, then it will be overwritten. Moving files or directories across * devices may not be possible. */ int lua_apr_file_rename(lua_State *L) { const char *source, *target; apr_status_t status; source = luaL_checkstring(L, 1); target = luaL_checkstring(L, 2); status = apr_file_rename(source, target, to_pool(L)); return push_status(L, status); } /* apr.file_remove(path) -> status {{{1 * * Delete the file pointed to by @path. On success true is returned, otherwise * a nil followed by an error message is returned. If the file is open, it * won't be removed until all instances of the file are closed. */ int lua_apr_file_remove(lua_State *L) { apr_status_t status; const char *path; path = luaL_checkstring(L, 1); status = apr_file_remove(path, to_pool(L)); return push_status(L, status); } /* apr.file_mtime_set(path, mtime) -> status {{{1 * * Set the last modified time of the file pointed to by @path to @mtime. On * success true is returned, otherwise a nil followed by an error message is * returned. */ int lua_apr_file_mtime_set(lua_State *L) { apr_status_t status; const char *path; apr_time_t mtime; path = luaL_checkstring(L, 1); mtime = time_check(L, 2); status = apr_file_mtime_set(path, mtime, to_pool(L)); return push_status(L, status); } /* apr.file_attrs_set(path, attributes) -> status {{{1 * * Set the attributes of the file pointed to by @path. On success true is * returned, otherwise a nil followed by an error message is returned. * * The table @attributes should consist of string keys and boolean values. The * supported attributes are `readonly`, `hidden` and `executable`. * * This function should be used in preference to explicit manipulation of the * file permissions, because the operations to provide these attributes are * platform specific and may involve more than simply setting permission bits. */ int lua_apr_file_attrs_set(lua_State *L) { apr_fileattrs_t attributes, valid; const char *path, *key; apr_status_t status; path = luaL_checkstring(L, 1); luaL_checktype(L, 2, LUA_TTABLE); attributes = valid = 0; lua_pushnil(L); while (lua_next(L, 2)) { key = lua_tostring(L, -2); if (strcmp(key, "readonly") == 0) { valid |= APR_FILE_ATTR_READONLY; if (lua_toboolean(L, -1)) attributes |= APR_FILE_ATTR_READONLY; } else if (strcmp(key, "hidden") == 0) { valid |= APR_FILE_ATTR_HIDDEN; if (lua_toboolean(L, -1)) attributes |= APR_FILE_ATTR_HIDDEN; } else if (strcmp(key, "executable") == 0) { valid |= APR_FILE_ATTR_EXECUTABLE; if (lua_toboolean(L, -1)) attributes |= APR_FILE_ATTR_EXECUTABLE; } else { luaL_argerror(L, 2, lua_pushfstring(L, "invalid key " LUA_QS, key)); } lua_pop(L, 1); } status = apr_file_attrs_set(path, attributes, valid, to_pool(L)); return push_status(L, status); } /* apr.file_perms_set(path, permissions) -> status {{{1 * * Set the permissions of the file specified by @path. On success true is * returned, otherwise a nil followed by an error message is returned. * * Warning: Some platforms may not be able to apply all of the available * permission bits, in this case a third value `'INCOMPLETE'` is returned (see * error handling). */ int lua_apr_file_perms_set(lua_State *L) { const char *path; apr_status_t status; apr_fileperms_t perms; path = luaL_checkstring(L, 1); perms = check_permissions(L, 2, 0); status = apr_file_perms_set(path, perms); return push_status(L, status); } /* apr.stat(path [, property, ...]) -> value, ... {{{1 * * Get the status of the file pointed to by @path. On success, if no properties * are given a table of property name/value pairs is returned, otherwise the * named properties are returned in the same order as the arguments. On failure * a nil followed by an error message is returned. * * The following fields are supported: * * - `name` is a string containing the name of the file in proper case * - `path` is a string containing the absolute pathname of the file * - `type` is one of the strings `'directory'`, `'file'`, `'link'`, `'pipe'`, * `'socket'`, `'block device'`, `'character device'` or `'unknown'` * - `user` is a string containing the name of user that owns the file * - `group` is a string containing the name of the group that owns the file * - `size` is a number containing the size of the file in bytes * - `csize` is a number containing the storage size consumed by the file * - `ctime` is the time the file was created, or the inode was last changed * - `atime` is the time the file was last accessed * - `mtime` is the time the file was last modified * - `nlink` is the number of hard links to the file * - `inode` is a unique number within the file system on which the file * resides * - `dev` is a number identifying the device on which the file is stored * - `protection` is a 9 character string with the file system @permissions * - `link` *is a special flag that does not return a field*, instead it is * used to signal that symbolic links should not be followed, i.e. the * status of the link itself should be returned * * Here are some examples: * * > -- Here's an example of a table with all properties: * > = apr.stat('lua-5.1.4.tar.gz') * { * name = 'lua-5.1.4.tar.gz', * path = 'lua-5.1.4.tar.gz', * type = 'file', * user = 'peter', * group = 'peter', * size = 216679, * csize = 217088, * ctime = 1284159662.7264, * atime = 1287954158.6019, * mtime = 1279317348.194, * nlink = 1, * inode = 1838576, * dev = 64514, * protection = 'rw-r--r--', * } * > -- To check whether a directory exists: * > function isdir(p) return apr.stat(p, 'type') == 'directory' end * > = isdir('.') * true * > -- To get a file's size in bytes: * > function filesize(p) return apr.stat(p, 'size') end * > = filesize('lua-5.1.4.tar.gz') * 216679 */ int lua_apr_stat(lua_State *L) { const char *path, *name, *dir; apr_pool_t *memory_pool; lua_apr_stat_context context = { 0 }; apr_status_t status; memory_pool = to_pool(L); path = luaL_checkstring(L, 1); name = apr_filepath_name_get(path); dir = apr_pstrndup(memory_pool, path, name - path); context.firstarg = 2; context.lastarg = lua_gettop(L); check_stat_request(L, &context); status = apr_stat(&context.info, path, context.wanted, memory_pool); if (status != APR_SUCCESS && !APR_STATUS_IS_INCOMPLETE(status)) return push_error_status(L, status); /* XXX apr_stat() doesn't fill in finfo.name (tested on Linux) */ if (!(context.info.valid & APR_FINFO_NAME)) { context.info.valid |= APR_FINFO_NAME; context.info.name = name; } return push_stat_results(L, &context, dir); } /* apr.file_open(path [, mode [, permissions]]) -> file {{{1 * * This function imitates Lua's `io.open()` function with one exception: On * UNIX you can pass a file descriptor (number) instead of a path string (see * also `file:fd_get()`). Now follows the documentation for `io.open()`: * * This function opens a file, in the mode specified in the string @mode. It * returns a new file handle, or, in case of errors, nil plus an error * message. The @mode string can be any of the following: * * - `'r'`: read mode (the default) * - `'w'`: write mode * - `'a'`: append mode * - `'r+'`: update mode, all previous data is preserved * - `'w+'`: update mode, all previous data is erased * - `'a+'`: append update mode, previous data is preserved, writing is only * allowed at the end of file * * The @mode string may also have a `b` at the end, which is needed in some * systems to open the file in binary mode. This string is exactly what is used * in the standard C function [fopen()] [fopen]. The @permissions argument is * documented elsewhere. * * [fopen]: http://linux.die.net/man/3/fopen */ int lua_apr_file_open(lua_State *L) { apr_status_t status; lua_apr_file *file; apr_int32_t flags; const char *path; apr_fileperms_t perm; # if defined(WIN32) || defined(OS2) || defined(NETWARE) /* On Windows apr_os_file_t isn't an integer: it's a HANDLE. */ if (0) ; # else /* On UNIX like systems apr_os_file_t is an integer. */ if (lua_isnumber(L, 1)) { apr_os_file_t fd = (apr_os_file_t) lua_tonumber(L, 1); flags = parse_mode_str(luaL_optstring(L, 2, "r")); file = file_alloc(L, NULL, NULL); status = apr_os_file_put(&file->handle, &fd, flags, file->pool->ptr); } # endif else { path = luaL_checkstring(L, 1); perm = check_permissions(L, 3, 0); flags = parse_mode_str(luaL_optstring(L, 2, "r")); file = file_alloc(L, path, NULL); status = apr_file_open(&file->handle, path, flags, perm, file->pool->ptr); } if (status != APR_SUCCESS) return push_file_error(L, file, status); init_file_buffers(L, file, !(flags & APR_FOPEN_BINARY)); return 1; } /* file:stat([field, ...]) -> value, ... {{{1 * * This method works like `apr.stat()` except that it uses a file handle * instead of a filepath to access the file. */ static int file_stat(lua_State *L) { lua_apr_stat_context context = { 0 }; lua_apr_file *file; apr_status_t status; file = file_check(L, 1, 1); context.firstarg = 2; context.lastarg = lua_gettop(L); check_stat_request(L, &context); status = apr_file_info_get(&context.info, context.wanted, file->handle); if (status != APR_SUCCESS && !APR_STATUS_IS_INCOMPLETE(status)) return push_file_error(L, file, status); return push_stat_results(L, &context, NULL); } /* file:lines() -> iterator {{{1 * * This function implements the interface of Lua's `file:lines()` function. */ static int file_lines(lua_State *L) { lua_apr_file *file = file_check(L, 1, 1); return read_lines(L, &file->input); } /* file:truncate([offset]) -> status {{{1 * * Truncate the file's length to the specified @offset (defaults to 0). On * success true is returned, otherwise a nil followed by an error message is * returned. Note that the read/write file offset is repositioned to the * selected offset. */ static int file_truncate(lua_State *L) { apr_status_t status; lua_apr_file *file; apr_off_t offset; file = file_check(L, 1, 1); offset = luaL_optlong(L, 2, 0); status = apr_file_trunc(file->handle, offset); return push_status(L, status); } /* file:read([format, ...]) -> mixed value, ... {{{1 * * This function implements the interface of Lua's `file:read()` function. */ static int file_read(lua_State *L) { lua_apr_file *file = file_check(L, 1, 1); return read_buffer(L, &file->input); } /* file:write(value [, ...]) -> status {{{1 * * This function implements the interface of Lua's `file:write()` function. */ static int file_write(lua_State *L) { lua_apr_file *file = file_check(L, 1, 1); return write_buffer(L, &file->output); } /* file:seek([whence [, offset]]) -> offset {{{1 * * This function implements the interface of Lua's `file:seek()` function. */ static int file_seek(lua_State *L) { /* TODO Seek the write buffer as well! */ const char *const modenames[] = { "set", "cur", "end", NULL }; const apr_seek_where_t modes[] = { APR_SET, APR_CUR, APR_END }; apr_status_t status; lua_apr_file *file; lua_apr_buffer *B; apr_off_t offset; int mode; file = file_check(L, 1, 1); B = &file->input.buffer; mode = modes[luaL_checkoption(L, 2, "cur", modenames)]; offset = luaL_optlong(L, 3, 0); /* XXX Flush write buffer before changing offset! */ if (!(mode == APR_CUR && offset == 0)) { status = flush_buffer(L, &file->output, 1); if (status != APR_SUCCESS) return push_file_error(L, file, status); } /* Make relative offsets absolute, adjust for buffered input. */ if (mode == APR_CUR && B->index < B->limit) { apr_off_t temp = 0; status = apr_file_seek(file->handle, APR_CUR, &temp); if (status != APR_SUCCESS) return push_file_error(L, file, status); mode = APR_SET, offset = temp - (B->limit - B->index); } /* Perform the requested seek() operation. */ status = apr_file_seek(file->handle, mode, &offset); if (status != APR_SUCCESS) return push_file_error(L, file, status); /* Invalidate all buffered input (very inefficient but foolproof: parts of * the buffer may have been modified by the binary to text translation). * XXX The write buffer has already been reset by flush_buffer() above. * FIXME Don't invalidate the buffered input unnecessarily?! */ file->input.buffer.index = 0; file->input.buffer.limit = 0; /* FIXME Bound to lose precision when APR_FOPEN_LARGEFILE is in effect? */ lua_pushnumber(L, (lua_Number) offset); return 1; } /* file:flush() -> status {{{1 * * Saves any written data to @file. On success true is returned, otherwise a * nil followed by an error message is returned. */ static int file_flush(lua_State *L) { lua_apr_file *file = file_check(L, 1, 1); apr_status_t status = flush_buffer(L, &file->output, 0); return push_file_status(L, file, status); } /* file:lock(type [, nonblocking ]) -> status {{{1 * * Establish a lock on the open file @file. On success true is returned, * otherwise a nil followed by an error message is returned. The @type must be * one of: * * - `'shared'`: Shared lock. More than one process or thread can hold a * shared lock at any given time. Essentially, this is a "read lock", * preventing writers from establishing an exclusive lock * - `'exclusive'`: Exclusive lock. Only one process may hold an exclusive * lock at any given time. This is analogous to a "write lock" * * If @nonblocking is true the call will not block while acquiring the file * lock. * * The lock may be advisory or mandatory, at the discretion of the platform. * The lock applies to the file as a whole, rather than a specific range. Locks * are established on a per-thread/process basis; a second lock by the same * thread will not block. */ static int file_lock(lua_State *L) { const char *options[] = { "shared", "exclusive", NULL }; const int flags[] = { APR_FLOCK_SHARED, APR_FLOCK_EXCLUSIVE }; apr_status_t status; lua_apr_file *file; int type; file = file_check(L, 1, 1); type = flags[luaL_checkoption(L, 2, NULL, options)]; if (!lua_isnoneornil(L, 3)) { luaL_checktype(L, 3, LUA_TSTRING); if (strcmp(lua_tostring(L, 3), "non-blocking") != 0) luaL_argerror(L, 3, "invalid option"); type |= APR_FLOCK_NONBLOCK; } status = apr_file_lock(file->handle, type); return push_file_status(L, file, status); } /* file:unlock() -> status {{{1 * * Remove any outstanding locks on the file. On success true is returned, * otherwise a nil followed by an error message is returned. */ static int file_unlock(lua_State *L) { apr_status_t status; lua_apr_file *file; file = file_check(L, 1, 1); status = apr_file_unlock(file->handle); return push_file_status(L, file, status); } /* pipe:timeout_get() -> timeout {{{1 * * Get the timeout value or blocking state of @pipe. On success the timeout * value is returned, otherwise a nil followed by an error message is returned. * * The @timeout true means wait forever, false means don't wait at all and a * number is the microseconds to wait. */ static int pipe_timeout_get(lua_State *L) { lua_apr_file *pipe; apr_status_t status; apr_interval_time_t timeout; pipe = file_check(L, 1, 1); status = apr_file_pipe_timeout_get(pipe->handle, &timeout); if (status != APR_SUCCESS) return push_file_error(L, pipe, status); else if (timeout <= 0) lua_pushboolean(L, timeout != 0); else lua_pushinteger(L, (lua_Integer) timeout); return 1; } /* pipe:timeout_set(timeout) -> status {{{1 * * Set the timeout value or blocking state of @pipe. On success true is * returned, otherwise a nil followed by an error message is returned. * * The @timeout true means wait forever, false means don't wait at all and a * number is the microseconds to wait. For example: * * -- Configure read end of pipe to block for a maximum of 5 seconds. * pipe:timeout_set(1000000 * 5) * for line in pipe:lines() do * print(line) * end */ static int pipe_timeout_set(lua_State *L) { lua_apr_file *pipe; apr_status_t status; apr_interval_time_t timeout; pipe = file_check(L, 1, 1); if (lua_isnumber(L, 2)) timeout = luaL_checkinteger(L, 2); else timeout = lua_toboolean(L, 2) ? -1 : 0; status = apr_file_pipe_timeout_set(pipe->handle, timeout); return push_file_status(L, pipe, status); } #if !defined(WIN32) && !defined(OS2) && !defined(NETWARE) /* file:fd_get() -> fd {{{1 * * Get the underlying [file descriptor] [fildes] for this file. On success a * number is returned, otherwise a nil followed by an error message is * returned. * * To convert a file descriptor into a Lua/APR file object you can pass the * file descriptor (number) to `apr.file_open()` instead of the pathname. * * Note that this function is only available on platforms where file * descriptors are numbers (this includes UNIX and excludes Windows). */ static int file_fd_get(lua_State *L) { apr_status_t status; lua_apr_file *file; apr_os_file_t fd; file = file_check(L, 1, 1); status = apr_os_file_get(&fd, file->handle); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushinteger(L, fd); return 1; } #endif /* file:inherit_set() -> status {{{1 * * Set a file to be inherited by child processes. By default, file descriptors * will not be inherited by child processes created by `apr.proc_create()`. * * At the time of writing this [seems to only apply to UNIX] [inherit] where * APR will close all open file handles after performing a [fork()] [fork] * unless you explicitly set your files to be inheritable. * * [inherit]: http://marc.info/?l=apache-httpd-dev&m=104361635329125&w=2 */ static int file_inherit_set(lua_State *L) { apr_status_t status; lua_apr_file *file; file = file_check(L, 1, 1); status = apr_file_inherit_set(file->handle); return push_file_status(L, file, status); } /* file:inherit_unset() -> status {{{1 * * Unset a file from being inherited by child processes. */ static int file_inherit_unset(lua_State *L) { apr_status_t status; lua_apr_file *file; file = file_check(L, 1, 1); status = apr_file_inherit_unset(file->handle); return push_file_status(L, file, status); } /* file:close() -> status {{{1 * * Close @file. On success true is returned, otherwise a nil followed by an * error message is returned. */ static int file_close(lua_State *L) { lua_apr_file *file; apr_status_t status; file = file_check(L, 1, 1); status = file_close_impl(L, file); return push_file_status(L, file, status); } /* file:__tostring() {{{1 */ static int file_tostring(lua_State *L) { lua_apr_file *file; file = file_check(L, 1, 0); if (file->handle != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_file_type.friendlyname, file->handle); else lua_pushfstring(L, "%s (closed)", lua_apr_file_type.friendlyname); return 1; } /* file:__gc() {{{1 */ static int file_gc(lua_State *L) { lua_apr_file *file = file_check(L, 1, 0); if (object_collectable((lua_apr_refobj*)file)) file_close_impl(L, file); release_object((lua_apr_refobj*)file); return 0; } /* }}}1 */ static luaL_Reg file_methods[] = { { "close", file_close }, { "flush", file_flush }, { "lock", file_lock }, { "lines", file_lines }, { "truncate", file_truncate }, { "read", file_read }, { "seek", file_seek }, { "stat", file_stat }, { "unlock", file_unlock }, { "write", file_write }, { "timeout_get", pipe_timeout_get }, { "timeout_set", pipe_timeout_set }, # if !defined(WIN32) && !defined(OS2) && !defined(NETWARE) { "fd_get", file_fd_get }, # endif { "inherit_set", file_inherit_set }, { "inherit_unset", file_inherit_unset }, { NULL, NULL } }; static luaL_Reg file_metamethods[] = { { "__tostring", file_tostring }, { "__eq", objects_equal }, { "__gc", file_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_file_type = { "lua_apr_file*", /* metatable name in registry */ "file", /* friendly object name */ sizeof(lua_apr_file), /* structure size */ file_methods, /* methods table */ file_metamethods /* metamethods table */ }; /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/io_net.c000066400000000000000000000564011220664456000163040ustar00rootroot00000000000000/* Network I/O handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 7, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * To get started with network programming using the Lua/APR binding, have a * look at any of the following examples: * * - [HTTP client](#example_http_client) * - [Single threaded webserver](#example_single_threaded_webserver) * - [Multi threaded webserver](#example_multi_threaded_webserver) * - [Asynchronous webserver](#example_asynchronous_webserver) */ #include "lua_apr.h" #include #include /* Internal functions {{{1 */ /* family_check(L, i) -- check for address family on Lua stack {{{2 */ #if APR_HAVE_IPV6 const char *family_options[] = { "inet", "inet6", "unspec", NULL }; const int family_values[] = { APR_INET, APR_INET6, APR_UNSPEC }; #else const char *family_options[] = { "inet", "unspec", NULL }; const int family_values[] = { APR_INET, APR_UNSPEC }; #endif #define family_check(L, i) \ family_values[luaL_checkoption(L, i, "inet", family_options)] /* socket_alloc(L) -- allocate and initialize socket object {{{2 */ static apr_status_t socket_alloc(lua_State *L, lua_apr_socket **p) { lua_apr_socket *object; apr_status_t status; object = new_object(L, &lua_apr_socket_type); if (object == NULL) raise_error_memory(L); status = apr_pool_create(&object->pool, NULL); *p = object; return status; } /* socket_init(L, object) -- initialize socket buffers {{{2 */ static void socket_init(lua_State *L, lua_apr_socket *object) { init_buffers(L, &object->input, &object->output, object->handle, 0, (lua_apr_buf_rf) apr_socket_recv, (lua_apr_buf_wf) apr_socket_send, NULL); } /* socket_check(L, i, open) -- get socket object from Lua stack {{{2 */ static lua_apr_socket* socket_check(lua_State *L, int i, int open) { lua_apr_socket *object = check_object(L, i, &lua_apr_socket_type); if (open && object->handle == NULL) luaL_error(L, "attempt to use a closed socket"); return object; } /* option_check(L, i) -- check for socket option on Lua stack {{{2 */ static apr_int32_t option_check(lua_State *L, int i) { const char *options[] = { "debug", "keep-alive", "linger", "non-block", "reuse-addr", "sndbuf", "rcvbuf", "disconnected", NULL }; const apr_int32_t values[] = { APR_SO_DEBUG, APR_SO_KEEPALIVE, APR_SO_LINGER, APR_SO_NONBLOCK, APR_SO_REUSEADDR, APR_SO_SNDBUF, APR_SO_RCVBUF, APR_SO_DISCONNECTED }; return values[luaL_checkoption(L, i, NULL, options)]; } /* socket_close_impl(L, socket) -- destroy socket object {{{2 */ static apr_status_t socket_close_impl(lua_State *L, lua_apr_socket *socket) { apr_status_t status = APR_SUCCESS; if (socket->handle != NULL) { status = apr_socket_close(socket->handle); socket->handle = NULL; } if (socket->pool != NULL) { apr_pool_destroy(socket->pool); socket->pool = NULL; } return status; } /* apr.socket_create([protocol [, family]]) -> socket {{{1 * * Create a network socket. On success the new socket object is returned, * otherwise a nil followed by an error message is returned. Valid values for * the @protocol argument are: * * - `'tcp'` to create a [TCP] [tcp] socket (this is the default) * - `'udp'` to create a [UDP] [udp] socket * * These are the valid values for the @family argument: * * - `'inet'` to create a socket using the [IPv4] [ipv4] address family (this * is the default) * - `'inet6'` to create a socket using the [IPv6] [ipv6] address family * - `'unspec'` to pick the system default type * * Note that `'inet6'` is only supported when `apr.socket_supports_ipv6` is * true. * * [tcp]: http://en.wikipedia.org/wiki/Transmission_Control_Protocol * [udp]: http://en.wikipedia.org/wiki/User_Datagram_Protocol * [ipv4]: http://en.wikipedia.org/wiki/IPv4 * [ipv6]: http://en.wikipedia.org/wiki/IPv6 */ int lua_apr_socket_create(lua_State *L) { /* Socket types */ const char *proto_options[] = { "tcp", "udp", NULL }; const int proto_values[] = { APR_PROTO_TCP, APR_PROTO_UDP }; lua_apr_socket *object; apr_status_t status; int family, type, protocol; protocol = proto_values[luaL_checkoption(L, 1, "tcp", proto_options)]; family = family_check(L, 2); type = protocol == APR_PROTO_TCP ? SOCK_STREAM : SOCK_DGRAM; /* Create and initialize the socket and its associated memory pool. */ status = socket_alloc(L, &object); object->family = family; object->protocol = protocol; if (status == APR_SUCCESS) status = apr_socket_create(&object->handle, family, type, protocol, object->pool); if (status != APR_SUCCESS) return push_error_status(L, status); socket_init(L, object); return 1; } /* apr.hostname_get() -> name {{{1 * * Get the name of the current machine. On success the host name string is * returned, otherwise a nil followed by an error message is returned. */ int lua_apr_hostname_get(lua_State *L) { char hostname[APRMAXHOSTLEN + 1]; apr_status_t status; apr_pool_t *pool; pool = to_pool(L); status = apr_gethostname(hostname, count(hostname), pool); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, hostname); return 1; } /* apr.host_to_addr(hostname [, family]) -> ip_address, ... {{{1 * * Resolve a host name to one or more IP addresses. On success one or more IP * addresses are returned as strings, otherwise a nil followed by an error * message is returned. The optional @family argument is documented under * `apr.socket_create()`. * * > = apr.host_to_addr 'www.lua.org' * '89.238.129.35' * > = apr.host_to_addr 'google.com' * '173.194.65.104' '173.194.65.106' '173.194.65.147' '173.194.65.103' '173.194.65.105' '173.194.65.99' * > = apr.host_to_addr('ipv6.google.com', 'inet6') * '2a00:1450:8005::67' */ int lua_apr_host_to_addr(lua_State *L) { apr_sockaddr_t *address; apr_pool_t *pool; const char *host; char *ip_address; apr_status_t status; int family; pool = to_pool(L); host = luaL_checkstring(L, 1); family = family_check(L, 2); status = apr_sockaddr_info_get(&address, host, family, SOCK_STREAM, 0, pool); if (status != APR_SUCCESS) return push_error_status(L, status); lua_settop(L, 0); do { status = apr_sockaddr_ip_get(&ip_address, address); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, ip_address); address = address->next; } while (address != NULL); return lua_gettop(L); } /* apr.addr_to_host(ip_address [, family]) -> hostname {{{1 * * Look up the host name from an IP-address (also known as a reverse [DNS] * [dns] lookup). On success the host name is returned as a string, otherwise a * nil followed by an error message is returned. The optional @family argument * is documented under `apr.socket_create()`. * * > = apr.addr_to_host '89.238.129.35' * 'flounder.pepperfish.net' * * [dns]: http://en.wikipedia.org/wiki/Domain_Name_System */ int lua_apr_addr_to_host(lua_State *L) { apr_sockaddr_t *address; apr_pool_t *pool; const char *ip_address; char *host; apr_status_t status; int family; pool = to_pool(L); ip_address = luaL_checkstring(L, 1); family = family_check(L, 2); status = apr_sockaddr_info_get(&address, ip_address, family, SOCK_STREAM, 0, pool); if (status == APR_SUCCESS) status = apr_getnameinfo(&host, address, 0); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, host); return 1; } /* socket:connect(host, port) -> status {{{1 * * Issue a connection request to a socket either on the same machine or a * different one, as indicated by the @host string and @port number. On success * true is returned, otherwise a nil followed by an error message is * returned. */ static int socket_connect(lua_State *L) { lua_apr_socket *object; apr_sockaddr_t *address; const char *host; apr_port_t port; apr_status_t status; object = socket_check(L, 1, 1); host = luaL_checkstring(L, 2); port = luaL_checkinteger(L, 3); status = apr_sockaddr_info_get(&address, host, object->family, port, 0, object->pool); if (status == APR_SUCCESS) status = apr_socket_connect(object->handle, address); return push_status(L, status); } /* socket:bind(host, port) -> status {{{1 * * Bind the socket to the given @host string and @port number. On success true * is returned, otherwise a nil followed by an error message is returned. The * special @host value `'*'` can be used to select the default 'any' address. * For example if you want to create a web server you can start with the * following: * * -- Basic single threaded server * server = assert(apr.socket_create()) * assert(server:bind('*', 80)) * assert(server:listen(10)) * while true do * local client = assert(server:accept()) * -- Here you can receive data from the client by calling client:read() * -- and send data to the client by calling client:write() * end * * This function can fail if you try to bind a port below 1000 without * superuser privileges or if another process is already bound to the given * port number. */ static int socket_bind(lua_State *L) { lua_apr_socket *object; apr_sockaddr_t *address; const char *host; apr_port_t port; apr_status_t status; object = socket_check(L, 1, 1); host = luaL_checkstring(L, 2); if (strcmp(host, "*") == 0) host = APR_ANYADDR; port = luaL_checkinteger(L, 3); status = apr_sockaddr_info_get(&address, host, object->family, port, 0, object->pool); if (status == APR_SUCCESS) status = apr_socket_bind(object->handle, address); return push_status(L, status); } /* socket:listen(backlog) -> status {{{1 * * To listen for incoming network connections three steps must be performed: * * 1. First a socket is created with `apr.socket_create()` * 2. Next a willingness to accept incoming connections and a queue limit for * incoming connections are specified with `socket:listen()` (this call * doesn't block) * 3. Finally `socket:accept()` is called to wait for incoming connections * * On success true is returned, otherwise a nil followed by an error message is * returned. The @backlog argument indicates the number of outstanding * connections allowed in the socket's listen queue. If this value is less than * zero, the listen queue size is set to zero. As a special case, if you pass * the string `'max'` as @backlog then a platform specific maximum value is * chosen based on the compile time constant [SOMAXCONN] [SOMAXCONN]. * * [SOMAXCONN]: http://www.google.com/search?q=SOMAXCONN */ static int socket_listen(lua_State *L) { lua_apr_socket *object; apr_status_t status; apr_int32_t backlog = SOMAXCONN; object = socket_check(L, 1, 1); if (strcmp(lua_tostring(L, 2), "max") != 0) backlog = luaL_checkinteger(L, 2); status = apr_socket_listen(object->handle, backlog); return push_status(L, status); } /* socket:recvfrom([bufsize]) -> address, data {{{1 * * Read data from an [UDP] [udp] socket that has been bound to an interface * and/or port. On success two values are returned: A table with the address of * the peer from which the data was sent and a string with the received data. * If the call fails it returns nil followed by an error message. * * By default @bufsize is 1024, this means the resulting @data string will be * truncated to a maximum of 1024 bytes. If you want to receive larger * messages, pass a larger @bufsize. * * The returned @address table contains the following fields: * * - `address` is the IP address (a string) * - `port` is the port number * - `family` is one of the strings `'inet'`, `'inet6'` or `'unspec'` * * *This function is binary safe.* * * [udp]: http://en.wikipedia.org/wiki/User_Datagram_Protocol */ static int socket_recvfrom(lua_State *L) { lua_apr_socket *object; apr_status_t status; apr_sockaddr_t address = { 0 }; apr_size_t buflen; apr_int32_t flags; char buffer[1024], ip_addr[APRMAXHOSTLEN]; char *bufptr; int i; /* Validate arguments. */ object = socket_check(L, 1, 1); buflen = luaL_optint(L, 2, sizeof buffer); /* Use dynamically allocated buffer only when necessary. */ bufptr = (buflen > sizeof buffer) ? lua_newuserdata(L, buflen) : &buffer[0]; flags = 0; status = apr_socket_recvfrom(&address, object->handle, flags, bufptr, &buflen); if (status != APR_SUCCESS) return push_error_status(L, status); /* Convert the socket address to a Lua table. */ lua_newtable(L); /* Get the IP address in numeric format. */ status = apr_sockaddr_ip_getbuf(ip_addr, sizeof ip_addr, &address); if (status == APR_SUCCESS) lua_pushstring(L, ip_addr), lua_setfield(L, -2, "address"); /* Get the port number. */ lua_pushnumber(L, address.port), lua_setfield(L, -2, "port"); /* Get the address family. */ for (i = 0; i < count(family_values); i++) if (family_values[i] == address.family) { lua_pushstring(L, family_options[i]); lua_setfield(L, -2, "family"); break; } /* Push the received data. */ lua_pushlstring(L, bufptr, buflen); /* Return address table and received data. */ return 2; } /* socket:accept() -> client_socket {{{1 * * Accept a connection request on a server socket. On success a socket is * returned which forms the connection to the client, otherwise a nil followed * by an error message is returned. This function blocks until a client * connects. */ static int socket_accept(lua_State *L) { lua_apr_socket *server, *client = NULL; apr_status_t status; server = socket_check(L, 1, 1); status = socket_alloc(L, &client); client->family = server->family; client->protocol = server->protocol; if (status == APR_SUCCESS) status = apr_socket_accept(&client->handle, server->handle, client->pool); socket_init(L, client); if (status != APR_SUCCESS) return push_error_status(L, status); return 1; } /* socket:read([format, ...]) -> mixed value, ... {{{1 * * This function implements the interface of Lua's `file:read()` function. */ static int socket_read(lua_State *L) { lua_apr_socket *object = socket_check(L, 1, 1); return read_buffer(L, &object->input); } /* socket:write(value [, ...]) -> status {{{1 * * This function implements the interface of Lua's `file:write()` function. */ static int socket_write(lua_State *L) { lua_apr_socket *object = socket_check(L, 1, 1); int nresults = write_buffer(L, &object->output); apr_status_t status = flush_buffer(L, &object->output, 1); if (status != APR_SUCCESS) return push_error_status(L, status); return nresults; } /* socket:lines() -> iterator {{{1 * * This function implements the interface of Lua's `file:lines()` function. */ static int socket_lines(lua_State *L) { lua_apr_socket *object = socket_check(L, 1, 1); return read_lines(L, &object->input); } /* socket:timeout_get() -> timeout {{{1 * * Get the timeout value or blocking state of @socket. On success the timeout * value is returned, otherwise a nil followed by an error message is returned. * * The @timeout true means wait forever, false means don't wait at all and a * number is the microseconds to wait. */ static int socket_timeout_get(lua_State *L) { lua_apr_socket *object; apr_status_t status; apr_interval_time_t timeout; object = socket_check(L, 1, 1); status = apr_socket_timeout_get(object->handle, &timeout); if (status != APR_SUCCESS) return push_error_status(L, status); else if (timeout <= 0) lua_pushboolean(L, timeout != 0); else lua_pushinteger(L, (lua_Integer) timeout); return 1; } /* socket:timeout_set(timeout) -> status {{{1 * * Set the timeout value or blocking state of @socket. On success true is * returned, otherwise a nil followed by an error message is returned. * * The @timeout true means wait forever, false means don't wait at all and a * number is the microseconds to wait. */ static int socket_timeout_set(lua_State *L) { lua_apr_socket *object; apr_status_t status; apr_interval_time_t timeout; object = socket_check(L, 1, 1); if (lua_isnumber(L, 2)) timeout = luaL_checkinteger(L, 2); else timeout = lua_toboolean(L, 2) ? -1 : 0; status = apr_socket_timeout_set(object->handle, timeout); return push_status(L, status); } /* socket:opt_get(name) -> value {{{1 * * Query socket options for the specified socket. Valid values for @name are: * * - `'debug'`: turn on debugging information * - `'keep-alive'`: keep connections active * - `'linger'`: lingers on close if data is present * - `'non-block'`: turns blocking on/off for socket * - `'reuse-addr'`: the rules used in validating addresses supplied to bind * should allow reuse of local addresses * - `'sndbuf'`: set the send buffer size * - `'rcvbuf'`: set the receive buffer size * - `'disconnected'`: query the disconnected state of the socket (currently only used on Windows) * * The `'sndbuf'` and `'rcvbuf'` options have integer values, all other options * have a boolean value. */ static int socket_opt_get(lua_State *L) { apr_status_t status; lua_apr_socket *object; apr_int32_t option, value; object = socket_check(L, 1, 1); option = option_check(L, 2); status = apr_socket_opt_get(object->handle, option, &value); if (status != APR_SUCCESS) return push_error_status(L, status); else if (option == APR_SO_SNDBUF || option == APR_SO_RCVBUF) lua_pushinteger(L, value); else lua_pushboolean(L, value); return 1; } /* socket:opt_set(name, value) -> status {{{1 * * Setup socket options for the specified socket. Valid values for @name are * documented under `socket:opt_get()`, @value should be a boolean or integer * value. On success true is returned, otherwise a nil followed by an error * message is returned. */ static int socket_opt_set(lua_State *L) { apr_status_t status; lua_apr_socket *object; apr_int32_t option, value; object = socket_check(L, 1, 1); option = option_check(L, 2); value = lua_isboolean(L, 3) ? lua_toboolean(L, 3) : luaL_checkinteger(L, 3); status = apr_socket_opt_set(object->handle, option, value); return push_status(L, status); } /* socket:addr_get([type]) -> ip_address, port [, hostname] {{{1 * * Get one of the IP-address / port pairs associated with @socket, according to * @type: * * - `'local'` to get the address/port to which the socket is bound locally * - `'remote'` to get the address/port of the peer to which the socket is * connected (this is the default) * * On success the local or remote IP-address (a string) and the port (a number) * are returned, otherwise a nil followed by an error message is returned. If a * host name is available that will be returned as the third value. */ static int socket_addr_get(lua_State *L) { const char *options[] = { "local", "remote", NULL }; const apr_interface_e values[] = { APR_LOCAL, APR_REMOTE }; lua_apr_socket *object; apr_sockaddr_t *address; apr_status_t status; apr_interface_e which; char *ip_address; object = socket_check(L, 1, 1); which = values[luaL_checkoption(L, 2, "remote", options)]; status = apr_socket_addr_get(&address, which, object->handle); if (status == APR_SUCCESS) status = apr_sockaddr_ip_get(&ip_address, address); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, ip_address); lua_pushinteger(L, address->port); lua_pushstring(L, address->hostname); return 3; } /* socket:fd_get() -> fd {{{1 * * Get the underlying [file descriptor] [fildes] for this socket. On success a * number is returned, otherwise a nil followed by an error message is * returned. * * [fildes]: http://en.wikipedia.org/wiki/File_descriptor */ int socket_fd_get(lua_State *L) { apr_status_t status; lua_apr_socket *object; apr_os_sock_t fd; object = socket_check(L, 1, 1); status = apr_os_sock_get(&fd, object->handle); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushinteger(L, fd); return 1; } /* socket:fd_set(fd) -> status {{{1 * * Set the underlying file descriptor (a number) of an existing socket. On * success true is returned, otherwise a nil followed by an error message is * returned. */ int socket_fd_set(lua_State *L) { lua_apr_socket *object; apr_status_t status; apr_os_sock_t fd; object = socket_check(L, 1, 0); fd = luaL_checkinteger(L, 2); status = apr_os_sock_put(&object->handle, &fd, object->pool); return push_status(L, status); } /* socket:shutdown(mode) -> status {{{1 * * Shutdown either reading, writing, or both sides of a socket. On success true * is returned, otherwise a nil followed by an error message is returned. Valid * values for @mode are: * * - `'read'`: no longer allow read requests * - `'write'`: no longer allow write requests * - `'both'`: no longer allow read or write requests * * This does not actually close the socket descriptor, it just controls which * calls are still valid on the socket. To close sockets see `socket:close()`. */ static int socket_shutdown(lua_State *L) { const char *options[] = { "read", "write", "both", NULL }; const apr_shutdown_how_e values[] = { APR_SHUTDOWN_READ, APR_SHUTDOWN_WRITE, APR_SHUTDOWN_READWRITE }; lua_apr_socket *socket; apr_status_t status; apr_shutdown_how_e how; socket = socket_check(L, 1, 1); how = values[luaL_checkoption(L, 2, NULL, options)]; status = apr_socket_shutdown(socket->handle, how); return push_status(L, status); } /* socket:close() -> status {{{1 * * Close @socket. On success true is returned, otherwise a nil followed by an * error message is returned. */ static int socket_close(lua_State *L) { return push_status(L, socket_close_impl(L, socket_check(L, 1, 1))); } /* socket:__tostring() {{{1 */ static int socket_tostring(lua_State *L) { lua_apr_socket *socket; socket = socket_check(L, 1, 0); if (socket->handle != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_socket_type.friendlyname, socket->handle); else lua_pushfstring(L, "%s (closed)", lua_apr_socket_type.friendlyname); return 1; } /* socket:__gc() {{{1 */ static int socket_gc(lua_State *L) { lua_apr_socket *socket = socket_check(L, 1, 0); if (object_collectable((lua_apr_refobj*)socket)) { free_buffer(L, &socket->input.buffer); free_buffer(L, &socket->output.buffer); socket_close_impl(L, socket); } release_object((lua_apr_refobj*)socket); return 0; } /* }}} */ luaL_reg socket_methods[] = { { "bind", socket_bind }, { "listen", socket_listen }, { "recvfrom", socket_recvfrom }, { "accept", socket_accept }, { "connect", socket_connect }, { "read", socket_read }, { "write", socket_write }, { "lines", socket_lines }, { "timeout_get", socket_timeout_get }, { "timeout_set", socket_timeout_set }, { "opt_get", socket_opt_get }, { "opt_set", socket_opt_set }, { "addr_get", socket_addr_get }, { "fd_get", socket_fd_get }, { "fd_set", socket_fd_set }, { "shutdown", socket_shutdown }, { "close", socket_close }, { NULL, NULL }, }; luaL_reg socket_metamethods[] = { { "__tostring", socket_tostring }, { "__eq", objects_equal }, { "__gc", socket_gc }, { NULL, NULL }, }; lua_apr_objtype lua_apr_socket_type = { "lua_apr_socket*", /* metatable name in registry */ "socket", /* friendly object name */ sizeof(lua_apr_socket), /* structure size */ socket_methods, /* methods table */ socket_metamethods /* metamethods table */ }; lua-apr-0.23.2.dfsg/src/io_pipe.c000066400000000000000000000106561220664456000164550ustar00rootroot00000000000000/* Pipe I/O handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: February 13, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Lua/APR represents [pipes] [pipeline] as files just like Lua's standard * library function `io.popen()` does because it works fairly well, however * there are some differences between files and pipes which impact the API: * * - File objects implement `pipe:timeout_get()` and `pipe:timeout_set()` even * though these methods only make sense for pipe objects * * - Pipe objects implement `file:seek()` but don't support it * * One of the reasons that file/pipe support is so interwoven in APR and thus * Lua/APR is that you can create a named pipe with `apr.namedpipe_create()` * and access it using `apr.file_open()` and APR won't know or even care that * you're reading/writing a pipe instead of a file. * * [pipeline]: http://en.wikipedia.org/wiki/Pipeline_(Unix) */ #include "lua_apr.h" #include static int pipe_open(lua_State*, lua_apr_openpipe_f); /* apr.pipe_open_stdin() -> pipe {{{1 * * Open standard input as a pipe. On success the pipe is returned, otherwise a * nil followed by an error message is returned. */ int lua_apr_pipe_open_stdin(lua_State *L) { return pipe_open(L, apr_file_open_stdin); } /* apr.pipe_open_stdout() -> pipe {{{1 * * Open standard output as a pipe. On success the pipe is returned, otherwise a * nil followed by an error message is returned. */ int lua_apr_pipe_open_stdout(lua_State *L) { return pipe_open(L, apr_file_open_stdout); } /* apr.pipe_open_stderr() -> pipe {{{1 * * Open standard error as a pipe. On success the pipe is returned, otherwise a * nil followed by an error message is returned. */ int lua_apr_pipe_open_stderr(lua_State *L) { return pipe_open(L, apr_file_open_stderr); } /* apr.namedpipe_create(name [, permissions]) -> status {{{1 * * Create a [named pipe] [named_pipe]. On success true is returned, otherwise a * nil followed by an error message is returned. The @permissions argument is * documented elsewhere. * * Named pipes can be used for interprocess communication: * * 1. Check if the named pipe already exists, if it doesn't then create it * 2. Have each process access the named pipe using `apr.file_open()` * 3. Communicate between the two processes over the read/write ends of the * named pipe and close it when the communication is finished. * * Note that APR supports named pipes on UNIX but not on Windows. If you try * anyhow the error message "This function has not been implemented on this * platform" is returned. * * [named_pipe]: http://en.wikipedia.org/wiki/Named_pipe */ int lua_apr_namedpipe_create(lua_State *L) { apr_status_t status; apr_pool_t *pool; apr_fileperms_t permissions; const char *filename; pool = to_pool(L); filename = luaL_checkstring(L, 1); permissions = check_permissions(L, 2, 0); status = apr_file_namedpipe_create(filename, permissions, pool); return push_status(L, status); } /* apr.pipe_create() -> input, output {{{1 * * Create an [anonymous pipe] [anon_pipe]. On success the write and read ends * of the pipe are returned, otherwise a nil followed by an error message is * returned. There's an example use of this function in the documentation for * `process:in_set()`. * * [anon_pipe]: http://en.wikipedia.org/wiki/Anonymous_pipe */ int lua_apr_pipe_create(lua_State *L) { apr_status_t status; lua_apr_file *input, *output; lua_apr_pool *refpool; /* XXX The apr_file_pipe_create() API enforces that both pipes are allocated * from the same memory pool. This means we need a reference counted memory * pool to avoid double free bugs on exit! */ refpool = refpool_alloc(L); input = file_alloc(L, NULL, refpool); output = file_alloc(L, NULL, refpool); status = apr_file_pipe_create(&input->handle, &output->handle, refpool->ptr); if (status != APR_SUCCESS) return push_error_status(L, status); init_file_buffers(L, input, 1); init_file_buffers(L, output, 1); return 2; } /* }}}1 */ int pipe_open(lua_State *L, lua_apr_openpipe_f open_std_pipe) { apr_status_t status; lua_apr_file *pipe; pipe = file_alloc(L, NULL, NULL); status = open_std_pipe(&pipe->handle, pipe->pool->ptr); if (status != APR_SUCCESS) return push_error_status(L, status); init_file_buffers(L, pipe, 1); return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/ldap.c000066400000000000000000001337451220664456000157560ustar00rootroot00000000000000/* LDAP connection handling module for the Lua/APR binding. * * Authors: * - zhiguo zhao * - Peter Odding * - Large parts of this module were based on LuaLDAP 1.1.0 by Roberto * Ierusalimschy, André Carregal and Tomás Guisasola (license below) * Last Change: December 4, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The Lightweight Directory Access Protocol ([LDAP] [ldap]) enables querying * and modifying data hosted on [directory servers] [dirs]. LDAP databases are * similar to [relational databases] [reldbs] in the sense that both types of * databases store records with attributes and allow clients to search records * based on those attributes. Notable differences between LDAP and relational * databases are that LDAP stores all records in a [hierarchy] [hierarchy] and * records can have an arbitrary number of attributes. LDAP is frequently used * by (large) organizations to provide a centralized address book for all * employees and to store system account information like user names and * passwords in a central place (one piece of the puzzle towards [roaming * profiles] [roaming]). * * This module is based on [LuaLDAP] [lualdap] by Roberto Ierusalimschy, André * Carregal and Tomás Guisasola. * * [ldap]: http://en.wikipedia.org/wiki/LDAP * [dirs]: http://en.wikipedia.org/wiki/Directory_(databases) * [reldbs]: http://en.wikipedia.org/wiki/Relational_database * [hierarchy]: http://en.wikipedia.org/wiki/Hierarchical_database_model * [roaming]: http://en.wikipedia.org/wiki/Roaming_user_profile * [lualdap]: http://www.keplerproject.org/lualdap/ */ #include "lua_apr.h" #include #include #if APR_HAS_LDAP /* LuaLDAP license. {{{1 * * The implementation of lua_apr_ldap_search() is based on the LuaLDAP 1.1.0 * source code whose license is reproduced here in full: * * LuaLDAP is free software: it can be used for both academic and commercial * purposes at absolutely no cost. There are no royalties or GNU-like * "copyleft" restrictions. LuaLDAP qualifies as Open Source software. Its * licenses are compatible with GPL. LuaLDAP is not in the public domain and * the Kepler Project keep its copyright. The legal details are below. * * The spirit of the license is that you are free to use LuaLDAP for any * purpose at no cost without having to ask us. The only requirement is that if * you do use LuaLDAP, then you should give us credit by including the * appropriate copyright notice somewhere in your product or its documentation. * * The LuaLDAP library is designed and implemented by Roberto Ierusalimschy, * André Carregal and Tomás Guisasola. The implementation is not derived from * licensed software. * * Copyright © 2003-2007 The 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. * * (This license text was taken from the source code distribution, it's also * available online at http://www.keplerproject.org/lualdap/license.html.) */ /* Private parts. {{{1 * * Some of the references I've used while working on this module: * * - The online OpenLDAP man pages, for example: * http://linux.die.net/man/3/ldap_get_option * * - The Python LDAP binding source code * http://genecube.med.yale.edu:8080/downloads/python-ldap-2.3.11/Modules/options.c * * - The LuaLDAP source code * https://github.com/luaforge/lualdap/blob/master/lualdap/src/lualdap.c */ static apr_pool_t *ldap_pool = NULL; static int ldap_ssl_inited = 0, ldap_rebind_inited = 0; /* Types and macros. {{{2 */ /* LDAP objects. */ typedef struct { lua_apr_refobj header; apr_pool_t *pool; LDAP* ldap; } lua_apr_ldap_object; /* Union of option value types. */ typedef union { int boolean, integer; struct timeval *time; char *string, **string_array; } lua_apr_ldap_option; #define check_ldap_connection(L, idx) \ (lua_apr_ldap_object*) check_object(L, idx, &lua_apr_ldap_type) #define raise_ldap_error(L, status) \ luaL_error(L, ldap_err2string(status)) /* Windows LDAP API compatibility from LuaLDAP. {{{3 */ #ifndef WINLDAPAPI /* All platforms except Windows */ typedef int ldap_int_t; typedef const char * ldap_pchar_t; #else /* Windows compatibility. */ typedef ULONG ldap_int_t; typedef PCHAR ldap_pchar_t; # define timeval l_timeval # include /* For some reason MSDN mentions LDAP_RES_MODDN, but not LDAP_RES_MODRDN. */ # ifndef LDAP_RES_MODDN # define LDAP_RES_MODDN LDAP_RES_MODRDN # endif /* LDAP_SCOPE_DEFAULT is an OpenLDAP extension, so on Windows we will default * to LDAP_SCOPE_SUBTREE instead. */ # ifndef LDAP_SCOPE_DEFAULT # define LDAP_SCOPE_DEFAULT LDAP_SCOPE_SUBTREE # endif /* MSDN doesn't mention this function at all. Unfortunately, LDAPMessage is an opaque type. */ # define ldap_msgtype(m) ((m)->lm_msgtype) # define ldap_first_message ldap_first_entry /* The WinLDAP API allows comparisons against either string or binary values. */ # undef ldap_compare_ext /* The WinLDAP API uses ULONG seconds instead of a struct timeval. */ # undef ldap_search_ext # ifdef UNICODE # define ldap_compare_ext(ld, dn, a, v, sc, cc, msg) \ ldap_compare_extW(ld, dn, a, 0, v, sc, cc, msg) # define ldap_search_ext(ld, base, scope, f, a, o, sc, cc, t, s, msg) \ ldap_search_extW(ld, base, scope, f, a, o, sc, cc, (t) ? (t)->tv_sec : 0, s, msg) # else # define ldap_compare_ext(ld, dn, a, v, sc, cc, msg) \ ldap_compare_extA(ld, dn, a, 0, v, sc, cc, msg) # define ldap_search_ext(ld, base, scope, f, a, o, sc, cc, t, s, msg) \ ldap_search_extA(ld, base, scope, f, a, o, sc, cc, (t) ? (t)->tv_sec : 0, s, msg) # endif #endif /* WINLDAPAPI */ /* check_ldap_option() {{{2 * Mapping between string options, (APR_)LDAP_OPT_* constants and types. * Some of the option constants are missing on Windows, hence the #ifdefs. */ static struct { const char *name; const int value; const enum { LUA_APR_LDAP_TB, /* boolean */ LUA_APR_LDAP_TI, /* integer */ LUA_APR_LDAP_TT, /* struct timeval */ LUA_APR_LDAP_TS /* string */ } type; } lua_apr_ldap_options[] = { # ifdef LDAP_OPT_DEFBASE { "defbase", LDAP_OPT_DEFBASE, LUA_APR_LDAP_TS }, # endif { "deref", LDAP_OPT_DEREF, LUA_APR_LDAP_TI }, # ifdef LDAP_OPT_NETWORK_TIMEOUT { "network-timeout", LDAP_OPT_NETWORK_TIMEOUT, LUA_APR_LDAP_TT }, # endif { "protocol-version", LDAP_OPT_PROTOCOL_VERSION, LUA_APR_LDAP_TI }, # ifdef APR_LDAP_OPT_REFHOPLIMIT { "refhop-limit", APR_LDAP_OPT_REFHOPLIMIT, LUA_APR_LDAP_TI }, # endif # ifdef APR_LDAP_OPT_REFERRALS { "referrals", APR_LDAP_OPT_REFERRALS, LUA_APR_LDAP_TB }, # endif { "restart", LDAP_OPT_RESTART, LUA_APR_LDAP_TB }, { "size-limit", LDAP_OPT_SIZELIMIT, LUA_APR_LDAP_TI }, { "time-limit", LDAP_OPT_TIMELIMIT, LUA_APR_LDAP_TI }, # ifdef LDAP_OPT_TIMEOUT { "timeout", LDAP_OPT_TIMEOUT, LUA_APR_LDAP_TT }, # endif # ifdef LDAP_OPT_URI { "uri", LDAP_OPT_URI, LUA_APR_LDAP_TS }, # endif }; #define ldap_option_value(idx) lua_apr_ldap_options[idx].value #define ldap_option_type(idx) lua_apr_ldap_options[idx].type static int check_ldap_option(lua_State *L, int idx) { const char *name; int i; name = luaL_checkstring(L, idx); for (i = 0; i < count(lua_apr_ldap_options); i++) if (strcmp(name, lua_apr_ldap_options[i].name) == 0) return i; return luaL_error(L, lua_pushfstring(L, "invalid option '%s'", name)); } /* number_to_time() {{{2 */ static struct timeval *number_to_time(lua_State *L, int idx, struct timeval *tv) { if (lua_isnumber(L, idx)) { lua_Number seconds = lua_tonumber(L, idx); tv->tv_sec = (long) seconds; tv->tv_usec = (long) ((seconds - tv->tv_sec) * APR_USEC_PER_SEC); return tv; } else return NULL; } /* push_ldap_status() {{{2 * Push true or nil followed by error message based on LDAP status code. */ static int push_ldap_status(lua_State *L, int status) { if (status == LDAP_SUCCESS) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); lua_pushstring(L, ldap_err2string(status)); return 2; } } /* push_ldap_error() {{{2 * Push nil followed by error message based on apr_ldap_err_t structure. */ static int push_ldap_error(lua_State *L, apr_status_t status, apr_ldap_err_t *error) { if (error == NULL) return push_error_status(L, status); lua_pushnil(L); if (error->reason != NULL && error->msg != NULL) { /* "reason" is from APR and "msg" is from the LDAP SDK. */ lua_pushfstring(L, "%s (%s)", error->reason, error->msg); lua_pushinteger(L, error->rc); } else if (error->reason != NULL) { /* Some APR functions fill in "reason" but not "msg". */ lua_pushstring(L, error->reason); lua_pushinteger(L, error->rc); } else { /* Not sure this is needed. */ status_to_message(L, status); status_to_name(L, status); } return 3; } /* Search iterator. {{{2 */ static void set_attributes(lua_State *L, LDAP *ld, LDAPMessage *entry, int tab) { BerElement *ber = NULL; BerValue **values; char *attr; int i, n; attr = ldap_first_attribute(ld, entry, &ber); while (attr != NULL) { values = ldap_get_values_len(ld, entry, attr); n = ldap_count_values_len(values); if (n == 0) /* no values */ lua_pushboolean(L, 1); else if (n == 1) /* just one value */ lua_pushlstring(L, values[0]->bv_val, values[0]->bv_len); else { /* multiple values */ lua_newtable(L); for (i = 0; i < n; i++) { lua_pushlstring(L, values[i]->bv_val, values[i]->bv_len); lua_rawseti(L, -2, i+1); } } lua_setfield(L, tab, attr); ldap_value_free_len(values); ldap_memfree(attr); attr = ldap_next_attribute(ld, entry, ber); } ber_free(ber, 0); } static void push_distinguished_name(lua_State *L, LDAP *ld, LDAPMessage *entry) { char *dn = ldap_get_dn(ld, entry); lua_pushstring(L, dn); ldap_memfree(dn); } static int search_iterator(lua_State *L) { LDAPMessage *result, *message, *entry; lua_apr_ldap_object *object; struct timeval *timeout; int status, msgid; object = lua_touserdata(L, lua_upvalueindex(1)); msgid = lua_tointeger(L, lua_upvalueindex(2)); timeout = lua_touserdata(L, lua_upvalueindex(3)); status = ldap_result(object->ldap, msgid, LDAP_MSG_ONE, timeout, &result); if (status == 0) raise_error_status(L, APR_TIMEUP); else if (status == -1) /* TODO Can we get a more specific error (message) here? ld_errno? */ raise_error_message(L, "Unspecified error"); else if (status == LDAP_RES_SEARCH_RESULT) { /* end of search results */ return 0; } else { message = ldap_first_message(object->ldap, result); switch (ldap_msgtype(message)) { case LDAP_RES_SEARCH_ENTRY: entry = ldap_first_entry(object->ldap, message); push_distinguished_name(L, object->ldap, entry); lua_newtable(L); set_attributes(L, object->ldap, entry, lua_gettop(L)); ldap_msgfree(result); return 2; /* No reference to LDAP_RES_SEARCH_REFERENCE on MSDN. Maybe is has a replacement? */ # ifdef LDAP_RES_SEARCH_REFERENCE case LDAP_RES_SEARCH_REFERENCE: { LDAPMessage *reference = ldap_first_reference(object->ldap, message); push_distinguished_name(L, object->ldap, reference); /* is this supposed to work? */ ldap_msgfree(result); return 1; } # endif case LDAP_RES_SEARCH_RESULT: /* end of search results */ ldap_msgfree(result); return 0; default: ldap_msgfree(result); raise_error_message(L, "unhandled message type in search results"); } } /* shouldn't be reached. */ ldap_msgfree(result); return 0; } /* Support for modifications. {{{2 */ /* Maximum number of attributes manipulated in an operation */ #ifndef LUA_APR_LDAP_MAX_ATTRS #define LUA_APR_LDAP_MAX_ATTRS 128 #endif /* Flags for supported LDAP operations. */ #define LUA_APR_LDAP_MOD_ADD (LDAP_MOD_ADD | LDAP_MOD_BVALUES) #define LUA_APR_LDAD_MOD_DEL (LDAP_MOD_DELETE | LDAP_MOD_BVALUES) #define LUA_APR_LDAD_MOD_REP (LDAP_MOD_REPLACE | LDAP_MOD_BVALUES) #define LUA_APR_LDAP_NOOP 0 /* Size of buffer of NULL-terminated arrays of pointers to struct values */ #ifndef LUA_APR_LDAP_ARRAY_VALUES_SIZE #define LUA_APR_LDAP_ARRAY_VALUES_SIZE (2 * LUA_APR_LDAP_MAX_ATTRS) #endif /* Maximum number of values structures */ #ifndef LUA_APR_LDAP_MAX_VALUES #define LUA_APR_LDAP_MAX_VALUES (LUA_APR_LDAP_ARRAY_VALUES_SIZE / 2) #endif /* LDAP attribute modification structure */ typedef struct { LDAPMod *attrs[LUA_APR_LDAP_MAX_ATTRS + 1]; LDAPMod mods[LUA_APR_LDAP_MAX_ATTRS]; int ai; BerValue *values[LUA_APR_LDAP_ARRAY_VALUES_SIZE]; int vi; BerValue bvals[LUA_APR_LDAP_MAX_VALUES]; int bi; } attrs_data; /* value_error() - Raise error because of invalid attribute value. {{{3 */ static void value_error(lua_State *L, const char *name) { luaL_error(L, "invalid value of attribute `%s' (%s)", name, lua_typename(L, lua_type(L, -1))); } /* A_init() - Initialize attributes structure. {{{3 */ static void A_init(attrs_data *attrs) { attrs->ai = 0; attrs->attrs[0] = NULL; attrs->vi = 0; attrs->values[0] = NULL; attrs->bi = 0; } /* A_setbval() - Store the string on top of the stack on the attributes {{{3 * structure. Increment the bvals counter. */ static BerValue *A_setbval(lua_State *L, attrs_data *a, const char *n) { BerValue *ret = &(a->bvals[a->bi]); if (a->bi >= LUA_APR_LDAP_MAX_VALUES) { luaL_error(L, "too many values"); return NULL; } else if (!lua_isstring(L, -1)) { value_error(L, n); return NULL; } a->bvals[a->bi].bv_len = lua_strlen(L, -1); a->bvals[a->bi].bv_val = (char *)lua_tostring(L, -1); a->bi++; return ret; } /* A_setval() - Store a pointer to the value on top of the stack on the {{{3 * attributes structure. */ static BerValue **A_setval(lua_State *L, attrs_data *a, const char *n) { BerValue **ret = &(a->values[a->vi]); if (a->vi >= LUA_APR_LDAP_ARRAY_VALUES_SIZE) { luaL_error(L, "too many values"); return NULL; } a->values[a->vi] = A_setbval(L, a, n); a->vi++; return ret; } /* A_nullval() - Store a NULL pointer on the attributes structure. {{{3 */ static BerValue **A_nullval(lua_State *L, attrs_data *a) { BerValue **ret = &(a->values[a->vi]); if (a->vi >= LUA_APR_LDAP_ARRAY_VALUES_SIZE) { luaL_error(L, "too many values"); return NULL; } a->values[a->vi] = NULL; a->vi++; return ret; } /* A_tab2val() - Store the value of an attribute. Valid values are: {{{3 * - true => no values; * - string => one value; or * - table of strings => many values. */ static BerValue **A_tab2val(lua_State *L, attrs_data *a, const char *name) { int tab = lua_gettop(L); BerValue **ret = &(a->values[a->vi]); if (lua_isboolean(L, tab) && (lua_toboolean(L, tab) == 1)) /* true */ return NULL; else if (lua_isstring(L, tab)) /* string */ A_setval(L, a, name); else if (lua_istable(L, tab)) { /* list of strings */ int i; int n = lua_strlen(L, tab); for (i = 1; i <= n; i++) { lua_rawgeti(L, tab, i); /* push table element */ A_setval(L, a, name); } lua_pop(L, n); } else { value_error(L, name); return NULL; } A_nullval(L, a); return ret; } /* A_setmod() - Set a modification value (which MUST be on top of the stack). {{{3 */ static void A_setmod(lua_State *L, attrs_data *a, int op, const char *name) { if (a->ai >= LUA_APR_LDAP_MAX_ATTRS) { luaL_error(L, "too many attributes"); return; } a->mods[a->ai].mod_op = op; a->mods[a->ai].mod_type = (char *)name; a->mods[a->ai].mod_bvalues = A_tab2val(L, a, name); a->attrs[a->ai] = &a->mods[a->ai]; a->ai++; } /* A_tab2mod() - Convert a Lua table into an array of modifications. {{{3 * An array of modifications is a NULL-terminated array of LDAPMod's. */ static void A_tab2mod(lua_State *L, attrs_data *a, int tab, int op) { lua_pushnil(L); /* first key for lua_next */ while (lua_next(L, tab) != 0) { /* attribute must be a string and not a number */ if (!lua_isnumber(L, -2) && lua_isstring(L, -2)) A_setmod(L, a, op, lua_tostring(L, -2)); /* pop value and leave last key on the stack as next key for lua_next */ lua_pop(L, 1); } } /* A_lastattr() - Terminate the array of attributes. {{{3 */ static void A_lastattr(lua_State *L, attrs_data *a) { if (a->ai >= LUA_APR_LDAP_MAX_ATTRS) { luaL_error(L, "too many attributes"); return; } a->attrs[a->ai] = NULL; a->ai++; } /* result_message() - Get the result message of an operation. {{{3 * #1 upvalue == connection * #2 upvalue == msgid * #3 upvalue == result code of the message (ADD, DEL etc.) to be received. */ static int result_message(lua_State *L) { struct timeval *timeout = NULL; /* ??? function parameter ??? */ LDAPMessage *res; int rc; lua_apr_ldap_object *object = check_ldap_connection(L, lua_upvalueindex(1)); int msgid = (int)lua_tonumber(L, lua_upvalueindex(2)); /*int res_code = (int)lua_tonumber(L, lua_upvalueindex(3));*/ luaL_argcheck(L, object->ldap, 1, "LDAP connection is closed"); rc = ldap_result(object->ldap, msgid, LDAP_MSG_ONE, timeout, &res); if (rc == 0) { return push_error_message(L, "result timeout expired"); } else if (rc < 0) { ldap_msgfree(res); return push_error_message(L, "result error"); } else { int err, ret = 1; char *mdn, *msg1, *msg2; rc = ldap_parse_result(object->ldap, res, &err, &mdn, &msg1, NULL, NULL, 1); if (rc != LDAP_SUCCESS) return push_error_message(L, ldap_err2string(rc)); switch (err) { case LDAP_SUCCESS: case LDAP_COMPARE_TRUE: lua_pushboolean(L, 1); break; case LDAP_COMPARE_FALSE: lua_pushboolean(L, 0); break; default: lua_pushnil(L); /* Either error message string may be NULL. */ msg2 = ldap_err2string(err); if (msg1 == NULL && msg2 == NULL) { ret = 1; } else if (msg1 != NULL && msg2 == NULL) { lua_pushstring(L, msg1); ret = 2; } else if (msg1 == NULL && msg2 != NULL) { lua_pushstring(L, msg2); ret = 2; } else { lua_pushstring(L, msg1); lua_pushliteral(L, " ("); lua_pushstring(L, msg2); lua_pushliteral(L, ")"); lua_concat(L, 4); ret = 2; } } ldap_memfree(mdn); ldap_memfree(msg1); return ret; } } /* create_future() - Push a function to process the LDAP result. {{{3 */ static int create_future(lua_State *L, ldap_int_t rc, int conn, ldap_int_t msgid, int code) { if (rc != LDAP_SUCCESS) return push_error_message(L, ldap_err2string(rc)); lua_pushvalue(L, conn); /* push connection as #1 upvalue */ lua_pushnumber(L, msgid); /* push msgid as #2 upvalue */ lua_pushnumber(L, code); /* push code as #3 upvalue */ lua_pushcclosure(L, result_message, 3); return 1; } /* op2code() - Convert a string into an internal LDAP_MOD operation code. {{{3 */ static int op2code(const char *s) { if (!s) return LUA_APR_LDAP_NOOP; switch (*s) { case '+': return LUA_APR_LDAP_MOD_ADD; case '-': return LUA_APR_LDAD_MOD_DEL; case '=': return LUA_APR_LDAD_MOD_REP; default: return LUA_APR_LDAP_NOOP; } } /* apr.ldap([url [, secure ]]) -> ldap_conn {{{1 * * Create an LDAP connection. The @url argument is a URL string with the * following components: * * - One of the URL schemes `ldap://` (the default) or `ldaps://` (for secure * connections) * - The host name or IP-address of the LDAP server (defaults to 127.0.0.1) * - An optional port number (defaults to 389) * * If @secure is true the connection will use [STARTTLS] [starttls] even if the * URL scheme is `ldap://`. On success an LDAP connection object is returned, * otherwise a nil followed by an error message is returned. * * [starttls]: http://en.wikipedia.org/wiki/STARTTLS */ int lua_apr_ldap(lua_State *L) { lua_apr_ldap_object *object; apr_ldap_err_t *error = NULL; apr_pool_t *memory_pool; apr_status_t status; int portno, secure = APR_LDAP_NONE; const char *url, *hostname; apr_uri_t info; lua_settop(L, 2); memory_pool = to_pool(L); url = luaL_optstring(L, 1, "ldap://127.0.0.1"); if (lua_toboolean(L, 2)) secure = APR_LDAP_STARTTLS; /* Get and parse the LDAP URL. */ status = apr_uri_parse(memory_pool, url, &info); if (status != APR_SUCCESS) return push_error_status(L, status); /* Get the host name and port number of the LDAP server. */ hostname = (info.hostname != NULL) ? info.hostname : "127.0.0.1"; portno = (info.port_str != NULL) ? info.port : APR_URI_LDAP_DEFAULT_PORT; /* Use a secure connection? */ if (info.scheme != NULL && strcmp(info.scheme, "ldaps") == 0) secure = APR_LDAP_SSL; /* Create the userdata object and memory pool. */ object = new_object(L, &lua_apr_ldap_type); status = apr_pool_create(&object->pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); /* Automatically call apr_ldap_ssl_init() as needed because this * stuff is so low level it doesn't make sense to expose it to Lua. */ if (secure != APR_LDAP_NONE && !ldap_ssl_inited) { if (ldap_pool == NULL) { /* Create a private memory pool for SSL and rebind support. */ status = apr_pool_create(&ldap_pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); } status = apr_ldap_ssl_init(ldap_pool, NULL, 0, &error); if (status != APR_SUCCESS) return push_error_status(L, status); ldap_ssl_inited = 1; } /* Open the LDAP connection. */ status = apr_ldap_init(object->pool, &object->ldap, hostname, portno, secure, &error); if (status != APR_SUCCESS) return push_ldap_error(L, status, error); return 1; } /* apr.ldap_info() -> string {{{1 * * This function returns a string describing the LDAP [SDK] [sdk] (library) * currently in use. On success a string is returned, otherwise a nil followed * by an error message is returned. The resulting string is intended to be * displayed to the user, it's not meant to be parsed (although you can of * course decide to do this :-). According to [apr_ldap.h] [ldap_docs] the * following LDAP SDKs can be used: * * - Netscape (I assume this been superseded by the Mozilla SDK below) * - Solaris * - [Novell](http://www.novell.com/developer/ndk/ldap_libraries_for_c.html) * - [Mozilla](https://wiki.mozilla.org/Directory) * - [OpenLDAP](http://www.openldap.org/software/man.cgi?query=ldap) * - [Microsoft] [ms_ldap_sdk] * - [Tivoli](http://en.wikipedia.org/wiki/IBM_Tivoli_Directory_Server) * - [zOS](http://www.lsu.edu/departments/ocs/tsc/ldap/ldappref.html) * - 'Others' (implying there is support for other SDKs?) * * [sdk]: http://en.wikipedia.org/wiki/Software_development_kit * [ms_ldap_sdk]: http://msdn.microsoft.com/en-us/library/aa367008(v=vs.85).aspx * [ldap_docs]: http://apr.apache.org/docs/apr/trunk/group___a_p_r___util___l_d_a_p.html */ int lua_apr_ldap_info(lua_State *L) { apr_pool_t *memory_pool; apr_ldap_err_t *result; int status; memory_pool = to_pool(L); status = apr_ldap_info(memory_pool, &result); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, result->reason); return 1; } /* apr.ldap_url_parse(string) -> table {{{1 * * Parse an [LDAP URL] [ldap_urls] into a table of URL components. On success a * table is returned, otherwise a nil followed by an error message and one of * the following strings is returned: * * - **MEM**: can't allocate memory space * - **PARAM**: parameter is bad * - **BADSCHEME**: URL doesn't begin with `ldap://`, `ldapi://` or `ldaps://` * - **BADENCLOSURE**: URL is missing trailing `>` * - **BADURL**: URL is bad * - **BADHOST**: host port is bad * - **BADATTRS**: bad (or missing) attributes * - **BADSCOPE**: scope string is invalid (or missing) * - **BADFILTER**: bad or missing filter * - **BADEXTS**: bad or missing extensions * * LDAP URLs look like this: * * ldap[is]://host:port[/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * * Where: * * - @attributes is a comma separated list * - @scope is one of the three strings **base**, **one** or **sub** (the default is **base**) * - @filter is an string-represented filter as in RFC 2254 * * For example: * * > = apr.ldap_url_parse 'ldap://root.openldap.org/dc=openldap,dc=org' * { * scheme = 'ldap', * host = 'root.openldap.org', * port = 389, * scope = 'sub', * dn = 'dc=openldap,dc=org', * crit_exts = 0, * } * * [ldap_urls]: http://en.wikipedia.org/wiki/LDAP#LDAP_URLs */ int lua_apr_ldap_url_parse(lua_State*L) { apr_ldap_url_desc_t *ludpp; apr_pool_t *memory_pool; apr_ldap_err_t *error = NULL; const char *url; int status, i; char *attr, *ext; memory_pool = to_pool(L); url = luaL_checkstring(L, 1); status = apr_ldap_url_parse_ext(memory_pool, url, &ludpp, &error); if (status != APR_LDAP_URL_SUCCESS) { push_ldap_error(L, status, error); lua_pop(L, 1); switch (status) { case APR_LDAP_URL_ERR_MEM: lua_pushliteral(L, "MEM"); return 3; case APR_LDAP_URL_ERR_PARAM: lua_pushliteral(L, "PARAM"); return 3; case APR_LDAP_URL_ERR_BADSCHEME: lua_pushliteral(L, "BADSCHEME"); return 3; case APR_LDAP_URL_ERR_BADENCLOSURE: lua_pushliteral(L, "BADENCLOSURE"); return 3; case APR_LDAP_URL_ERR_BADURL: lua_pushliteral(L, "BADURL"); return 3; case APR_LDAP_URL_ERR_BADHOST: lua_pushliteral(L, "BADHOST"); return 3; case APR_LDAP_URL_ERR_BADATTRS: lua_pushliteral(L, "BADATTRS"); return 3; case APR_LDAP_URL_ERR_BADSCOPE: lua_pushliteral(L, "BADSCOPE"); return 3; case APR_LDAP_URL_ERR_BADFILTER: lua_pushliteral(L, "BADFILTER"); return 3; case APR_LDAP_URL_ERR_BADEXTS: lua_pushliteral(L, "BADEXTS"); return 3; default: return 2; } } lua_newtable(L); lua_pushstring(L, ludpp->lud_scheme); lua_setfield(L, -2, "scheme"); lua_pushstring(L, ludpp->lud_host); lua_setfield(L, -2, "host"); lua_pushinteger(L, ludpp->lud_port); lua_setfield(L, -2, "port"); if (ludpp->lud_scope == LDAP_SCOPE_BASE) lua_pushliteral(L, "base"); else if (ludpp->lud_scope == LDAP_SCOPE_ONELEVEL) lua_pushliteral(L, "one"); else lua_pushliteral(L, "sub"); lua_setfield(L, -2, "scope"); lua_pushstring(L, ludpp->lud_filter); lua_setfield(L, -2, "filter"); lua_pushstring(L, ludpp->lud_dn); lua_setfield(L, -2, "dn"); lua_pushinteger(L, ludpp->lud_crit_exts); lua_setfield(L, -2, "crit_exts"); if (ludpp->lud_attrs != NULL) { i = 0; lua_newtable(L); while ((attr = ludpp->lud_attrs[i++]) != NULL) { lua_pushinteger(L, i + 1); lua_pushstring(L, attr); lua_settable(L, -3); } lua_setfield(L, -2, "attrs"); } if (ludpp->lud_exts != NULL) { i = 0; lua_newtable(L); while ((ext = ludpp->lud_exts[i++]) != NULL) { lua_pushinteger(L, i + 1); lua_pushstring(L, ext); lua_settable(L, -3); } lua_setfield(L, -2, "exts"); } return 1; } /* apr.ldap_url_check(url) -> type {{{1 * * Checks whether the given URL is an LDAP URL. On success one of the strings * below is returned, otherwise nil is returned: * * - **ldap** for regular LDAP URLs (`ldap://`) * - **ldapi** for socket LDAP URLs (`ldapi://`) * - **ldaps** for SSL LDAP URLs (`ldaps://`) */ int lua_apr_ldap_url_check(lua_State *L) { const char *url; url = luaL_checkstring(L, 1); if (apr_ldap_is_ldapi_url(url)) lua_pushliteral(L, "ldapi"); else if (apr_ldap_is_ldaps_url(url)) lua_pushliteral(L, "ldaps"); else if (apr_ldap_is_ldap_url(url)) lua_pushliteral(L, "ldap"); else lua_pushnil(L); return 1; } /* ldap_conn:bind([who [, passwd]]) -> status {{{1 * * Bind to the LDAP directory. If no arguments are given an anonymous bind is * attempted, otherwise @who should be a string with the relative distinguished * name (RDN) of the user in the form `'cn=admin,dc=example,dc=com'`. On * success true is returned, otherwise a nil followed by an error message is * returned. */ static int lua_apr_ldap_bind(lua_State *L) { lua_apr_ldap_object *object; const char *who, *passwd; int status, version; object = check_ldap_connection(L, 1); who = luaL_optstring(L, 2, NULL); passwd = luaL_optstring(L, 3, NULL); /* Default to LDAP v3 */ version = LDAP_VERSION3; status = ldap_set_option(object->ldap, LDAP_OPT_PROTOCOL_VERSION, &version); if (status != LDAP_SUCCESS) return push_ldap_status(L, status); status = ldap_simple_bind_s(object->ldap, (char*)who, (char*)passwd); return push_ldap_status(L, status); } /* ldap_conn:unbind() -> status {{{1 * * Unbind from the directory. On success true is returned, otherwise a nil * followed by an error message is returned. */ static int lua_apr_ldap_unbind(lua_State *L) { lua_apr_ldap_object *object; int status; object = check_ldap_connection(L, 1); status = ldap_unbind(object->ldap); return push_ldap_status(L, status); } /* ldap_conn:option_get(name) -> value {{{1 * * Get an LDAP option by its @name (one of the strings documented below). On * success the option value is returned, otherwise a nil followed by an error * message is returned. These are the supported LDAP options: * * - **defbase** (string) * - **deref** (integer) * - **network-timeout** (fractional number of seconds) * - **protocol-version** (integer) * - **refhop-limit** (integer) * - **referral-urls** (list of strings) * - **referrals** (boolean) * - **restart** (boolean) * - **size-limit** (integer) * - **time-limit** (integer) * - **timeout** (fractional number of seconds) * - **uri** (string with space separated URIs) */ static int lua_apr_ldap_option_get(lua_State *L) { lua_apr_ldap_object *object; apr_ldap_err_t *error = NULL; int optidx, type, status; lua_apr_ldap_option value; /* Check the arguments. */ object = check_ldap_connection(L, 1); optidx = check_ldap_option(L, 2); /* Get the option value. */ status = apr_ldap_get_option(object->pool, object->ldap, ldap_option_value(optidx), &value, &error); if (status != APR_SUCCESS) return push_ldap_error(L, status, error); /* Convert the LDAP C API value to a Lua value. */ type = ldap_option_type(optidx); if (type == LUA_APR_LDAP_TB) { /* Boolean. */ lua_pushboolean(L, (void*)value.boolean == LDAP_OPT_ON); } else if (type == LUA_APR_LDAP_TI) { /* Integer. */ lua_pushinteger(L, value.integer); } else if (type == LUA_APR_LDAP_TT) { /* Time (fractional number of seconds). */ if (value.time != NULL) { lua_pushnumber(L, (lua_Number)value.time->tv_sec + ((lua_Number)value.time->tv_usec / APR_USEC_PER_SEC)); ldap_memfree((void*)value.time); } else lua_pushnil(L); } else if (type == LUA_APR_LDAP_TS) { /* String. */ if (value.string != NULL) { lua_pushstring(L, value.string); ldap_memfree(value.string); } else lua_pushnil(L); } else assert(0); return 1; } /* ldap_conn:option_set(name, value) -> status {{{1 * * Set the LDAP option @name (one of the strings documented for * `ldap_conn:option_get()`) to @value. On success true is returned, otherwise * a nil followed by an error message is returned. */ static int lua_apr_ldap_option_set(lua_State *L) { lua_apr_ldap_object *object; apr_ldap_err_t *error = NULL; struct timeval time; apr_status_t status; int optidx, type, intval; void *value; object = check_ldap_connection(L, 1); optidx = check_ldap_option(L, 2); /* Convert the Lua value to an LDAP C API value. */ type = ldap_option_type(optidx); if (type == LUA_APR_LDAP_TB) { /* Boolean. */ value = lua_toboolean(L, 3) ? LDAP_OPT_ON : LDAP_OPT_OFF; } else if (type == LUA_APR_LDAP_TI) { /* Integer. */ intval = luaL_checkint(L, 3); value = &intval; } else if (type == LUA_APR_LDAP_TT) { /* Time (fractional number of seconds). */ luaL_checktype(L, 3, LUA_TNUMBER); value = number_to_time(L, 3, &time); } else if (type == LUA_APR_LDAP_TS) { /* String. */ value = (void*)luaL_optstring(L, 3, NULL); } else assert(0); /* Set the option value. */ status = apr_ldap_set_option(object->pool, object->ldap, ldap_option_value(optidx), value, &error); if (status != APR_SUCCESS) return push_ldap_error(L, status, error); lua_pushboolean(L, 1); return 1; } #if (APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 3)) /* ldap_conn:rebind_add([who [, password]]) -> status {{{1 * * LDAP servers can return referrals to other servers for requests the server * itself will not/can not serve. This function creates a cross reference entry * for the specified LDAP connection. The rebind callback function will look up * this LDAP connection so it can retrieve the @who and @password fields for * use in any binds while referrals are being chased. * * On success true is returned, otherwise a nil followed by an error message is * returned. * * When the LDAP connection is garbage collected the cross reference entry is * automatically removed, alternatively `ldap_conn:rebind_remove()` can be * called to explicitly remove the entry. */ static int lua_apr_ldap_rebind_add(lua_State*L) { /* For LDAP rebind support APR requires a memory pool from the caller to create * a mutex. Inspecting the implementation, it appears that this mutex cannot be * reinitialized. This means the memory pool must not be destroyed or the LDAP * rebind support would break badly! In other words, now follows a known * memory leak caused by an apparently borked API :-) */ lua_apr_ldap_object *object; const char *who, *password; apr_status_t status; object = check_ldap_connection(L, 1); who = luaL_optstring(L, 2, NULL); password = luaL_optstring(L, 3, NULL); /* Automatically call apr_ldap_rebind_init() as needed because this * stuff is so low level it doesn't make sense to expose it to Lua. */ if (!ldap_rebind_inited) { if (ldap_pool == NULL) { /* Create a private memory pool for SSL and rebind support. */ status = apr_pool_create(&ldap_pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); } status = apr_ldap_rebind_init(ldap_pool); if (status != APR_SUCCESS) return push_error_status(L, status); ldap_rebind_inited = 1; } status = apr_ldap_rebind_add(object->pool, object->ldap, who, password); return push_status(L, status); } /* ldap_conn:rebind_remove() -> status {{{1 * * Explicitly remove an LDAP cross reference entry (also done automatically * when the LDAP connection is garbage collected). On success true is returned, * otherwise a nil followed by an error message is returned. */ static int lua_apr_ldap_rebind_remove(lua_State*L) { lua_apr_ldap_object *object; apr_status_t status = APR_SUCCESS; object = check_ldap_connection(L, 1); if (ldap_rebind_inited) status = apr_ldap_rebind_remove(object->ldap); /* TODO The original code by zhiguo zhao had "object->ldap = NULL" here. */ return push_status(L, status); } #endif /* ldap_conn:search(parameters) -> iterator {{{1 * * _The implementation of this method is based on LuaLDAP and the following * documentation was based on the [LuaLDAP manual] [lualdap]:_ * * Performs a search operation on the directory. The parameters are described * below. The search method will return a search iterator which is a function * that requires no arguments. The search iterator is used to get the search * result and will return a string representing the distinguished name and a * table of attributes as returned by the search request. * * Supported parameters: * * - **attrs**: a string or a list of attribute names to be retrieved (default * is to retrieve all attributes) * * - **attrsonly**: a boolean value that must be either false (default) if * both attribute names and values are to be retrieved, or true if only * names are wanted * * - **base**: The [distinguished name] [distinguished_name] of the entry at * which to start the search * * - **filter**: A string representing the search filter as described in [The * String Representation of LDAP Search Filters] [rfc2254] (RFC 2254) * * - **scope**: A string indicating the scope of the search. The valid strings * are: _base_, _one_ and _sub_. The empty string and nil will be treated as * the default scope * * - **sizelimit**: The maximum number of entries to return (default is no * limit) * * - **timeout**: The timeout in seconds (default is no timeout). The * precision is microseconds * * [distinguished_name]: http://www.keplerproject.org/lualdap/manual.html#dn * [rfc2254]: http://www.ietf.org/rfc/rfc2254.txt * [lualdap]: http://www.keplerproject.org/lualdap/manual.html#connection */ static int lua_apr_ldap_search(lua_State *L) { lua_apr_ldap_object *object; int scope, attrsonly, sizelimit; int status, i, n, msgid, time_idx; struct timeval *timeout; ldap_pchar_t base, filter; char **attrs; lua_settop(L, 2); object = check_ldap_connection(L, 1); luaL_checktype(L, 2, LUA_TTABLE); /* Get the size limit (if any). */ lua_getfield(L, 2, "sizelimit"); sizelimit = lua_isnumber(L, -1) ? lua_tointeger(L, -1) : LDAP_NO_LIMIT; lua_pop(L, 1); /* Check if we're interested in attribute values. */ lua_getfield(L, 2, "attrsonly"); attrsonly = lua_toboolean(L, -1); lua_pop(L, 1); /* Get "base" string. */ lua_getfield(L, 2, "base"); base = (ldap_pchar_t) (lua_isstring(L, -1) ? lua_tostring(L, -1) : NULL); lua_pop(L, 1); /* Get "filter" string. */ lua_getfield(L, 2, "filter"); filter = (ldap_pchar_t) (lua_isstring(L, -1) ? lua_tostring(L, -1) : NULL); lua_pop(L, 1); /* Get timeout value. */ timeout = lua_newuserdata(L, sizeof *timeout); time_idx = lua_gettop(L); lua_getfield(L, 2, "timeout"); timeout = number_to_time(L, -1, timeout); lua_pop(L, 1); /* Get scope type from string. */ lua_getfield(L, 2, "scope"); scope = LDAP_SCOPE_DEFAULT; if (lua_isstring(L, -1)) { const char *scopename = lua_tostring(L, -1); if (strcmp(scopename, "base") == 0) scope = LDAP_SCOPE_BASE; else if (strcmp(scopename, "one") == 0) scope = LDAP_SCOPE_ONELEVEL; else if (strcmp(scopename, "sub") == 0) scope = LDAP_SCOPE_SUBTREE; } lua_pop(L, 1); /* Get attributes to search for as NULL terminated array of strings. */ lua_getfield(L, 2, "attrs"); n = lua_istable(L, -1) ? lua_objlen(L, -1) : 1; attrs = lua_newuserdata(L, sizeof attrs[0] * (n + 1)); if (!lua_istable(L, -1)) { attrs[0] = (char*)lua_tostring(L, -1); attrs[1] = NULL; } else { for (i = 0; i < n; i++) { lua_rawgeti(L, -1, i + 1); attrs[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); /* pop string */ } attrs[n] = NULL; } lua_pop(L, 1); /* pop "attrs" */ /* Start the search. */ status = ldap_search_ext(object->ldap, base, scope, filter, attrs, attrsonly, NULL, NULL, timeout, sizelimit, &msgid); if (status != LDAP_SUCCESS) raise_ldap_error(L, status); /* Prepare the search iterator and its upvalues. */ lua_pushvalue(L, 1); lua_pushnumber(L, msgid); if (timeout != NULL) lua_pushvalue(L, time_idx); else lua_pushlightuserdata(L, NULL); lua_pushcclosure(L, search_iterator, 3); return 1; } /* ldap_conn:add(dn, attrs) -> future {{{1 * * Add a new entry to the directory. The string @dn is the distinguished name * of the new entry. The table @attrs contains the attributes and values. * Returns a function to process the LDAP result. */ static int lua_apr_ldap_add(lua_State *L) { lua_apr_ldap_object *object; ldap_pchar_t dn; attrs_data attrs; ldap_int_t rc, msgid; object = check_ldap_connection(L, 1); dn = (ldap_pchar_t) luaL_checkstring(L, 2); A_init(&attrs); if (lua_istable(L, 3)) A_tab2mod(L, &attrs, 3, LUA_APR_LDAP_MOD_ADD); A_lastattr(L, &attrs); rc = ldap_add_ext(object->ldap, dn, attrs.attrs, NULL, NULL, &msgid); return create_future(L, rc, 1, msgid, LDAP_RES_ADD); } /* ldap_conn:compare(dn, attr, value) -> future {{{1 * * Compare a value against an entry. The string @dn contains the distinguished * name of the entry, the string @attr is the name of the attribute to compare * and the string @value is the value to compare against. Returns a function to * process the LDAP result. */ static int lua_apr_ldap_compare(lua_State *L) { lua_apr_ldap_object *object; ldap_pchar_t dn, attr; BerValue bvalue; ldap_int_t rc, msgid; object = check_ldap_connection(L, 1); dn = (ldap_pchar_t) luaL_checkstring(L, 2); attr = (ldap_pchar_t) luaL_checkstring(L, 3); bvalue.bv_val = (char *)luaL_checkstring(L, 4); bvalue.bv_len = lua_strlen(L, 4); rc = ldap_compare_ext(object->ldap, dn, attr, &bvalue, NULL, NULL, &msgid); return create_future(L, rc, 1, msgid, LDAP_RES_COMPARE); } /* ldap_conn:delete(dn) -> future {{{1 * * Delete an entry. The string @dn is the distinguished name of the entry to * delete. Returns a function to process the LDAP result. */ static int lua_apr_ldap_delete(lua_State *L) { lua_apr_ldap_object *object; ldap_pchar_t dn; ldap_int_t rc, msgid; object = check_ldap_connection(L, 1); dn = (ldap_pchar_t) luaL_checkstring(L, 2); rc = ldap_delete_ext(object->ldap, dn, NULL, NULL, &msgid); return create_future(L, rc, 1, msgid, LDAP_RES_DELETE); } /* ldap_conn:modify(dn, mods [, ...]) -> future {{{1 * * Modify an entry. The string @dn is the distinguished name of the entry to * modify. The table @mods contains modifications to apply. You can pass any * number of additional tables with modifications to apply. On success true is * returned, otherwise a nil followed by an error message is returned. */ static int lua_apr_ldap_modify(lua_State *L) { lua_apr_ldap_object *object; ldap_pchar_t dn; attrs_data attrs; ldap_int_t rc, msgid; int param = 3; object = check_ldap_connection(L, 1); dn = (ldap_pchar_t) luaL_checkstring(L, 2); A_init (&attrs); while (lua_istable(L, param)) { int op; /* get operation ('+','-','=' operations allowed) */ lua_rawgeti(L, param, 1); op = op2code(lua_tostring(L, -1)); if (op == LUA_APR_LDAP_NOOP) return luaL_error(L, "Forgotten operation on argument #%d!", param); /* get array of attributes and values */ A_tab2mod(L, &attrs, param, op); param++; } A_lastattr(L, &attrs); rc = ldap_modify_ext(object->ldap, dn, attrs.attrs, NULL, NULL, &msgid); return create_future(L, rc, 1, msgid, LDAP_RES_MODIFY); } /* ldap_conn:rename(dn, new_rdn [, new_parent [, delete]]) -> future {{{1 * * Change the distinguished name of an entry. The string @dn is the * distinguished name of the entry to rename. The string @new_rdn gives the new * root distinguished name. The optional string @new_parent gives the * distinguished name of the new parent for the entry. If the optional argument * @delete is true the entry is removed from it's old parent. Returns a * function to process the LDAP result. */ static int lua_apr_ldap_rename(lua_State *L) { lua_apr_ldap_object *object; ldap_pchar_t dn, rdn, par; ldap_int_t msgid; ldap_int_t rc; int del; object = check_ldap_connection(L, 1); dn = (ldap_pchar_t) luaL_checkstring(L, 2); rdn = (ldap_pchar_t) luaL_checkstring(L, 3); par = (ldap_pchar_t) luaL_optstring(L, 4, NULL); del = luaL_optint(L, 5, 0); rc = ldap_rename(object->ldap, dn, rdn, par, del, NULL, NULL, &msgid); return create_future(L, rc, 1, msgid, LDAP_RES_MODDN); } /* tostring(ldap_conn) -> string {{{1 */ static int ldap_tostring(lua_State *L) { lua_apr_ldap_object *object; object = check_ldap_connection(L, 1); lua_pushfstring(L, "%s (%p)", lua_apr_ldap_type.friendlyname, object); return 1; } /* ldap_conn:__gc() {{{1 */ static int ldap_gc(lua_State *L) { lua_apr_ldap_object *object; object = check_ldap_connection(L, 1); if (object->ldap != NULL) { apr_pool_destroy(object->pool); object->ldap = NULL; } return 0; } /* }}}1 */ static luaL_reg ldap_metamethods[] = { { "__tostring", ldap_tostring }, { "__gc", ldap_gc }, { NULL, NULL } }; static luaL_reg ldap_methods[] = { { "bind", lua_apr_ldap_bind }, { "unbind", lua_apr_ldap_unbind }, { "option_get", lua_apr_ldap_option_get }, { "option_set", lua_apr_ldap_option_set }, # if (APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 3)) { "rebind_add", lua_apr_ldap_rebind_add }, { "rebind_remove", lua_apr_ldap_rebind_remove }, # endif { "search", lua_apr_ldap_search }, { "add", lua_apr_ldap_add }, { "compare", lua_apr_ldap_compare }, { "delete", lua_apr_ldap_delete }, { "modify", lua_apr_ldap_modify }, { "rename", lua_apr_ldap_rename }, { NULL, NULL } }; lua_apr_objtype lua_apr_ldap_type = { "lua_apr_ldap_object*", /* metatable name in registry */ "LDAP connection", /* friendly object name */ sizeof(lua_apr_ldap_object), /* structure size */ ldap_methods, /* methods table */ ldap_metamethods /* metamethods table */ }; #endif lua-apr-0.23.2.dfsg/src/lua_apr.c000066400000000000000000000324431220664456000164520ustar00rootroot00000000000000/* Miscellaneous functions module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 20, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include /* APR_HAS_LDAP */ #include #include #if LUA_APR_HAVE_APREQ #include #endif /* Used to make sure that APR is only initialized once. */ static int apr_was_initialized = 0; /* List of all userdata types exposed to Lua by the binding. */ lua_apr_objtype *lua_apr_types[] = { &lua_apr_file_type, &lua_apr_dir_type, &lua_apr_socket_type, # if APR_HAS_THREADS &lua_apr_thread_type, &lua_apr_queue_type, # endif &lua_apr_pollset_type, &lua_apr_proc_type, &lua_apr_dbm_type, &lua_apr_dbd_type, &lua_apr_dbr_type, &lua_apr_dbp_type, # if APR_HAS_LDAP &lua_apr_ldap_type, # endif #if LUA_APR_HAVE_MEMCACHE &lua_apr_memcache_type, &lua_apr_memcache_server_type, #endif &lua_apr_md5_type, &lua_apr_sha1_type, &lua_apr_xml_type, NULL }; /* luaopen_apr_core() initializes the binding and library. {{{1 */ LUA_APR_EXPORT int luaopen_apr_core(lua_State *L) { apr_status_t status; /* Table of library functions. */ luaL_Reg functions[] = { /* lua_apr.c -- miscellaneous functions. */ { "platform_get", lua_apr_platform_get }, { "version_get", lua_apr_version_get }, { "os_default_encoding", lua_apr_os_default_encoding }, { "os_locale_encoding", lua_apr_os_locale_encoding }, { "type", lua_apr_type }, { "ref", lua_apr_ref }, { "deref", lua_apr_deref }, /* base64.c -- base64 encoding/decoding. */ { "base64_encode", lua_apr_base64_encode }, { "base64_decode", lua_apr_base64_decode }, /* crypt.c -- cryptographic functions. */ { "md5_init", lua_apr_md5_init }, { "md5_encode", lua_apr_md5_encode }, { "password_get", lua_apr_password_get }, { "password_validate", lua_apr_password_validate }, { "sha1_init", lua_apr_sha1_init }, /* date.c -- date parsing. */ { "date_parse_http", lua_apr_date_parse_http }, { "date_parse_rfc", lua_apr_date_parse_rfc }, /* dbd.c -- database module. */ { "dbd", lua_apr_dbd }, /* dbm.c -- dbm routines. */ { "dbm_open", lua_apr_dbm_open }, { "dbm_getnames", lua_apr_dbm_getnames }, /* env.c -- environment variable handling. */ { "env_get", lua_apr_env_get }, { "env_set", lua_apr_env_set }, { "env_delete", lua_apr_env_delete }, /* filepath.c -- filepath manipulation. */ { "filepath_root", lua_apr_filepath_root }, { "filepath_parent", lua_apr_filepath_parent }, { "filepath_name", lua_apr_filepath_name }, { "filepath_merge", lua_apr_filepath_merge }, { "filepath_list_split", lua_apr_filepath_list_split }, { "filepath_list_merge", lua_apr_filepath_list_merge }, { "filepath_get", lua_apr_filepath_get }, { "filepath_set", lua_apr_filepath_set }, /* fnmatch.c -- filename matching. */ { "fnmatch", lua_apr_fnmatch }, { "fnmatch_test", lua_apr_fnmatch_test }, /* getopt.c -- command argument parsing. */ { "getopt", lua_apr_getopt }, # if LUA_APR_HAVE_APREQ /* http.c -- HTTP request parsing. */ { "parse_headers", lua_apr_parse_headers }, { "parse_multipart", lua_apr_parse_multipart }, { "parse_cookie_header", lua_apr_parse_cookie_header }, { "parse_query_string", lua_apr_parse_query_string }, { "header_attribute", lua_apr_header_attribute }, { "uri_encode", lua_apr_uri_encode }, { "uri_decode", lua_apr_uri_decode }, # endif /* io_dir.c -- directory manipulation. */ { "temp_dir_get", lua_apr_temp_dir_get }, { "dir_make", lua_apr_dir_make }, { "dir_make_recursive", lua_apr_dir_make_recursive }, { "dir_remove", lua_apr_dir_remove }, { "dir_remove_recursive", lua_apr_dir_remove_recursive }, { "dir_open", lua_apr_dir_open }, /* io_file.c -- file i/o handling. */ # if APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 4) { "file_link", lua_apr_file_link }, # endif { "file_copy", lua_apr_file_copy }, { "file_append", lua_apr_file_append }, { "file_rename", lua_apr_file_rename }, { "file_remove", lua_apr_file_remove }, { "file_mtime_set", lua_apr_file_mtime_set }, { "file_attrs_set", lua_apr_file_attrs_set }, { "file_perms_set", lua_apr_file_perms_set }, { "stat", lua_apr_stat }, { "file_open", lua_apr_file_open }, /* io_net.c -- network i/o handling. */ { "socket_create", lua_apr_socket_create }, { "hostname_get", lua_apr_hostname_get }, { "host_to_addr", lua_apr_host_to_addr }, { "addr_to_host", lua_apr_addr_to_host }, /* io_pipe.c -- pipe i/o handling. */ { "pipe_open_stdin", lua_apr_pipe_open_stdin }, { "pipe_open_stdout", lua_apr_pipe_open_stdout }, { "pipe_open_stderr", lua_apr_pipe_open_stderr }, { "namedpipe_create", lua_apr_namedpipe_create }, { "pipe_create", lua_apr_pipe_create }, # if APR_HAS_LDAP /* ldap.c -- LDAP connection handling. */ { "ldap", lua_apr_ldap }, { "ldap_info", lua_apr_ldap_info }, { "ldap_url_check", lua_apr_ldap_url_check }, { "ldap_url_parse", lua_apr_ldap_url_parse }, # endif /* pollset -- asynchronous network communication. */ { "pollset", lua_apr_pollset }, /* proc -- process handling. */ { "proc_create", lua_apr_proc_create }, { "proc_detach", lua_apr_proc_detach }, # if APR_HAS_FORK { "proc_fork", lua_apr_proc_fork }, # endif /* shm.c -- shared memory. */ { "shm_create", lua_apr_shm_create }, { "shm_attach", lua_apr_shm_attach }, { "shm_remove", lua_apr_shm_remove }, /* signal.c -- signal handling. */ { "signal", lua_apr_signal }, { "signal_raise", lua_apr_signal_raise }, { "signal_block", lua_apr_signal_block }, { "signal_unblock", lua_apr_signal_unblock }, { "signal_names", lua_apr_signal_names }, /* str.c -- string handling. */ { "strnatcmp", lua_apr_strnatcmp }, { "strnatcasecmp", lua_apr_strnatcasecmp }, { "strfsize", lua_apr_strfsize }, { "tokenize_to_argv", lua_apr_tokenize_to_argv }, # if APR_HAS_THREADS /* thread.c -- multi threading. */ { "thread", lua_apr_thread }, { "thread_yield", lua_apr_thread_yield }, /* thread_queue.c -- thread queues. */ { "thread_queue", lua_apr_thread_queue }, # endif /* time.c -- time management */ { "sleep", lua_apr_sleep }, { "time_now", lua_apr_time_now }, { "time_explode", lua_apr_time_explode }, { "time_implode", lua_apr_time_implode }, { "time_format", lua_apr_time_format }, /* uri.c -- URI parsing/unparsing. */ { "uri_parse", lua_apr_uri_parse }, { "uri_unparse", lua_apr_uri_unparse }, { "uri_port_of_scheme", lua_apr_uri_port_of_scheme }, /* user.c -- user/group identification. */ { "user_get", lua_apr_user_get }, { "user_homepath_get", lua_apr_user_homepath_get }, /* uuid.c -- UUID generation. */ { "uuid_get", lua_apr_uuid_get }, { "uuid_format", lua_apr_uuid_format }, { "uuid_parse", lua_apr_uuid_parse }, /* xlate.c -- character encoding translation. */ { "xlate", lua_apr_xlate }, /* xml.c -- XML parsing. */ { "xml", lua_apr_xml }, # if LUA_APR_HAVE_MEMCACHE /* memcache.c -- memcached client. */ { "memcache", lua_apr_memcache }, # endif { NULL, NULL } }; /* Initialize the library (only once per process). */ if (!apr_was_initialized) { if ((status = apr_initialize()) != APR_SUCCESS) raise_error_status(L, status); if (atexit(apr_terminate) != 0) raise_error_message(L, "Lua/APR: Failed to register apr_terminate()"); apr_was_initialized = 1; } /* Create the `scratch' memory pool for global APR functions (as opposed to * object methods) and install a __gc metamethod to detect when the Lua state * is exited. */ to_pool(L); /* Create the table of global functions. */ lua_createtable(L, 0, count(functions)); luaL_register(L, NULL, functions); /* Let callers of process:user_set() know whether it requires a password. */ lua_pushboolean(L, APR_PROCATTR_USER_SET_REQUIRES_PASSWORD); lua_setfield(L, -2, "user_set_requires_password"); /* Let callers of apr.socket_create() know whether it supports IPv6. */ lua_pushboolean(L, APR_HAVE_IPV6); lua_setfield(L, -2, "socket_supports_ipv6"); return 1; } /* apr.platform_get() -> name {{{1 * * Get the name of the platform for which the Lua/APR binding was compiled. * Returns one of the following strings: * * - `'UNIX'` * - `'WIN32'` * - `'NETWARE'` * - `'OS2'` * * Please note that the labels returned by `apr.platform_get()` don't imply * that these platforms are fully supported; the author of the Lua/APR binding * doesn't have NETWARE and OS2 environments available for testing. */ int lua_apr_platform_get(lua_State *L) { # if defined(WIN32) lua_pushstring(L, "WIN32"); # elif defined(NETWARE) lua_pushstring(L, "NETWARE"); # elif defined(OS2) lua_pushstring(L, "OS2"); # else lua_pushstring(L, "UNIX"); # endif return 1; } /* apr.version_get() -> versions_table {{{1 * * Get the versions of the libraries used by the Lua/APR binding. * Returns a table with one or more of the following fields: * * - **apr**: The version of the Apache Portable Runtime library. This field * is always available. * * - **aprutil**: The version of the APR utility library. This field is only * available when Lua/APR is compiled against APR and APR-util 1.x because * in version 2.x the utility library has been absorbed back into the APR * library; there is no longer a distinction between the APR core and APR * utility libraries. * * - **apreq**: The version of the HTTP request parsing library. This field is * only available when the libapreq2 library is installed. * * Each field is a string containing three numbers separated by dots. These * numbers have the following meaning: * * 1. Major [API] [api] changes that can cause compatibility problems between * the Lua/APR binding and APR library * * 2. Minor API changes that shouldn't impact existing functionality in the * Lua/APR binding * * 3. Used exclusively for bug fixes * * This function can be useful when you want to know whether a certain bug fix * has been applied to APR and/or APR-util or if you want to report a bug in * APR, APR-util or the Lua/APR binding. * * If you're looking for the version of the Lua/APR binding you can use the * `apr._VERSION` string, but note that Lua/APR currently does not adhere to * the above versioning rules. * * [api]: http://en.wikipedia.org/wiki/Application_programming_interface */ int lua_apr_version_get(lua_State *L) { lua_newtable(L); lua_pushstring(L, apr_version_string()); lua_setfield(L, -2, "apr"); # if APR_MAJOR_VERSION < 2 lua_pushstring(L, apu_version_string()); lua_setfield(L, -2, "aprutil"); # endif # if LUA_APR_HAVE_APREQ lua_pushstring(L, apreq_version_string()); lua_setfield(L, -2, "apreq"); # endif return 1; } /* apr.os_default_encoding() -> name {{{1 * * Get the name of the system default character set as a string. */ int lua_apr_os_default_encoding(lua_State *L) { lua_pushstring(L, apr_os_default_encoding(to_pool(L))); return 1; } /* apr.os_locale_encoding() -> name {{{1 * * Get the name of the current locale character set as a string. If the current * locale's data cannot be retrieved on this system, the name of the system * default character set is returned instead. */ int lua_apr_os_locale_encoding(lua_State *L) { lua_pushstring(L, apr_os_locale_encoding(to_pool(L))); return 1; } /* apr.type(object) -> name {{{1 * * Return the type of a userdata object created by the Lua/APR binding. If * @object is of a known type one of the following strings will be returned, * otherwise nothing is returned: * * - `'file'` * - `'directory'` * - `'socket'` * - `'thread'` * - `'process'` * - `'dbm'` * - `'database driver'` * - `'prepared statement'` * - `'result set'` * - `'memcache client'` * - `'memcache server'` * - `'md5 context'` * - `'sha1 context'` * - `'xml parser'` */ int lua_apr_type(lua_State *L) { int i; lua_settop(L, 1); luaL_checktype(L, 1, LUA_TUSERDATA); lua_getmetatable(L, 1); for (i = 0; lua_apr_types[i] != NULL; i++) { if (object_has_type(L, 1, lua_apr_types[i], 0)) { lua_pushstring(L, lua_apr_types[i]->friendlyname); return 1; } } return 0; } /* status_to_message() converts APR status codes to error messages. {{{1 */ int status_to_message(lua_State *L, apr_status_t status) { int length; char message[LUA_APR_MSGSIZE]; apr_strerror(status, message, count(message)); length = strlen(message); while (length > 0 && isspace(message[length - 1])) length--; lua_pushlstring(L, message, length); return 1; } /* push_status() returns true for APR_SUCCESS or the result of status_to_message(). {{{1 */ int push_status(lua_State *L, apr_status_t status) { if (status == APR_SUCCESS) { lua_pushboolean(L, 1); return 1; } else { return push_error_status(L, status); } } /* push_error_status() converts APR status codes to (nil, message, code). {{{1 */ int push_error_status(lua_State *L, apr_status_t status) { lua_pushnil(L); status_to_message(L, status); status_to_name(L, status); return 3; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/lua_apr.h000066400000000000000000000327661220664456000164670ustar00rootroot00000000000000/* Header file for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 20, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #ifndef LUA_APR_H #define LUA_APR_H /* Global headers. {{{1 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LUA_APR_HAVE_MEMCACHE \ (APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 3)) /* Macro definitions. {{{1 */ /* Enable redefining exporting of loader function, with sane defaults. */ #ifndef LUA_APR_EXPORT # ifdef WIN32 # define LUA_APR_EXPORT __declspec(dllexport) # else # define LUA_APR_EXPORT extern # endif #endif #define LUA_APR_POOL_KEY "Lua/APR memory pool" #define LUA_APR_POOL_MT "Lua/APR memory pool metamethods" /* FIXME Pushing onto the stack might not work in this scenario? But then what will?! */ #define error_message_memory "memory allocation error" /* Size of error message buffers on stack. */ #define LUA_APR_MSGSIZE 512 /* The initial size of I/O buffers. */ #define LUA_APR_BUFSIZE 1024 #define count(array) \ (sizeof((array)) / sizeof((array)[0])) #define filename_symbolic(S) \ ((S)[0] == '.' && ( \ (S)[1] == '\0' || ( \ (S)[1] == '.' && \ (S)[2] == '\0'))) #define raise_error_message(L, message) \ (lua_pushstring((L), (message)), lua_error((L))) #define raise_error_status(L, status) \ (status_to_message((L), (status)), lua_error((L))) #define raise_error_memory(L) \ raise_error_message((L), (error_message_memory)) #define push_error_message(L, message) \ (lua_pushnil((L)), lua_pushstring((L), (message)), 2) #define push_error_memory(L) \ push_error_message((L), (error_message_memory)) #define time_get(L, idx) \ ((apr_time_t) (lua_tonumber(L, idx) * APR_USEC_PER_SEC)) #define time_put(L, time) \ lua_pushnumber(L, (lua_Number)time / APR_USEC_PER_SEC) #define push_string_or_true(L, s) \ (s != NULL && s[0] != '\0' ? lua_pushstring(L, s) : lua_pushboolean(L, 1)) /* Debugging aids. {{{1 */ #include /* Capture debug mode in a compile time conditional. */ #ifdef DEBUG #define DEBUG_TEST 1 #else #define DEBUG_TEST 0 #endif /* Used in I/O buffer handling. */ #ifndef APR_SIZE_MAX #define APR_SIZE_MAX SIZE_MAX #endif /* Enable printing messages to stderr in debug mode, but always compile * the code so that it's syntax checked even when debug mode is off. */ #define LUA_APR_DBG(MSG, ...) do { \ if (DEBUG_TEST) { \ fprintf(stderr, " *** " MSG "\n", __VA_ARGS__); \ fflush(stderr); \ } \ } while (0) /* Since I don't use the MSVC++ IDE I can't set breakpoints without this :-) */ #define LUA_APR_BRK() do { \ if (DEBUG_TEST) \ *((int*)0) = 1; \ } while (0) /* Dump the state of the Lua stack. */ #define LUA_APR_DUMP_STACK(L, LABEL) do { \ int i, top = lua_gettop(L); \ LUA_APR_DBG("%s: %i", LABEL, top); \ for (i = 1; i <= top; i++) { \ switch (lua_type(L, i)) { \ case LUA_TNIL: LUA_APR_DBG(" %i: nil", i); break; \ case LUA_TBOOLEAN: LUA_APR_DBG(" %i: boolean %s", i, lua_toboolean(L, i) ? "true" : "false"); \ case LUA_TNUMBER: LUA_APR_DBG(" %i: number %f", i, lua_tonumber(L, i)); break; \ case LUA_TSTRING: LUA_APR_DBG(" %i: string \"%.*s\"", i, lua_objlen(L, i), lua_tostring(L, i)); break; \ default: LUA_APR_DBG(" %i: %s (%p)", i, luaL_typename(L, i), lua_topointer(L, i)); break; \ } \ } \ } while (0) /* Type definitions. {{{1 */ /* Reference counted Lua objects. */ typedef struct lua_apr_refobj lua_apr_refobj; struct lua_apr_refobj { lua_apr_refobj *reference; volatile apr_uint32_t refcount; int unmanaged; }; /* Reference counted APR memory pool. */ typedef struct { apr_pool_t *ptr; int refs; } lua_apr_pool; /* Context structure for stat() calls. */ typedef struct { apr_int32_t wanted; apr_finfo_t info; apr_int32_t fields[15]; int firstarg, lastarg, count; } lua_apr_stat_context; /* The calling convention for APR functions and callbacks. On Windows this * means __stdcall and omitting it can cause nasty stack corruption! */ #define lua_apr_cc APR_THREAD_FUNC /* Type definitions used to call APR functions through function pointers. */ typedef apr_status_t (lua_apr_cc *lua_apr_buf_rf)(void*, char*, apr_size_t*); typedef apr_status_t (lua_apr_cc *lua_apr_buf_wf)(void*, const char*, apr_size_t*); typedef apr_status_t (lua_apr_cc *lua_apr_buf_ff)(void*); typedef apr_status_t (lua_apr_cc *lua_apr_openpipe_f)(apr_file_t**, apr_pool_t*); typedef apr_status_t (lua_apr_cc *lua_apr_setpipe_f)(apr_procattr_t*, apr_file_t*, apr_file_t*); /* Structures for (buffered) I/O streams. */ typedef struct { int unmanaged; size_t index, limit, size; char *data; } lua_apr_buffer; typedef struct { int text_mode; void *object; lua_apr_buf_rf read; lua_apr_buffer buffer; } lua_apr_readbuf; typedef struct { int text_mode; void *object; lua_apr_buf_wf write; lua_apr_buf_ff flush; lua_apr_buffer buffer; } lua_apr_writebuf; /* Structure for file objects. */ typedef struct { lua_apr_refobj header; lua_apr_readbuf input; lua_apr_writebuf output; apr_file_t *handle; lua_apr_pool *pool; const char *path; } lua_apr_file; /* Structure for socket objects. */ typedef struct { lua_apr_refobj header; lua_apr_readbuf input; lua_apr_writebuf output; apr_pool_t *pool; apr_socket_t *handle; int family, protocol; } lua_apr_socket; /* Structure used to define Lua userdata types created by Lua/APR. */ typedef struct { const char *typename, *friendlyname; const size_t objsize; luaL_Reg *methods; luaL_Reg *metamethods; } lua_apr_objtype; /* External type definitions. */ extern lua_apr_objtype *lua_apr_types[]; extern lua_apr_objtype lua_apr_file_type; extern lua_apr_objtype lua_apr_dir_type; extern lua_apr_objtype lua_apr_socket_type; extern lua_apr_objtype lua_apr_thread_type; extern lua_apr_objtype lua_apr_queue_type; extern lua_apr_objtype lua_apr_pollset_type; extern lua_apr_objtype lua_apr_proc_type; extern lua_apr_objtype lua_apr_shm_type; extern lua_apr_objtype lua_apr_dbm_type; extern lua_apr_objtype lua_apr_dbd_type; extern lua_apr_objtype lua_apr_dbr_type; extern lua_apr_objtype lua_apr_dbp_type; extern lua_apr_objtype lua_apr_md5_type; extern lua_apr_objtype lua_apr_sha1_type; extern lua_apr_objtype lua_apr_xml_type; #if LUA_APR_HAVE_MEMCACHE extern lua_apr_objtype lua_apr_memcache_type; extern lua_apr_objtype lua_apr_memcache_server_type; #endif extern lua_apr_objtype lua_apr_ldap_type; /* Prototypes. {{{1 */ /* lua_apr.c */ int lua_apr_platform_get(lua_State*); int lua_apr_version_get(lua_State*); int lua_apr_os_default_encoding(lua_State*); int lua_apr_os_locale_encoding(lua_State*); int lua_apr_type(lua_State*); int status_to_message(lua_State*, apr_status_t); int push_status(lua_State*, apr_status_t); int push_error_status(lua_State*, apr_status_t); /* base64.c */ int lua_apr_base64_encode(lua_State*); int lua_apr_base64_decode(lua_State*); /* buffer.c */ void init_buffers(lua_State*, lua_apr_readbuf*, lua_apr_writebuf*, void*, int, lua_apr_buf_rf, lua_apr_buf_wf, lua_apr_buf_ff); void init_unmanaged_buffers(lua_State*, lua_apr_readbuf*, lua_apr_writebuf*, char*, size_t); int read_lines(lua_State*, lua_apr_readbuf*); int read_buffer(lua_State*, lua_apr_readbuf*); int write_buffer(lua_State*, lua_apr_writebuf*); apr_status_t flush_buffer(lua_State*, lua_apr_writebuf*, int); void free_buffer(lua_State*, lua_apr_buffer*); /* crypt.c */ int lua_apr_md5_init(lua_State*); int lua_apr_md5_encode(lua_State*); int lua_apr_sha1_init(lua_State*); int lua_apr_password_validate(lua_State*); int lua_apr_password_get(lua_State*); /* date.c */ int lua_apr_date_parse_http(lua_State*); int lua_apr_date_parse_rfc(lua_State*); /* dbd.c */ int lua_apr_dbd(lua_State*); /* dbm.c */ int lua_apr_dbm_open(lua_State*); int lua_apr_dbm_getnames(lua_State*); /* env.c */ int lua_apr_env_get(lua_State*); int lua_apr_env_set(lua_State*); int lua_apr_env_delete(lua_State*); /* errno.c */ void status_to_name(lua_State*, apr_status_t); /* filepath.c */ int lua_apr_filepath_root(lua_State*); int lua_apr_filepath_parent(lua_State*); int lua_apr_filepath_name(lua_State*); int lua_apr_filepath_merge(lua_State*); int lua_apr_filepath_list_split(lua_State*); int lua_apr_filepath_list_merge(lua_State*); int lua_apr_filepath_get(lua_State*); int lua_apr_filepath_set(lua_State*); /* fnmatch.c */ int lua_apr_fnmatch(lua_State*); int lua_apr_fnmatch_test(lua_State*); /* getopt.c */ int lua_apr_getopt(lua_State*); /* http.c */ int lua_apr_parse_headers(lua_State*); int lua_apr_parse_multipart(lua_State*); int lua_apr_parse_cookie_header(lua_State*); int lua_apr_parse_query_string(lua_State*); int lua_apr_header_attribute(lua_State*); int lua_apr_uri_encode(lua_State*); int lua_apr_uri_decode(lua_State*); /* io_dir.c */ int lua_apr_temp_dir_get(lua_State*); int lua_apr_dir_make(lua_State*); int lua_apr_dir_make_recursive(lua_State*); int lua_apr_dir_remove(lua_State*); int lua_apr_dir_remove_recursive(lua_State*); int lua_apr_dir_open(lua_State*); /* io_file.c */ int lua_apr_file_link(lua_State*); int lua_apr_file_copy(lua_State*); int lua_apr_file_append(lua_State*); int lua_apr_file_rename(lua_State*); int lua_apr_file_remove(lua_State*); int lua_apr_file_mtime_set(lua_State*); int lua_apr_file_attrs_set(lua_State*); int lua_apr_file_perms_set(lua_State*); int lua_apr_stat(lua_State*); int lua_apr_file_open(lua_State*); lua_apr_file *file_alloc(lua_State*, const char*, lua_apr_pool*); void init_file_buffers(lua_State*, lua_apr_file*, int); lua_apr_file *file_check(lua_State*, int, int); apr_status_t file_close_impl(lua_State*, lua_apr_file*); /* io_net.c */ int lua_apr_socket_create(lua_State*); int lua_apr_hostname_get(lua_State*); int lua_apr_host_to_addr(lua_State*); int lua_apr_addr_to_host(lua_State*); /* io_pipe.c */ int lua_apr_pipe_open_stdin(lua_State*); int lua_apr_pipe_open_stdout(lua_State*); int lua_apr_pipe_open_stderr(lua_State*); int lua_apr_namedpipe_create(lua_State*); int lua_apr_pipe_create(lua_State*); /* ldap.c */ int lua_apr_ldap(lua_State*); int lua_apr_ldap_info(lua_State*); int lua_apr_ldap_url_check(lua_State*); int lua_apr_ldap_url_parse(lua_State*); /* memory_pool.c */ apr_pool_t *to_pool(lua_State*); /* object.c */ void *new_object(lua_State*, lua_apr_objtype*); void *prepare_reference(lua_apr_objtype*, lua_apr_refobj*); void create_reference(lua_State*, lua_apr_objtype*, lua_apr_refobj*); void init_object(lua_State*, lua_apr_objtype*); int object_collectable(lua_apr_refobj*); void release_object(lua_apr_refobj*); void object_env_default(lua_State*); int object_env_private(lua_State*, int); int object_has_type(lua_State*, int, lua_apr_objtype*, int); int objects_equal(lua_State*); void *check_object(lua_State*, int, lua_apr_objtype*); int get_metatable(lua_State*, lua_apr_objtype*); void object_incref(lua_apr_refobj*); int object_decref(lua_apr_refobj*); lua_apr_pool *refpool_alloc(lua_State*); apr_pool_t* refpool_incref(lua_apr_pool*); void refpool_decref(lua_apr_pool*); int lua_apr_ref(lua_State*); int lua_apr_deref(lua_State*); /* permissions.c */ int push_protection(lua_State*, apr_fileperms_t); apr_fileperms_t check_permissions(lua_State*, int, int); /* pollset.c */ int lua_apr_pollset(lua_State*); /* proc.c */ int lua_apr_proc_create(lua_State*); int lua_apr_proc_detach(lua_State*); int lua_apr_proc_fork(lua_State*); /* serialize.c */ int lua_apr_ref(lua_State*); int lua_apr_deref(lua_State*); int lua_apr_serialize(lua_State*, int); int lua_apr_unserialize(lua_State*); /* stat.c */ void check_stat_request(lua_State*, lua_apr_stat_context*); int push_stat_results(lua_State*, lua_apr_stat_context*, const char*); /* shm.c */ int lua_apr_shm_create(lua_State*); int lua_apr_shm_attach(lua_State*); int lua_apr_shm_remove(lua_State*); /* signal.c */ int lua_apr_signal(lua_State*); int lua_apr_signal_raise(lua_State*); int lua_apr_signal_block(lua_State*); int lua_apr_signal_unblock(lua_State*); int lua_apr_signal_names(lua_State*); /* str.c */ int lua_apr_strnatcmp(lua_State*); int lua_apr_strnatcasecmp(lua_State*); int lua_apr_strfsize(lua_State*); int lua_apr_tokenize_to_argv(lua_State*); /* thread.c */ int lua_apr_thread(lua_State*); int lua_apr_thread_yield(lua_State*); /* thread_queue.c */ int lua_apr_thread_queue(lua_State*); /* time.c */ int lua_apr_sleep(lua_State*); int lua_apr_time_now(lua_State*); int lua_apr_time_explode(lua_State*); int lua_apr_time_implode(lua_State*); int lua_apr_time_format(lua_State*); apr_time_t time_check(lua_State*, int); int time_push(lua_State*, apr_time_t); /* uri.c */ int lua_apr_uri_parse(lua_State*); int lua_apr_uri_unparse(lua_State*); int lua_apr_uri_port_of_scheme(lua_State*); /* user.c */ int lua_apr_user_get(lua_State*); int lua_apr_user_homepath_get(lua_State*); int push_username(lua_State*, apr_pool_t*, apr_uid_t); int push_groupname(lua_State*, apr_pool_t*, apr_gid_t); /* uuid.c */ int lua_apr_uuid_get(lua_State*); int lua_apr_uuid_format(lua_State*); int lua_apr_uuid_parse(lua_State*); /* xlate.c */ int lua_apr_xlate(lua_State*); /* xml.c */ int lua_apr_xml(lua_State*); /* memcache */ #if LUA_APR_HAVE_MEMCACHE int lua_apr_memcache(lua_State *L); #endif #endif /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/memcache.c000066400000000000000000000442041220664456000165670ustar00rootroot00000000000000/* Memcached client module for the Lua/APR binding. * * Authors: * - zhiguo zhao * - Peter Odding * Last Change: November 4, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * [Memcached] [memcached] is a "distributed memory object caching system". * It's designed as an in-memory key-value store for small chunks of arbitrary * data (strings, objects) from results of database calls, API calls, or page * rendering. The memcached client module makes it possible to read from and * write to one or more memcached servers over a network socket in Lua. * * To-do: Find out if "flags" can be any 32 bits value and how useful it is * to Lua. * * [memcached]: http://memcached.org/ */ #include "lua_apr.h" #if LUA_APR_HAVE_MEMCACHE #include #include typedef struct { lua_apr_refobj header; apr_memcache_t *client; apr_pool_t *memory_pool; } lua_apr_memcache_object; typedef struct { lua_apr_refobj header; apr_memcache_server_t *server; } lua_apr_memcache_server_object; static const apr_uint32_t mc_default_timeout = 60; /* seconds */ /* Macros. {{{1 */ #define check_mc_client(L, idx) \ ((lua_apr_memcache_object*)check_object(L, idx, &lua_apr_memcache_type))->client #define check_mc_server(L, idx) \ ((lua_apr_memcache_server_object*)check_object(L, idx, &lua_apr_memcache_server_type))->server /* apr.memcache([max_servers]) -> mc_client {{{1 * * Create a memcached client. The optional argument @max_servers determines the * maximum number of memcached servers supported by the client (defaults to * 10). On success the client object is returned, otherwise nil followed by an * error message is returned. */ int lua_apr_memcache(lua_State *L) { apr_status_t status; lua_apr_memcache_object *object; int max_servers; max_servers = luaL_optint(L, 1, 10); object = new_object(L, &lua_apr_memcache_type); status = apr_pool_create(&object->memory_pool, NULL); if (status == APR_SUCCESS) { status = apr_memcache_create(object->memory_pool, max_servers, 0, &object->client); if (status == APR_SUCCESS) return 1; apr_pool_destroy(object->memory_pool); object->memory_pool = NULL; } return push_error_status(L, status); } /* mc_client:hash(str) -> hash {{{1 * * Create a [CRC32] [crc] hash used to split keys between servers. * The hash is not compatible with old memcached clients. * * [crc]: http://en.wikipedia.org/wiki/Cyclic_redundancy_check */ static int mc_hash(lua_State *L) { apr_memcache_t *client; const char *data; size_t length; client = check_mc_client(L, 1); data = luaL_checklstring(L, 2, &length); lua_pushinteger(L, apr_memcache_hash(client, data, length)); return 1; } /* mc_client:find_server_hash(hash) -> mc_server {{{1 * * Picks a server based on a hash. Returns the info of the server that controls * the specified hash. */ static int mc_find_server_hash(lua_State *L) { apr_memcache_t *client; apr_memcache_server_t *server; apr_uint32_t hash; lua_apr_memcache_server_object *object; client = check_mc_client(L, 1); hash = luaL_checkint(L, 2); server = apr_memcache_find_server_hash(client, hash); if (server == NULL) return 0; object = new_object(L, &lua_apr_memcache_server_type); object->server = server; return 1; } /* mc_client:add_server(host, port [, min [, smax [, max [, ttl]]]]) -> mc_server {{{1 * * Create a new server object and add it to the client object. On success the * server object is returned, otherwise a nil followed by an error message is * returned. The parameters have the following meaning: * * - @host: hostname of server * - @port: port of server (usually 11211) * - @min: minimum number of client sockets to open (defaults to 0) * - @smax: soft maximum number of client connections to open (defaults to 1) * - @max: hard maximum number of client connections (defaults to 1) * - @ttl: time to live in microseconds of a client connection (defaults to 60000) * * Note that @min, @smax and @max are only used when APR was compiled with * threads. Also a word of caution: Changing servers after startup may cause * keys to go to different servers. */ static int mc_add_server(lua_State *L) { apr_memcache_t *client; apr_memcache_server_t *server; apr_status_t status = APR_SUCCESS; lua_apr_memcache_server_object *object; client = check_mc_client(L, 1); if (lua_isuserdata(L, 2)) { server = check_mc_server(L, 2); } else { const char* host = luaL_checkstring(L, 2); int port = luaL_checkint(L, 3); int min = luaL_optint(L, 4, 0); int smax = luaL_optint(L, 5, 1); int max = luaL_optint(L, 6, 1); int ttl = luaL_optint(L, 7, 60000); /* 1 minute, 60 second, */ status = apr_memcache_server_create(client->p, host, port, min, smax, max, ttl, &server); } if (status == APR_SUCCESS) { status = apr_memcache_add_server(client, server); if (status == APR_SUCCESS) { object = new_object(L, &lua_apr_memcache_server_type); object->server = server; return 1; } } return push_error_status(L, status); } /* mc_client:find_server(host, port) -> mc_server {{{1 * * Finds a server object based on a (hostname, port) pair. On success the * server with matching host name and port is returned, otherwise nothing is * returned. */ static int mc_find_server(lua_State *L) { apr_memcache_t *client; const char* host; apr_port_t port; apr_memcache_server_t *server; lua_apr_memcache_server_object *object; client = check_mc_client(L, 1); host = luaL_checkstring(L, 2); port = (apr_port_t)luaL_checkint(L, 3); server = apr_memcache_find_server(client, host, port); if (server == NULL) return 0; object = new_object(L, &lua_apr_memcache_server_type); object->server = server; return 1; } /* mc_client:enable_server(mc_server) -> status {{{1 * * Enable a server for use again after disabling the server with * `mc_client:disable_server()`. On success true is returned, * otherwise nil followed by an error message is returned. */ static int mc_enable_server(lua_State *L) { apr_memcache_t *client; apr_memcache_server_t *server; apr_status_t status; client = check_mc_client(L, 1); server = check_mc_server(L, 2); status = apr_memcache_enable_server(client, server); return push_status(L, status); } /* mc_client:disable_server(mc_server) -> status {{{1 * * Disable a server. On success true is returned, otherwise nil followed by an * error message is returned. */ static int mc_disable_server(lua_State *L) { apr_memcache_t *client; apr_memcache_server_t *server; apr_status_t status; client = check_mc_client(L, 1); server = check_mc_server(L, 2); status = apr_memcache_disable_server(client, server); return push_status(L, status); } /* mc_client:get(key [, ...]) -> status, value [, ...] {{{1 * * Get one or more values from the server. On success true is returned followed * by the retrieved value(s), otherwise nil followed by an error message is * returned. The keys are null terminated strings and the return values are * binary safe strings. Keys that don't have an associated value result in nil. */ static int mc_get(lua_State *L) { apr_memcache_t *client; apr_status_t status; const char *key; apr_size_t len; char *value; int i, argc; client = check_mc_client(L, 1); argc = lua_gettop(L); lua_pushboolean(L, 1); for (i = 2; i <= argc; i++) { key = luaL_checkstring(L, i); status = apr_memcache_getp(client, client->p, key, &value, &len, NULL); if (status == APR_SUCCESS) { lua_pushlstring(L, value, len); } else if (APR_STATUS_IS_NOTFOUND(status)) { lua_pushnil(L); } else { lua_settop(L, argc); push_error_status(L, status); } } return lua_gettop(L) - argc; } /* mc_client:set(key, value [, timeout]) -> status {{{1 * * Sets a value by key on the server. If the key already exists the old value * will be overwritten. The @key is a null terminated string, the @value is a * binary safe string and @timeout is the time in seconds for the data to live * on the server (a number, defaults to 60 seconds). On success true is * returned, otherwise nil followed by an error message is returned. */ static int mc_set(lua_State *L) { apr_memcache_t *client; const char *key, *value; apr_size_t len; apr_uint32_t timeout; apr_status_t status; client = check_mc_client(L, 1); key = luaL_checkstring(L, 2); value = luaL_checklstring(L, 3, &len); timeout = luaL_optint(L, 4, mc_default_timeout); status = apr_memcache_set(client, key, (char*)value, len, timeout, 0); return push_status(L, status); } /* mc_client:add(key, value [, timeout]) -> status {{{1 * * Adds a value by key on the server. If the key already exists this call will * fail and the old value will be preserved. The arguments and return values * are documented under `mc_client:set()`. */ static int mc_add(lua_State *L) { apr_memcache_t *client; const char* key, *value; apr_uint32_t timeout; apr_status_t status; apr_size_t len; client = check_mc_client(L, 1); key = luaL_checkstring(L, 2); value = luaL_checklstring(L, 3, &len); timeout = luaL_optint(L, 4, mc_default_timeout); status = apr_memcache_add(client, key, (char*)value, len, timeout, 0); return push_status(L, status); } /* mc_client:replace(key, value [, timeout]) -> status {{{1 * * Replace a value by key on the server. If the key doesn't exist no value will * be set. The arguments and return values are documented under * `mc_client:set()`. */ static int mc_replace(lua_State *L) { apr_memcache_t *client; const char* key, *value; apr_uint32_t timeout; apr_status_t status; apr_size_t len; client = check_mc_client(L, 1); key = luaL_checkstring(L, 2); value = luaL_checklstring(L, 3, &len); timeout = luaL_optint(L, 4, mc_default_timeout); status = apr_memcache_replace(client, key, (char*)value, len, timeout, 0); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, value, len); return 1; } /* mc_client:delete(key [, timeout]) -> status {{{1 * * Delete a key from the server. The @key is a null terminated string and * @timeout is the time in seconds for the delete to stop other clients from * adding (a number, defaults to 10 seconds). On success true is returned, * otherwise nil followed by an error message is returned. */ static int mc_delete(lua_State *L) { apr_memcache_t *client; const char* key; apr_uint32_t timeout; apr_status_t status; client = check_mc_client(L, 1); key = luaL_checkstring(L, 2); timeout = luaL_optint(L, 3, 10); status = apr_memcache_delete(client, key, timeout); return push_status(L, status); } /* mc_client:incr(key [, number]) -> value {{{1 * * Increment a value. The @key is a null terminated string and the optional * argument @number is the number to increment by (defaults to 1). On success * the new value after incrementing is returned, otherwise nil followed by an * error message is returned. */ static int mc_incr(lua_State *L) { apr_memcache_t *client; const char* key; apr_uint32_t increment_by, resulting_value; apr_status_t status; client = check_mc_client(L, 1); key = luaL_checkstring(L, 2); increment_by = luaL_optint(L, 3, 1); status = apr_memcache_incr(client, key, increment_by, &resulting_value); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushinteger(L, resulting_value); return 1; } /* mc_client:decr(key [, number]) -> value {{{1 * * Decrement a value. The @key is a null terminated string and the optional * argument @number is the number to decrement by (defaults to 1). On success * the new value after decrementing is returned, otherwise nil followed by an * error message is returned. */ static int mc_decr(lua_State *L) { apr_memcache_t *client; const char* key; apr_uint32_t decrement_by, resulting_value; apr_status_t status; client = check_mc_client(L, 1); key = luaL_checkstring(L, 2); decrement_by = luaL_checkint(L, 3); status = apr_memcache_decr(client, key, decrement_by, &resulting_value); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushinteger(L, resulting_value); return 1; } /* mc_client:version(mc_server) -> version {{{1 * * Query a server's version. On success the version string is returned, * otherwise nil followed by an error message is returned. */ static int mc_version(lua_State *L) { apr_memcache_server_t *server; apr_status_t status; char* value; size_t length; (void)check_mc_client(L, 1); server = check_mc_server(L, 2); status = apr_memcache_version(server, server->p, &value); if (status != APR_SUCCESS) return push_error_status(L, status); length = strlen(value); while (apr_isspace(value[length - 1])) length--; lua_pushlstring(L, value, length); return 1; } /* mc_client:stats() -> statistics {{{1 * * Query a server for statistics. On success a table with information is * returned, otherwise nil followed by an error message is returned. The * following fields are supported: * * - @version: version string of the server * - @pid: process ID of the server process * - @uptime: number of seconds this server has been running * - @time: current UNIX time according to the server * - @rusage_user: accumulated user time for this process * - @rusage_system: accumulated system time for this process * - @curr_items: current number of items stored by the server * - @total_items: total number of items stored by this server * - @bytes: current number of bytes used by this server to store items * - @curr_connections: number of open connections * - @total_connections: total number of connections opened since the server started running * - @connection_structures: number of connection structures allocated by the server * - @cmd_get: cumulative number of retrieval requests * - @cmd_set: Cumulative number of storage requests * - @get_hits: number of keys that have been requested and found present * - @get_misses: number of items that have been requested and not found * - @evictions: number of items removed from cache because they passed their expiration time * - @bytes_read: total number of bytes read by this server * - @bytes_written: total number of bytes sent by this server * - @limit_maxbytes: number of bytes this server is allowed to use for storage * - @threads: number of threads the server is running (if built with threading) */ static int mc_stats(lua_State *L) { apr_memcache_server_t *server; apr_memcache_stats_t *stats; apr_status_t status; (void)check_mc_client(L, 1); server = check_mc_server(L, 2); status = apr_memcache_stats(server, server->p, &stats); if (status != APR_SUCCESS) return push_error_status(L, status); lua_newtable(L); lua_pushstring(L, stats->version); lua_setfield(L, -2, "version"); # define setstat(key, value) \ (lua_pushnumber(L, (lua_Number) value), lua_setfield(L, -2, key)) setstat("pid", stats->pid); setstat("uptime", stats->uptime); setstat("time", stats->time); setstat("rusage_user", stats->rusage_user); setstat("rusage_system", stats->rusage_system); setstat("curr_items", stats->curr_items); setstat("total_items", stats->total_items); setstat("bytes", stats->bytes); setstat("curr_connections", stats->curr_connections); setstat("total_connections", stats->total_connections); setstat("connection_structures", stats->connection_structures); setstat("cmd_get", stats->cmd_get); setstat("cmd_set", stats->cmd_set); setstat("get_hits", stats->get_hits); setstat("get_misses", stats->get_misses); setstat("evictions", stats->evictions); setstat("bytes_read", stats->bytes_read); setstat("bytes_written", stats->bytes_written); setstat("limit_maxbytes", stats->limit_maxbytes); setstat("threads", stats->threads); return 1; } /* tostring(mc_client) -> string {{{1 */ static int mc_tostring(lua_State *L) { lua_apr_memcache_object *object; object = check_object(L, 1, &lua_apr_memcache_type); lua_pushfstring(L, "%s (%p)", lua_apr_memcache_type.friendlyname, object->client); return 1; } /* tostring(mc_server) -> string {{{1 */ static int ms_tostring(lua_State *L) { lua_apr_memcache_server_object *object; object = check_object(L, 1, &lua_apr_memcache_server_type); lua_pushfstring(L, "%s (%p)", lua_apr_memcache_server_type.friendlyname, object->server); return 1; } /* mc_client:__gc() {{{1 */ static int mc_gc(lua_State *L) { lua_apr_memcache_object *object; object = check_object(L, 1, &lua_apr_memcache_type); if (object->memory_pool != NULL) { apr_pool_destroy(object->memory_pool); object->memory_pool = NULL; } return 0; } /* Internal object definitions. {{{1 */ static luaL_reg mc_methods[] = { { "hash", mc_hash }, { "find_server_hash", mc_find_server_hash }, { "add_server", mc_add_server }, { "find_server", mc_find_server }, { "enable_server", mc_enable_server }, { "disable_server", mc_disable_server }, { "get", mc_get }, { "set", mc_set }, { "add", mc_add }, { "replace", mc_replace }, { "delete", mc_delete }, { "incr", mc_incr }, { "decr", mc_decr }, { "version", mc_version }, { "stats", mc_stats }, { NULL, NULL } }; static luaL_reg mc_metamethods[] = { { "__tostring", mc_tostring }, { "__gc", mc_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_memcache_type = { "lua_apr_memcache_t*", /* metatable name in registry */ "memcache client", /* friendly object name */ sizeof(lua_apr_memcache_object), /* structure size */ mc_methods, /* methods table */ mc_metamethods /* metamethods table */ }; static luaL_reg ms_methods[] = { { NULL, NULL } }; static luaL_reg ms_metamethods[] = { { "__tostring", ms_tostring }, { NULL, NULL } }; lua_apr_objtype lua_apr_memcache_server_type = { "lua_apr_memcache_server_t*", /* metatable name in registry */ "memcache server", /* friendly object name */ sizeof(lua_apr_memcache_server_object), /* structure size */ ms_methods, /* methods table */ ms_metamethods /* metamethods table */ }; #endif /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/memory_pool.c000066400000000000000000000101241220664456000173600ustar00rootroot00000000000000/* Global memory pool handling for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 28, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Most functions in APR and APR-util require a memory pool argument to perform * memory allocation. Object methods in Lua/APR generally use the memory pool * associated with the object (such memory pools are destroyed when the object * userdata is garbage collected). For standalone functions Lua/APR uses a * global memory pool stored in the registry of the Lua state. This source file * implements the global memory pool. */ #include "lua_apr.h" typedef struct { apr_pool_t *pool; int managed; /* should be cleared/destroyed by Lua/APR? */ } global_pool; static apr_pool_t *pool_register(lua_State*, apr_pool_t*, int); static int pool_gc(lua_State*); /* to_pool() - Get the global memory pool (creating or clearing it). {{{1 */ apr_pool_t *to_pool(lua_State *L) { global_pool *reference; apr_pool_t *memory_pool; apr_status_t status; luaL_checkstack(L, 1, "not enough stack space to get memory pool"); lua_getfield(L, LUA_REGISTRYINDEX, LUA_APR_POOL_KEY); if (!lua_isuserdata(L, -1)) { /* Pop the nil value from lua_getfield(). */ lua_pop(L, 1); /* Create the memory pool itself. */ status = apr_pool_create(&memory_pool, NULL); if (status != APR_SUCCESS) raise_error_status(L, status); /* Create a reference to the memory pool in the Lua state. */ (void) pool_register(L, memory_pool, 1); } else { /* Return the previously created global memory pool. */ reference = lua_touserdata(L, -1); memory_pool = reference->pool; /* Clear it when we're allowed to do so. */ if (reference->managed) apr_pool_clear(memory_pool); lua_pop(L, 1); } return memory_pool; } /* pool_register() - Initialize or replace the global memory pool. {{{1 */ apr_pool_t *pool_register(lua_State *L, apr_pool_t *new_pool, int managed) { apr_pool_t *old_pool = NULL; global_pool *reference; /* Get the old global memory pool (if any). */ lua_getfield(L, LUA_REGISTRYINDEX, LUA_APR_POOL_KEY); if (lua_isuserdata(L, -1)) { reference = lua_touserdata(L, -1); old_pool = reference->pool; /* We don't need this userdata on the stack. */ lua_pop(L, 1); } else { /* Pop the nil value from lua_getfield(). */ lua_pop(L, 1); /* Create the reference to the global memory pool. */ reference = lua_newuserdata(L, sizeof *reference); reference->managed = managed; /* Create and install a metatable for garbage collection. */ if (luaL_newmetatable(L, LUA_APR_POOL_MT)) { /* The metatable has not yet been initialized. */ lua_pushcfunction(L, pool_gc); lua_setfield(L, -2, "__gc"); } lua_setmetatable(L, -2); /* Add the reference tot the Lua registry (popping it from the stack). */ lua_setfield(L, LUA_REGISTRYINDEX, LUA_APR_POOL_KEY); } /* Should we change the memory pool? */ if (new_pool != old_pool) { /* Just in case lua_apr_pool_register() is ever called after the global * memory pool has already been created. */ if (reference->managed && old_pool != NULL) { /* Destroy the old _managed_ memory pool. */ apr_pool_destroy(old_pool); /* Don't return it to the caller though. */ old_pool = NULL; } /* Set the reference to the new pool. */ reference->pool = new_pool; } /* Always set the managed field. */ reference->managed = managed; /* Return the old memory pool (if any) in case * the caller created it and wants it back :-) */ return old_pool; } /* pool_gc() - Destroy the global memory pool automatically. {{{1 */ int pool_gc(lua_State *L) { global_pool *reference; reference = luaL_checkudata(L, 1, LUA_APR_POOL_MT); if (reference->managed) apr_pool_destroy(reference->pool); return 0; } /* lua_apr_pool_register() - Enable others to replace the global memory pool (e.g. mod_lua). {{{1 */ LUA_APR_EXPORT apr_pool_t *lua_apr_pool_register(lua_State *L, apr_pool_t *new_pool) { return pool_register(L, new_pool, 0); } lua-apr-0.23.2.dfsg/src/object.c000066400000000000000000000172251220664456000162760ustar00rootroot00000000000000/* Object model for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 20, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" static lua_apr_refobj *root_object(lua_apr_refobj *object) { while (object->reference != NULL) object = object->reference; return object; } /* new_object() {{{1 * * Allocate and initialize an object of the given type as a Lua userdata with * a metatable, returning the address of the userdata. */ void *new_object(lua_State *L, lua_apr_objtype *T) { lua_apr_refobj *object = lua_newuserdata(L, T->objsize); memset(object, 0, T->objsize); object->reference = NULL; object->refcount = 1; object->unmanaged = 0; init_object(L, T); return object; } /* prepare_reference() {{{1 * * Prepare an object for being referenced from multiple operating system * threads and/or Lua states by moving the object to unmanaged memory and * turning the original object into a reference to the object in unmanaged * memory. Returns the address of the object in unmanaged memory. * * XXX Note that this does not change the reference count! */ void *prepare_reference(lua_apr_objtype *T, lua_apr_refobj *object) { object = root_object(object); if (object->reference == NULL && !object->unmanaged) { lua_apr_refobj *clone = malloc(T->objsize); if (clone == NULL) return NULL; memcpy(clone, object, T->objsize); apr_atomic_set32(&clone->refcount, 1); clone->unmanaged = 1; object->reference = clone; object = clone; } return object; } /* create_reference() {{{1 * * Create an object of the given type which references another object. * * XXX Note that this does not increment the reference count! */ void create_reference(lua_State *L, lua_apr_objtype *T, lua_apr_refobj *original) { lua_apr_refobj *reference; /* Objects are never moved back from unmanaged to managed memory so we don't * need to allocate a full structure here; we only need the fields defined in * the lua_apr_refobj structure. */ reference = lua_newuserdata(L, sizeof *reference); reference->reference = root_object(original); reference->unmanaged = 0; init_object(L, T); } /* init_object() {{{1 * * Install a metatable and environment table on the Lua userdata at the top of * the Lua stack. */ void init_object(lua_State *L, lua_apr_objtype *T) { get_metatable(L, T); lua_setmetatable(L, -2); object_env_default(L); lua_setfenv(L, -2); } /* object_collectable() {{{1 * * Check whether an object can be destroyed (if the reference count is more * than one the object should not be destroyed, instead just the reference * should be garbage collected). * * XXX Even though object_incref() and object_decref() use atomic operations * this function can break the atomicity; it promises something it doesn't * control. Whether this can be a problem in practice, I don't know... */ int object_collectable(lua_apr_refobj *object) { object = root_object(object); return apr_atomic_read32(&object->refcount) == 1; } /* release_object() {{{1 * * Decrement the reference count of an object. When the object resides in * unmanaged memory and the reference count becomes zero the object will be * deallocated. */ void release_object(lua_apr_refobj *object) { object = root_object(object); if (object_decref(object) && object->unmanaged) free(object); } /* object_env_default() {{{1 * * Get the default environment for objects created by Lua/APR. */ void object_env_default(lua_State *L) { const char *key = "Lua/APR default environment for userdata"; lua_getfield(L, LUA_REGISTRYINDEX, key); if (!lua_istable(L, -1)) { lua_pop(L, 1); lua_newtable(L); lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, key); } } /* object_env_private() {{{1 * * Get the private environment of an object, creating one if it doesn't exist. */ int object_env_private(lua_State *L, int idx) { lua_getfenv(L, idx); /* get current environment table */ object_env_default(L); /* get default environment table */ if (!lua_equal(L, -1, -2)) { lua_pop(L, 1); return 1; } else { lua_pop(L, 2); lua_newtable(L); /* create environment table */ lua_pushvalue(L, -1); /* copy reference to table */ lua_setfenv(L, idx); /* install environment table */ return 0; } } /* object_has_type() {{{1 * * Check if the type of an object on the Lua stack matches the type defined by * the given Lua/APR type structure. */ int object_has_type(lua_State *L, int idx, lua_apr_objtype *T, int getmt) { int valid = 0, top = lua_gettop(L); if (getmt) lua_getmetatable(L, idx); get_metatable(L, T); valid = lua_rawequal(L, -1, -2); lua_settop(L, top); return valid; } /* objects_equal() {{{1 * * Check if two objects refer to the same unmanaged object. This is an * implementation of the __eq metamethod for Lua/APR userdata objects. */ int objects_equal(lua_State *L) { lua_apr_refobj *a, *b; /* Get and compare the metatables. */ lua_getmetatable(L, 1); lua_getmetatable(L, 2); if (lua_equal(L, -1, -2)) { /* Compare the referenced objects. */ a = root_object(lua_touserdata(L, 1)); b = root_object(lua_touserdata(L, 2)); lua_pushboolean(L, a == b); } else lua_pushboolean(L, 0); return 1; } /* check_object() {{{1 * * Check if the type of a userdata object on the Lua stack matches the given * Lua/APR type and return a pointer to the userdata object. */ void *check_object(lua_State *L, int idx, lua_apr_objtype *T) { if (!object_has_type(L, idx, T, 1)) luaL_typerror(L, idx, T->typename); return root_object(lua_touserdata(L, idx)); } /* get_metatable() {{{1 * * Get the metatable for the given type, creating it if it doesn't exist. */ int get_metatable(lua_State *L, lua_apr_objtype *T) { luaL_getmetatable(L, T->typename); if (lua_type(L, -1) != LUA_TTABLE) { lua_pop(L, 1); luaL_newmetatable(L, T->typename); luaL_register(L, NULL, T->metamethods); if (T->methods != NULL) { lua_newtable(L); luaL_register(L, NULL, T->methods); lua_setfield(L, -2, "__index"); } } return 1; } /* object_incref() {{{1 * * Increment the reference count of an object. */ void object_incref(lua_apr_refobj *object) { object = root_object(object); apr_atomic_inc32(&object->refcount); } /* object_decref() {{{1 * * Decrement the reference count of an object. * This does not destroy the object in any way! */ int object_decref(lua_apr_refobj *object) { object = root_object(object); return apr_atomic_dec32(&object->refcount) == 0; } /* refpool_alloc() {{{1 * * Allocate a reference counted APR memory pool that can be shared between * multiple Lua/APR objects in the same Lua state and OS thread (that is to say * no synchronization or atomic instructions are). The memory pool is destroyed * when the last reference is released. */ lua_apr_pool *refpool_alloc(lua_State *L) { apr_status_t status; apr_pool_t *memory_pool; lua_apr_pool *refpool = NULL; status = apr_pool_create(&memory_pool, NULL); if (status != APR_SUCCESS) raise_error_status(L, status); refpool = apr_palloc(memory_pool, sizeof(*refpool)); refpool->ptr = memory_pool; refpool->refs = 0; return refpool; } /* refpool_incref() {{{1 * * Increase the reference count of an APR memory pool. */ apr_pool_t* refpool_incref(lua_apr_pool *refpool) { refpool->refs++; return refpool->ptr; } /* refpool_decref() {{{1 * * Decrease the reference count of an APR memory pool. */ void refpool_decref(lua_apr_pool *refpool) { refpool->refs--; if (refpool->refs == 0) apr_pool_destroy(refpool->ptr); } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/permissions.c000066400000000000000000000152711220664456000174020ustar00rootroot00000000000000/* File system permissions module for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 28, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The Apache Portable Runtime represents file system permissions somewhat * similar to those of [UNIX] [unix]. There are three categories of * permissions: the user, the group and everyone else (the world). Each * category supports read and write permission bits while the meaning of the * third permission bit differs between categories. * * [unix]: http://en.wikipedia.org/wiki/Unix * * ### How Lua/APR presents permissions * * The Lua/APR binding uses a string of 9 characters to represent file system * permissions such as those returned by `apr.stat()`. Here's an example: * * > = apr.stat('.', 'protection') * 'rwxr-xr-x' * * This is the syntax of these permissions strings: * * - Character 1: `r` if the user has read permissions, `-` otherwise * - Character 2: `w` if the user has write permissions, `-` otherwise * - Character 3: `x` if the user has execute permissions, `S` if the user * has set user id permissions or `s` if the user has both permissions * - Characters 4..6: the same respective permissions for the group * - Characters 7..8: the same respective permissions for the world * - Character 9: `x` if the world has execute permissions, `T` if the world * has sticky permissions or `t` if the world has both permissions * * As an example, `rwxrwx---` means the user and group have full permissions * while the world has none. Another example: `r-xr-xr-x` means no-one has * write permissions. * * ### How you can request permissions * * When you need to request file system permissions for an operation like * [reading](#apr.file_open) or [copying](#apr.file_copy) a file there are two * string formats you can use. The first format is a string of nine characters * that lists each permission explicitly. This is the format documented above. * * The second format is very flexible and is one of the formats accepted by the * Linux command line program [chmod] [chmod]. The permissions are split in * three groups with a one-letter code: user is `u`, group is `g` and world is * `o` (for "others"). One or more permissions can then be assigned to one or * more of these groups. Here's an example that requests read permission for * user, group and others: `ugo=r`. Now when you also need write permission for * user and group, you can use `ugo=r,ug=w`. * * [chmod]: http://en.wikipedia.org/wiki/chmod */ #include "lua_apr.h" /* Character constants used to represent permission bits */ #define NONE '-' #define READ 'r' #define WRITE 'w' #define EXEC 'x' #define SETID 'S' #define STICKY 'T' #define EXEC_AND(S) (S + 32) /* Convert an APR bitfield to a Lua string */ int push_protection(lua_State *L, apr_fileperms_t perm) { char str[9], *p = str; #define UNPARSE(KIND, CHAR, MAGIC) \ *p++ = (perm & APR_FPROT_ ## KIND ## READ) ? 'r' : '-'; \ *p++ = (perm & APR_FPROT_ ## KIND ## WRITE) ? 'w' : '-'; \ if ((perm & APR_FPROT_ ## KIND ## EXECUTE) && \ (perm & APR_FPROT_ ## KIND ## MAGIC)) \ *p++ = CHAR; \ else if (perm & APR_FPROT_ ## KIND ## MAGIC) \ *p++ = (CHAR - 32); \ else if (perm & APR_FPROT_ ## KIND ## EXECUTE) \ *p++ = 'x'; \ else \ *p++ = '-' UNPARSE(U, 's', SETID); UNPARSE(G, 's', SETID); UNPARSE(W, 't', STICKY); #undef UNPARSE lua_pushlstring(L, str, sizeof str); return 1; } /* Convert a Lua value to an APR bitfield of filesystem permission flags */ apr_fileperms_t check_permissions(lua_State *L, int idx, int inherit) { enum { USER = 0x01, GROUP = 0x02, OTHER = 0x04 } whom; apr_fileperms_t output = 0; char *input; int loop; if (!lua_isstring(L, idx)) return (inherit && lua_toboolean(L, idx)) ? APR_FPROT_FILE_SOURCE_PERMS : APR_FPROT_OS_DEFAULT; /* Note: Though the "input" pointer is incremented, the Lua string * isn't modified. I just don't know to express this in C casts... */ input = (char *) lua_tostring(L, idx); # define MATCH(offset, special) ( \ (input[offset+0] == NONE || input[offset+0] == READ) && \ (input[offset+1] == NONE || input[offset+1] == WRITE) && \ (input[offset+2] == NONE || input[offset+2] == EXEC || \ input[offset+2] == special || input[offset+2] == EXEC_AND(special))) if (MATCH(0, SETID) && MATCH(3, SETID) && MATCH(6, STICKY)) { #undef MATCH # define PARSE(offset, special, class) \ if (input[offset+0] == READ) \ output |= APR_FPROT_ ## class ## READ; \ if (input[offset+1] == WRITE) \ output |= APR_FPROT_ ## class ## WRITE; \ if (input[offset+2] == EXEC_AND(special)) \ output |= APR_FPROT_ ## class ## EXECUTE | APR_FPROT_ ## class ## special; \ else if (input[offset+2] == special) \ output |= APR_FPROT_ ## class ## special; \ else if (input[offset+2] == EXEC) \ output |= APR_FPROT_ ## class ## EXECUTE PARSE(0, SETID, U); PARSE(3, SETID, G); PARSE(6, STICKY, W); #undef PARSE return output; } for (whom = 0;;) { switch (*input++) { case '\0': /* Lua API always \0 terminates. */ return output; case 'u': whom |= USER; break; case 'g': whom |= GROUP; break; case 'o': whom |= OTHER; break; default: whom |= USER | GROUP | OTHER; input--; /* fall through! */ case '=': for (loop = 1; loop;) { switch (*input++) { default: return output; case ',': loop = 0; whom = 0; break; case READ: if (whom & USER) output |= APR_FPROT_UREAD; if (whom & GROUP) output |= APR_FPROT_GREAD; if (whom & OTHER) output |= APR_FPROT_WREAD; break; case WRITE: if (whom & USER) output |= APR_FPROT_UWRITE; if (whom & GROUP) output |= APR_FPROT_GWRITE; if (whom & OTHER) output |= APR_FPROT_WWRITE; break; case EXEC: if (whom & USER) output |= APR_FPROT_UEXECUTE; if (whom & GROUP) output |= APR_FPROT_GEXECUTE; if (whom & OTHER) output |= APR_FPROT_WEXECUTE; break; case SETID: if (whom & USER) output |= APR_FPROT_USETID; if (whom & GROUP) output |= APR_FPROT_GSETID; break; case STICKY: if (whom & OTHER) output |= APR_FPROT_WSTICKY; break; } } } } } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/pollset.c000066400000000000000000000264161220664456000165140ustar00rootroot00000000000000/* Pollset module for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 3, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The pollset module enables [asynchronous I/O] [wp_async_io] which can * improve throughput, latency and/or responsiveness. It works as follows: * * 1. Create a pollset object by calling `apr.pollset()` * 2. Add one or more sockets to the pollset (e.g. a server socket listening * for connections or a bunch of sockets receiving data) * 3. Call `pollset:poll()` in a loop to process readable/writable sockets * * You can keep adding and removing sockets from the pollset at runtime, just * keep in mind that the size given to `apr.pollset()` is a hard limit. There * is an example of a [simple asynchronous webserver] [async_server] that uses * a pollset. * * [wp_async_io]: http://en.wikipedia.org/wiki/Asynchronous_I/O * [async_server]: #example_asynchronous_webserver */ #include "lua_apr.h" #include /* Internal functions. {{{1 */ typedef struct { lua_apr_refobj header; /* required by new_object() */ apr_pollset_t *pollset; /* opaque pointer allocated by APR from memory pool */ apr_pool_t *memory_pool; /* standalone memory pool for pollset */ apr_pollfd_t *fds; /* file descriptor array allocated from memory pool */ int size; /* size of file descriptor array */ } lua_apr_pollset_object; #define check_socket(L, idx) \ check_object(L, idx, &lua_apr_socket_type) /* check_pollset() */ static lua_apr_pollset_object* check_pollset(lua_State *L, int idx, int open) { lua_apr_pollset_object *object = check_object(L, idx, &lua_apr_pollset_type); if (open && object->pollset == NULL) luaL_error(L, "attempt to use a destroyed pollset"); return object; } /* find_fd_by_socket() {{{2 */ static apr_pollfd_t* find_fd_by_socket(lua_apr_pollset_object *object, lua_apr_socket *socket) { apr_pollfd_t *fd; int i; for (i = 0; i < object->size; i++) { fd = &object->fds[i]; if (fd->desc_type == APR_POLL_SOCKET && fd->client_data == socket) return fd; } return NULL; } /* find_empty_fd() {{{2 */ static apr_pollfd_t* find_empty_fd(lua_apr_pollset_object *object) { int i; for (i = 0; i < object->size; i++) if (object->fds[i].desc_type == APR_NO_DESC) return &object->fds[i]; return NULL; } /* destroy_pollset() {{{2 */ static apr_status_t destroy_pollset(lua_apr_pollset_object *object) { apr_status_t status = APR_SUCCESS; if (object_collectable((lua_apr_refobj*)object)) { if (object->pollset != NULL) { status = apr_pollset_destroy(object->pollset); object->pollset = NULL; } if (object->memory_pool != NULL) { apr_pool_destroy(object->memory_pool); object->memory_pool = NULL; } } release_object((lua_apr_refobj*)object); return status; } /* apr.pollset(size) -> pollset {{{1 * * Create a pollset object. The number @size is the maximum number of sockets * that the pollset can hold. On success a pollset object is returned, * otherwise a nil followed by an error message is returned. */ int lua_apr_pollset(lua_State *L) { lua_apr_pollset_object *object; apr_status_t status; int i, size; size = luaL_checkint(L, 1); object = new_object(L, &lua_apr_pollset_type); status = apr_pool_create(&object->memory_pool, NULL); if (status == APR_SUCCESS) { status = apr_pollset_create(&object->pollset, size, object->memory_pool, 0); if (status == APR_SUCCESS) { object->fds = apr_pcalloc(object->memory_pool, sizeof object->fds[0] * size); object->size = size; /* Unused descriptors are marked with APR_NO_DESC. */ for (i = 0; i < size; i++) object->fds[i].desc_type = APR_NO_DESC; /* Return the new userdata. */ return 1; } destroy_pollset(object); } return push_error_status(L, status); } /* pollset:add(socket, flag [, ...]) -> status {{{1 * * Add a network socket to the pollset. On success true is returned, otherwise * a nil followed by an error message is returned. One or two of the following * flags should be provided: * * - `'input'` indicates that the socket can be read without blocking * - `'output'` indicates that the socket can be written without blocking * * If the socket is already in the pollset the flags of the existing entry in * the pollset will be combined with the new flags. If you want to *change* a * socket from readable to writable or the other way around, you have to first * remove the socket from the pollset and then add it back with the new flag. */ static int pollset_add(lua_State *L) { const char *options[] = { "input", "output", NULL }; const apr_int32_t values[] = { APR_POLLIN, APR_POLLOUT }; lua_apr_pollset_object *object; apr_int16_t reqevents; lua_apr_socket *socket; apr_pollfd_t *fd; apr_status_t status; /* pollset, socket, flag1 [, flag2] */ lua_settop(L, 4); /* Get the object arguments. */ object = check_pollset(L, 1, 1); socket = check_socket(L, 2); /* Check the requested event type(s). */ reqevents = values[luaL_checkoption(L, 3, NULL, options)]; if (!lua_isnil(L, 4)) reqevents |= values[luaL_checkoption(L, 4, NULL, options)]; /* Get the private environment of the pollset. */ object_env_private(L, 1); /* Check if the socket is already in the pollset. */ fd = find_fd_by_socket(object, socket); if (fd != NULL) { /* XXX I couldn't find any documentation on having a socket that is both * readable and writable in the file descriptor array, and I also don't * know what's the intended way to change the requested events for a socket * that is already in the pollset. I assume that removing the socket, * OR'ing the flags and adding it back in will work. */ status = APR_SUCCESS; /* If the flags haven't changed we don't have to do anything :-) */ if ((fd->reqevents & reqevents) != reqevents) { status = apr_pollset_remove(object->pollset, fd); if (status == APR_SUCCESS) { fd->reqevents |= reqevents; status = apr_pollset_add(object->pollset, fd); } } } else { /* Try to add the socket to the pollset. */ fd = find_empty_fd(object); if (fd == NULL) { status = APR_ENOMEM; } else { fd->p = socket->pool; fd->desc_type = APR_POLL_SOCKET; fd->reqevents = reqevents; fd->rtnevents = 0; fd->desc.s = socket->handle; fd->client_data = socket; /* Add the file descriptor to the pollset. */ status = apr_pollset_add(object->pollset, fd); if (status == APR_SUCCESS) { /* Add the socket to the environment table of the pollset so that the * socket doesn't get garbage collected as long as it's contained in * the pollset. */ lua_pushlightuserdata(L, socket); lua_pushvalue(L, 2); lua_rawset(L, 5); } } } return push_status(L, status); } /* pollset:remove(socket) -> status {{{1 * * Remove a @socket from the pollset. On success true is returned, otherwise a * nil followed by an error message is returned. It is not an error if the * socket is not contained in the pollset. */ static int pollset_remove(lua_State *L) { lua_apr_pollset_object *object = APR_SUCCESS; lua_apr_socket *socket; apr_pollfd_t *fd; apr_status_t status; object = check_pollset(L, 1, 1); socket = check_socket(L, 2); fd = find_fd_by_socket(object, socket); if (fd != NULL) { /* Remove it from the pollset. */ status = apr_pollset_remove(object->pollset, fd); /* Remove it from our file descriptor array. */ fd->desc_type = APR_NO_DESC; /* Remove it from the environment. */ object_env_private(L, 1); lua_pushlightuserdata(L, socket); lua_pushnil(L); lua_rawset(L, -3); } return push_status(L, status); } /* pollset:poll(timeout) -> readable, writable {{{1 * * Block for activity on the descriptor(s) in a pollset. The @timeout argument * gives the amount of time in microseconds to wait. This is a maximum, not a * minimum. If a descriptor is signaled, we will wake up before this time. A * negative number means wait until a descriptor is signaled. On success a * table with sockets waiting to be read followed by a table with sockets * waiting to be written is returned, otherwise a nil followed by an error * message is returned. */ static int pollset_poll(lua_State *L) { lua_apr_pollset_object *object; apr_interval_time_t timeout; const apr_pollfd_t *fds; apr_status_t status; apr_int32_t num_fds; int i; /* Normalize stack to (pollset, timeout, environment). */ lua_settop(L, 2); object = check_pollset(L, 1, 1); timeout = luaL_checkint(L, 2); object_env_private(L, 1); /* environment @ 3 */ /* Poll the sockets. */ status = apr_pollset_poll(object->pollset, timeout, &num_fds, &fds); if (status != APR_SUCCESS) return push_error_status(L, status); /* Create tables to hold the readable/writable sockets. */ lua_newtable(L); /* readable @ 4 */ lua_newtable(L); /* writable @ 5 */ for (i = 0; i < num_fds; i++) { /* Find the userdata associated with the socket. */ lua_pushlightuserdata(L, fds[i].client_data); lua_rawget(L, 3); /* Add the socket to the readable list? */ if (fds[i].rtnevents & APR_POLLIN) { lua_pushvalue(L, -1); lua_rawseti(L, 4, lua_objlen(L, 4) + 1); } /* Add the socket to the writable list? */ if (fds[i].rtnevents & APR_POLLOUT) { lua_rawseti(L, 5, lua_objlen(L, 5) + 1); } else lua_pop(L, 1); } return 2; } /* pollset:destroy() -> status {{{1 * * Destroy a pollset. On success true is returned, otherwise a nil followed by * an error message is returned. Note that pollset objects are automatically * destroyed when they are garbage collected. */ static int pollset_destroy(lua_State *L) { lua_apr_pollset_object *object; apr_status_t status; object = check_pollset(L, 1, 0); status = destroy_pollset(object); return push_status(L, status); } /* pollset:__tostring() {{{1 */ static int pollset_tostring(lua_State *L) { lua_apr_pollset_object *object; object = check_pollset(L, 1, 0); if (object->pollset != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_pollset_type.friendlyname, object->pollset); else lua_pushfstring(L, "%s (closed)", lua_apr_pollset_type.friendlyname); return 1; } /* pollset:__gc() {{{1 */ static int pollset_gc(lua_State *L) { lua_apr_pollset_object *object; object = check_pollset(L, 1, 0); destroy_pollset(object); return 0; } /* Internal object definitions. {{{1 */ static luaL_reg pollset_methods[] = { { "add", pollset_add }, { "remove", pollset_remove }, { "poll", pollset_poll }, { "destroy", pollset_destroy }, { NULL, NULL } }; static luaL_reg pollset_metamethods[] = { { "__tostring", pollset_tostring }, { "__gc", pollset_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_pollset_type = { "lua_apr_pollset_t*", /* metatable name in registry */ "pollset", /* friendly object name */ sizeof(lua_apr_pollset_object), /* structure size */ pollset_methods, /* methods table */ pollset_metamethods /* metamethods table */ }; /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/proc.c000066400000000000000000000611671220664456000157770ustar00rootroot00000000000000/* Process handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 6, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include #include #include /* TODO Bind apr_procattr_limit_set(), apr_procattr_perms_set_register(), apr_proc_wait_all_procs() */ /* Structure for process objects. */ typedef struct { lua_apr_refobj header; apr_pool_t *memory_pool; apr_proc_t handle; apr_procattr_t *attr; const char *path; const char **env; } lua_apr_proc; /* Internal functions {{{1 */ /* proc_alloc(L, path) -- allocate and initialize process object {{{2 */ static lua_apr_proc *proc_alloc(lua_State *L, const char *path) { apr_status_t status; lua_apr_proc *process; process = new_object(L, &lua_apr_proc_type); status = apr_pool_create(&process->memory_pool, NULL); if (status != APR_SUCCESS) process->memory_pool = NULL; else status = apr_procattr_create(&process->attr, process->memory_pool); if (status != APR_SUCCESS) raise_error_status(L, status); if (path != NULL) process->path = apr_pstrdup(process->memory_pool, path); return process; } /* proc_check(L, i) -- check for process object on Lua stack {{{2 */ static lua_apr_proc *proc_check(lua_State *L, int i) { return check_object(L, i, &lua_apr_proc_type); } /* get_pipe(L, file, key) -- return standard input/output/error pipe {{{2 */ static int get_pipe(lua_State *L, apr_file_t *handle, const char *key) { lua_apr_file *file; if (object_env_private(L, 1)) { lua_getfield(L, -1, key); /* get cached pipe object */ if (lua_type(L, -1) == LUA_TUSERDATA) return 1; /* return cached pipe object */ lua_pop(L, 1); /* pop nil result from lua_getfield() */ } if (handle != NULL) { file = file_alloc(L, NULL, NULL); file->handle = handle; init_file_buffers(L, file, 1); lua_pushvalue(L, -1); /* copy reference to userdata */ lua_setfield(L, -3, key); /* cache userdata in environment table */ return 1; /* return new pipe */ } return 0; } /* set_pipe(L, ck, pk, cb) -- open standard input/output/error pipe {{{2 */ static int set_pipe(lua_State *L, const char *ck, const char *pk, lua_apr_setpipe_f cb) { lua_apr_proc *process; apr_file_t *child, *parent = NULL; /* Validate and collect arguments. */ lua_settop(L, 3); /* process, child_pipe, parent_pipe */ process = proc_check(L, 1); child = file_check(L, 2, 1)->handle; if (!lua_isnil(L, 3)) parent = file_check(L, 3, 1)->handle; /* Make sure pipe(s) aren't garbage collected while process is alive! */ object_env_private(L, 1); /* process, child_pipe, parent_pipe, environment */ lua_insert(L, 1); /* environment, process, child_pipe, parent_pipe */ lua_setfield(L, 1, pk); /* environment, process, child_pipe */ lua_setfield(L, 1, ck); /* environment, process */ return push_status(L, cb(process->attr, child, parent)); } /* close_pipe(L, key) -- close standard input/output/error pipe {{{2 */ static void close_pipe(lua_State *L, const char *key) { lua_getfield(L, 2, key); if (lua_type(L, -1) == LUA_TUSERDATA) file_close_impl(L, lua_touserdata(L, -1)); lua_pop(L, 1); } /* apr.proc_create(program) -> process {{{1 * * Create a child process that will execute the given @program when started. * Once you've called this function you still need to execute the process using * the `process:exec()` function. Here's a simple example that emulates Lua's * `os.execute()` function: * * function execute(command) * local arguments = apr.tokenize_to_argv(command) * local progname = table.remove(arguments, 1) * local process = apr.proc_create(progname) * process:cmdtype_set('shellcmd/env') * process:exec(arguments) * local done, code, why = process:wait(true) * return code * end * * execute 'echo This can be any process...' */ int lua_apr_proc_create(lua_State *L) { proc_alloc(L, luaL_checkstring(L, 1)); return 1; } /* apr.proc_detach(daemonize) -> status {{{1 * * Detach the current process from the controlling terminal. If @daemonize * evaluates to true the process will [daemonize] [daemons] and become a * background process, otherwise it will stay in the foreground. On success * true is returned, otherwise a nil followed by an error message is * returned. * * [daemons]: http://en.wikipedia.org/wiki/Daemon_(computer_software) */ int lua_apr_proc_detach(lua_State *L) { apr_status_t status; int daemonize; luaL_checkany(L, 1); daemonize = lua_toboolean(L, 1); status = apr_proc_detach(daemonize); return push_status(L, status); } #if APR_HAS_FORK /* apr.proc_fork() -> process, context {{{1 * * This is currently the only non-portable function in APR and by extension * Lua/APR. It performs a [standard UNIX fork][fork]. If the fork succeeds a * @process object and @context string (`'parent'` or `'child'`) are returned, * otherwise a nil followed by an error message is returned. The parent process * can use the returned @process object to wait for the child process to die: * * if apr.proc_fork then -- forking supported? * process, context = assert(apr.proc_fork()) * if context == 'parent' then * print "Parent waiting for child.." * process:wait(true) * print "Parent is done!" * else -- context == 'child' * print "Child simulating activity.." * apr.sleep(10) * print "Child is done!" * end * end * * As the above example implies the `apr.proc_fork()` function will only be * defined when forking is supported on the current platform. * * [fork]: http://en.wikipedia.org/wiki/Fork_(operating_system) */ int lua_apr_proc_fork(lua_State *L) { lua_apr_proc *process = proc_alloc(L, NULL); apr_status_t status = apr_proc_fork(&process->handle, process->memory_pool); if (status != APR_INCHILD && status != APR_INPARENT) return push_error_status(L, status); lua_pushstring(L, status == APR_INPARENT ? "parent" : "child"); return 2; } #endif /* process:addrspace_set(separate) -> status {{{1 * * If @separate evaluates to true the child process will start in its own * address space, otherwise the child process executes in the current address * space from its parent. On success true is returned, otherwise a nil followed * by an error message is returned. The default is no on NetWare and yes on * other platforms. */ static int proc_addrspace_set(lua_State *L) { apr_int32_t separate; apr_status_t status; lua_apr_proc *process; process = proc_check(L, 1); separate = lua_toboolean(L, 2); status = apr_procattr_addrspace_set(process->attr, separate); return push_status(L, status); } /* process:user_set(username [, password]) -> status {{{1 * * Set the user under which the child process will run. On success true is * returned, otherwise a nil followed by an error message is returned. * * On Windows and other platforms where `apr.user_set_requires_password` is * true this method _requires_ a password. */ static int proc_user_set(lua_State *L) { const char *username, *password; apr_status_t status; lua_apr_proc *process; process = proc_check(L, 1); username = luaL_checkstring(L, 2); # if APR_PROCATTR_USER_SET_REQUIRES_PASSWORD password = luaL_checkstring(L, 3); # else password = luaL_optstring(L, 3, NULL); # endif status = apr_procattr_user_set(process->attr, username, password); return push_status(L, status); } /* process:group_set(groupname) -> status {{{1 * * Set the group under which the child process will run. On success true is * returned, otherwise a nil followed by an error message is returned. */ static int proc_group_set(lua_State *L) { apr_status_t status; const char *groupname; lua_apr_proc *process; process = proc_check(L, 1); groupname = luaL_checkstring(L, 2); status = apr_procattr_group_set(process->attr, groupname); return push_status(L, status); } /* process:cmdtype_set(type) -> status {{{1 * * Set what type of command the child process will execute. On success true is * returned, otherwise a nil followed by an error message is returned. The * argument @type must be one of: * * - `'shellcmd'`: Use the shell to invoke the program * - `'shellcmd/env'`: Use the shell to invoke the program, replicating our environment * - `'program'`: Invoke the program directly, without copying the environment * - `'program/env'`: Invoke the program directly, replicating our environment * - `'program/env/path'`: Find program in `$PATH`, replicating our environment */ static int proc_cmdtype_set(lua_State *L) { const char *options[] = { "shellcmd", "shellcmd/env", "program", "program/env", "program/env/path", NULL }; const apr_cmdtype_e types[] = { APR_SHELLCMD, APR_SHELLCMD_ENV, APR_PROGRAM, APR_PROGRAM_ENV, APR_PROGRAM_PATH }; lua_apr_proc *process; apr_cmdtype_e type; apr_status_t status; process = proc_check(L, 1); type = types[luaL_checkoption(L, 2, NULL, options)]; status = apr_procattr_cmdtype_set(process->attr, type); return push_status(L, status); } /* process:env_set(environment) -> status {{{1 * * Set the environment variables of the child process to the key/value pairs in * the table @environment. On success true is returned, otherwise a nil * followed by an error message is returned. * * Please note that the environment table is ignored for the command types * `'shellcmd/env'`, `'program/env'` and `'program/env/path'` (set using the * `process:cmdtype_set()` method). */ static int proc_env_set(lua_State *L) { const char *format, *message, *name, *value; size_t i, count; char **env; lua_apr_proc *process; /* validate input, calculate size of environment array */ process = proc_check(L, 1); luaL_checktype(L, 2, LUA_TTABLE); for (count = 0, lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1), count++) { if (lua_type(L, -2) != LUA_TSTRING) { format = "expected string key, got %s"; message = lua_pushfstring(L, format, luaL_typename(L, -2)); luaL_argerror(L, 2, message); } if (!lua_isstring(L, -1)) { format = "expected string value for key " LUA_QS ", got %s"; message = lua_pushfstring(L, format, lua_tostring(L, -2), luaL_typename(L, -1)); luaL_argerror(L, 2, message); } } /* convert Lua table to array of environment variables */ env = apr_palloc(process->memory_pool, sizeof env[0] * (count+1)); if (!env) return push_error_memory(L); for (i = 0, lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1), i++) { name = lua_tostring(L, -2); value = lua_tostring(L, -1); env[i] = apr_pstrcat(process->memory_pool, name, "=", value, NULL); if (!env[i]) return push_error_memory(L); } env[i] = NULL; process->env = (const char**)env; lua_pushboolean(L, 1); return 1; } /* process:dir_set(path) -> status {{{1 * * Set which directory the child process should start executing in. On success * true is returned, otherwise a nil followed by an error message is returned. * * By default child processes inherit this directory from their parent process * at the moment when the `process:exec()` call is made. To find out the * current directory see the `apr.filepath_get()` function. */ static int proc_dir_set(lua_State *L) { apr_status_t status; const char *path; lua_apr_proc *process; process = proc_check(L, 1); path = luaL_checkstring(L, 2); status = apr_procattr_dir_set(process->attr, path); return push_status(L, status); } /* process:detach_set(detach) -> status {{{1 * * Determine if the child should start in detached state. On success true is * returned, otherwise a nil followed by an error message is returned. Default * is no. */ static int proc_detach_set(lua_State *L) { apr_status_t status; apr_int32_t detach; lua_apr_proc *process; process = proc_check(L, 1); detach = lua_toboolean(L, 2); status = apr_procattr_detach_set(process->attr, detach); return push_status(L, status); } /* process:error_check_set(enabled) -> nothing {{{1 * * Specify that `process:exec()` should do whatever it can to report failures * directly, rather than find out in the child that something is wrong. This * leads to extra overhead in the calling process, but it may help you handle * these errors more gracefully. * * Note that this option is only useful on platforms where [fork()][fork] is * used. * * [fork]: http://linux.die.net/man/2/fork */ static int proc_error_check_set(lua_State *L) { apr_status_t status; apr_int32_t error_check; lua_apr_proc *process; process = proc_check(L, 1); error_check = lua_toboolean(L, 2); status = apr_procattr_error_check_set(process->attr, error_check); return push_status(L, status); } /* process:io_set(stdin, stdout, stderr) -> status {{{1 * * Determine if the child process should be linked to its parent through one or * more pipes. On success true is returned, otherwise a nil followed by an * error message is returned. * * Each argument gives the blocking mode of a pipe, which can be one of the * following strings: * * - `'none'`: Don't create a pipe * - `'full-block'`: Create a pipe that blocks until the child process writes to the pipe or dies * - `'full-nonblock'`: Create a pipe that doesn't block * - `'parent-block'`: Create a pipe that only blocks on the parent's end * - `'child-block'`: Create a pipe that only blocks on the child's end * * *Once the child process has been started* with `process:exec()`, the pipes * can be accessed with the methods `process:in_get()`, `process:out_get()` * and `process:err_get()`. * * Here's an example that executes the external command `tr a-z A-Z` to * translate some characters to uppercase: * * > p = apr.proc_create 'tr' * > p:cmdtype_set('shellcmd/env') * > p:io_set('child-block', 'parent-block', 'none') * > p:exec{'a-z', 'A-Z'} * > input = p:in_get() * > output = p:out_get() * > input:write('Testing, 1, 2, 3\n') * > input:close() * > print(output:read()) * TESTING, 1, 2, 3 * > output:close() * > p:wait(true) */ static int proc_io_set(lua_State *L) { const char *options[] = { "none", "full-block", "full-nonblock", "parent-block", "child-block", NULL }; const apr_int32_t values[] = { APR_NO_PIPE, APR_FULL_BLOCK, APR_FULL_NONBLOCK, APR_PARENT_BLOCK, APR_CHILD_BLOCK }; apr_status_t status; lua_apr_proc *process; apr_int32_t input, output, error; process = proc_check(L, 1); input = values[luaL_checkoption(L, 2, "none", options)]; output = values[luaL_checkoption(L, 3, "none", options)]; error = values[luaL_checkoption(L, 4, "none", options)]; status = apr_procattr_io_set(process->attr, input, output, error); return push_status(L, status); } /* process:in_set(child_in [, parent_in]) -> status {{{1 * * Initialize the [standard input pipe] [stdin] of the child process to an * existing pipe or a pair of pipes. This can be useful if you have already * opened a pipe (or multiple files) that you wish to use, perhaps persistently * across multiple process invocations - such as a log file. On success true is * returned, otherwise a nil followed by an error message is returned. Here's * a basic example that connects two processes using an anonymous pipe: * * -- Create a gzip process to decompress the Lua source code archive. * gzip = apr.proc_create 'gunzip' * gzip:cmdtype_set 'shellcmd/env' * gzip:in_set(apr.file_open('lua-5.1.4.tar.gz', 'rb')) * * -- Create a tar process to list the files in the decompressed archive. * tar = apr.proc_create 'tar' * tar:cmdtype_set 'shellcmd/env' * tar:out_set(apr.pipe_open_stdout()) * * -- Connect the two processes using an anonymous pipe. * input, output = assert(apr.pipe_create()) * gzip:out_set(output) * tar:in_set(input) * * -- Start the pipeline by executing both processes. * gzip:exec() * tar:exec{'-t'} * * [stdin]: http://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29 */ static int proc_in_set(lua_State *L) { return set_pipe(L, "in_child", "in_parent", (lua_apr_setpipe_f)apr_procattr_child_in_set); } /* process:out_set(child_out [, parent_out]) -> status {{{1 * * Initialize the [standard output pipe] [stdout] of the child process to an * existing pipe or a pair of pipes. This can be useful if you have already * opened a pipe (or multiple files) that you wish to use, perhaps persistently * across multiple process invocations - such as a log file. On success true is * returned, otherwise a nil followed by an error message is returned. * * [stdout]: http://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29 */ static int proc_out_set(lua_State *L) { return set_pipe(L, "out_child", "out_parent", (lua_apr_setpipe_f)apr_procattr_child_out_set); } /* process:err_set(child_err [, parent_err]) -> status {{{1 * * Initialize the [standard error pipe] [stderr] of the child process to an * existing pipe or a pair of pipes. This can be useful if you have already * opened a pipe (or multiple files) that you wish to use, perhaps persistently * across multiple process invocations - such as a log file. On success true is * returned, otherwise a nil followed by an error message is returned. * * [stderr]: http://en.wikipedia.org/wiki/Standard_streams#Standard_error_.28stderr.29 */ static int proc_err_set(lua_State *L) { return set_pipe(L, "err_child", "err_parent", (lua_apr_setpipe_f)apr_procattr_child_err_set); } /* process:in_get() -> pipe {{{1 * * Get the parent end of the standard input pipe (a writable pipe). */ static int proc_in_get(lua_State *L) { lua_apr_proc *process = proc_check(L, 1); return get_pipe(L, process->handle.in, "in_parent"); } /* process:out_get() -> pipe {{{1 * * Get the parent end of the standard output pipe (a readable pipe). */ static int proc_out_get(lua_State *L) { lua_apr_proc *process = proc_check(L, 1); return get_pipe(L, process->handle.out, "out_parent"); } /* process:err_get() -> pipe {{{1 * * Get the parent end of the standard error pipe (a readable pipe). */ static int proc_err_get(lua_State *L) { lua_apr_proc *process = proc_check(L, 1); return get_pipe(L, process->handle.err, "err_parent"); } /* process:exec([args]) -> status {{{1 * * Create the child process and execute a program or shell command inside it. * On success true is returned, otherwise a nil followed by an error message is * returned. If the @args array is given the contained strings become the * command line arguments to the child process. The [program name] [progname] * for the child process defaults to the name passed into `apr.proc_create()`, * but you can change it by setting `args[0]`. * * [progname]: http://en.wikipedia.org/wiki/BusyBox#Single_binary */ static int proc_exec(lua_State *L) { apr_status_t status; lua_apr_proc *process; const char *p, **args; int i, nargs = 0; lua_settop(L, 2); process = proc_check(L, 1); if (!lua_isnoneornil(L, 2)) { luaL_checktype(L, 2, LUA_TTABLE); nargs = lua_objlen(L, 2); } /* Allocate and initialize the array of arguments. */ args = apr_palloc(process->memory_pool, sizeof args[0] * (nargs + 2)); if (args == NULL) return push_error_memory(L); args[0] = apr_filepath_name_get(process->path); args[nargs+1] = NULL; /* Copy the arguments? */ if (nargs > 0) { for (i = 0; i <= nargs; i++) { lua_pushinteger(L, i); lua_gettable(L, 2); p = lua_tostring(L, -1); if (p != NULL) /* argument */ args[i] = apr_pstrdup(process->memory_pool, p); else if (i != 0) /* invalid value */ luaL_argcheck(L, 0, 2, lua_pushfstring(L, "invalid value at index %d", i)); lua_pop(L, 1); } } /* Create the child process using the given command line arguments. */ status = apr_proc_create(&process->handle, process->path, args, process->env, process->attr, process->memory_pool); return push_status(L, status); } /* process:wait(how) -> done [, why, code] {{{1 * * Wait for the child process to die. If @how is true the call blocks until the * process dies, otherwise the call returns immediately regardless of if the * process is dead or not. The first return value is false if the process isn't * dead yet. If it's true the process died and two more return values are * available. The second return value is the reason the process died, which is * one of: * * - `'exit'`: Process exited normally * - `'signal'`: Process exited due to a signal * - `'signal/core'`: Process exited and dumped [a core file] [coredump] * * The third return value is the exit code of the process. If an error occurs a * nil followed by an error message is returned. * * [coredump]: http://en.wikipedia.org/wiki/Core_dump */ static int proc_wait(lua_State *L) { apr_status_t status; apr_exit_why_e why; apr_wait_how_e how; lua_apr_proc *process; int code; process = proc_check(L, 1); how = lua_toboolean(L, 2) ? APR_WAIT : APR_NOWAIT; status = apr_proc_wait(&process->handle, &code, &why, how); if (APR_STATUS_IS_CHILD_NOTDONE(status)) return (lua_pushboolean(L, 0), 1); else if (!APR_STATUS_IS_CHILD_DONE(status)) return push_error_status(L, status); else lua_pushboolean(L, 1); switch (why) { default: case APR_PROC_EXIT: lua_pushliteral(L, "exit"); break; case APR_PROC_SIGNAL: lua_pushliteral(L, "signal"); break; case APR_PROC_SIGNAL_CORE: lua_pushliteral(L, "signal/core"); break; } lua_pushinteger(L, code); return 3; } /* process:kill(how) -> status {{{1 * * Terminate a running child process. On success true is returned, otherwise a * nil followed by an error message is returned. The parameter @how must be one * of: * * - `'never'`: The process is never sent any signals * - `'always'`: The process is sent the [SIGKILL] [sigkill] signal when its * Lua userdata is garbage collected * - `'timeout'`: Send the [SIGTERM] [sigterm] signal, wait for 3 seconds, * then send the [SIGKILL] [sigkill] signal * - `'wait'`: Wait forever for the process to complete * - `'once'`: Send the [SIGTERM] [sigterm] signal and then wait * * [sigkill]: http://en.wikipedia.org/wiki/SIGKILL * [sigterm]: http://en.wikipedia.org/wiki/SIGTERM */ static int proc_kill(lua_State *L) { const char *options[] = { "never", "always", "timeout", "wait", "once", NULL, }; const apr_kill_conditions_e values[] = { APR_KILL_NEVER, APR_KILL_ALWAYS, APR_KILL_AFTER_TIMEOUT, APR_JUST_WAIT, APR_KILL_ONLY_ONCE, }; apr_status_t status; lua_apr_proc *process; int option; process = proc_check(L, 1); option = values[luaL_checkoption(L, 2, NULL, options)]; status = apr_proc_kill(&process->handle, option); return push_status(L, status); } /* process:__tostring() {{{1 */ static int proc_tostring(lua_State *L) { lua_apr_proc *process; process = proc_check(L, 1); lua_pushfstring(L, "%s (%p)", lua_apr_proc_type.friendlyname, process); return 1; } /* process:__gc() {{{1 */ static int proc_gc(lua_State *L) { lua_apr_proc *process = proc_check(L, 1); if (object_collectable((lua_apr_refobj*)process)) { lua_settop(L, 1); lua_getfenv(L, 1); if (lua_type(L, -1) == LUA_TTABLE) { close_pipe(L, "in_child"); close_pipe(L, "in_parent"); close_pipe(L, "out_child"); close_pipe(L, "out_parent"); close_pipe(L, "err_child"); close_pipe(L, "err_parent"); } if (process->memory_pool != NULL) { apr_pool_destroy(process->memory_pool); process->memory_pool = NULL; } } release_object((lua_apr_refobj*)process); return 0; } /* }}}1 */ static luaL_Reg proc_methods[] = { { "cmdtype_set", proc_cmdtype_set }, { "addrspace_set", proc_addrspace_set }, { "detach_set" , proc_detach_set }, { "error_check_set", proc_error_check_set }, { "user_set", proc_user_set }, { "group_set", proc_group_set }, { "env_set", proc_env_set }, { "dir_set", proc_dir_set }, { "io_set", proc_io_set }, { "in_get", proc_in_get }, { "out_get", proc_out_get }, { "err_get", proc_err_get }, { "in_set", proc_in_set }, { "out_set", proc_out_set }, { "err_set", proc_err_set }, { "exec", proc_exec }, { "wait", proc_wait }, { "kill", proc_kill }, { NULL, NULL }, }; static luaL_Reg proc_metamethods[] = { { "__tostring", proc_tostring }, { "__eq", objects_equal }, { "__gc", proc_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_proc_type = { "lua_apr_proc*", /* metatable name in registry */ "process", /* friendly object name */ sizeof(lua_apr_proc), /* structure size */ proc_methods, /* methods table */ proc_metamethods /* metamethods table */ }; /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/serialize.c000066400000000000000000000154561220664456000170230ustar00rootroot00000000000000/* Serialization module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 20, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The Lua/APR binding contains a serialization function based on the [Metalua * table-to-source serializer] [metalua_serializer] extended to support * function upvalues and userdata objects created by the Lua/APR binding. The * following Lua values can be serialized: * * - strings, numbers, booleans, nil (scalars) * - Lua functions (including upvalues) * - userdata objects created by the Lua/APR binding * - tables thereof. There is no restriction on keys; recursive and shared * sub-tables are handled correctly. * * Restrictions: * * - *Metatables and environments aren't saved*; * this might or might not be what you want. * * - *If multiple functions share a scalar upvalue they will each get their * own copy.* Because it is impossible to join upvalues of multiple * functions in Lua 5.1 this won't be fixed any time soon. * * The following functions in the Lua/APR binding internally use serialization * to transfer Lua functions and other values between operating system threads: * * - `apr.thread()` and `thread:wait()` * - `queue:push()` and `queue:pop()` * - `queue:try_push()` and `queue:try_pop()` * * [metalua_serializer]: https://github.com/fab13n/metalua/blob/master/src/lib/serialize.lua */ /* TODO Verify that we're reference counting correctly... * TODO Locking around modifications of chain?! Bad experiences with mutexes :-\ */ #include "lua_apr.h" #include /* Internal stuff. {{{1 */ typedef struct reference reference; struct reference { char uuid[APR_UUID_FORMATTED_LENGTH + 1]; lua_apr_objtype *type; lua_apr_refobj *object; reference *next; }; static reference *chain = NULL; static void load_lua_apr(lua_State *L) { /* Make sure the Lua/APR binding is loaded. */ lua_getglobal(L, "require"); lua_pushliteral(L, "apr"); lua_call(L, 1, 1); /* require('apr') should raise on errors, but just as a sanity check: */ if (!lua_istable(L, -1)) raise_error_message(L, "Failed to load Lua/APR binding!"); } /* apr.ref(object) -> uuid {{{1 * * Prepare the Lua/APR userdata @object so that it can be referenced from * another Lua state in the same operating system process and associate a * [UUID] [uuid] with the object. The UUID is returned as a string. When you * pass this UUID to `apr.deref()` you'll get the same object back. This only * works once, but of course you're free to generate another UUID for the same * object. * * [uuid]: http://en.wikipedia.org/wiki/Universally_unique_identifier */ int lua_apr_ref(lua_State *L) { lua_apr_objtype *type = NULL; reference *node = NULL; apr_uuid_t uuid; int i; /* Make sure we're dealing with a userdata object. */ luaL_checktype(L, 1, LUA_TUSERDATA); /* Make sure the userdata has one of the supported types. */ for (i = 0; lua_apr_types[i] != NULL; i++) if (object_has_type(L, 1, lua_apr_types[i], 1)) { type = lua_apr_types[i]; break; } luaL_argcheck(L, type != NULL, 1, "userdata cannot be referenced"); /* Prepare to insert object in chain of references. */ node = calloc(1, sizeof(reference)); if (node == NULL) raise_error_memory(L); node->object = prepare_reference(type, lua_touserdata(L, 1)); if (node->object == NULL) { free(node); raise_error_memory(L); } node->type = type; apr_uuid_get(&uuid); apr_uuid_format(node->uuid, &uuid); /* Increase the reference count of the object because it is now being * referenced from the Lua state and the chain of references. */ object_incref(node->object); /* Insert the object into the chain of references. */ node->next = chain; chain = node; /* Return newly associated UUID for object. */ lua_pushlstring(L, node->uuid, APR_UUID_FORMATTED_LENGTH); return 1; } /* apr.deref(uuid) -> object {{{1 * * Convert a UUID that was previously returned by `apr.ref()` into a userdata * object and return the object. You can only dereference a UUID once, but of * course you're free to generate another UUID for the same object. */ int lua_apr_deref(lua_State *L) { const char *uuid; reference *node, *last = NULL; uuid = luaL_checkstring(L, 1); /* Look for the UUID in the chain of object references. */ node = chain; while (node != NULL) { if (node->object != NULL && strcmp(uuid, node->uuid) == 0) { /* Return an object that references the real object in unmanaged memory. */ create_reference(L, node->type, node->object); /* Invalidate the UUID. */ if (node == chain) chain = node->next; else last->next = node->next; free(node); return 1; } last = node; node = node->next; } luaL_argerror(L, 1, "userdata has not been referenced"); /* Make the compiler happy. */ return 0; } /* lua_apr_serialize() - serialize values from "idx" to stack top (pops 0..n values, pushes string) {{{1 */ int lua_apr_serialize(lua_State *L, int idx) { int num_args = lua_gettop(L) - idx + 1; /* calculate number of arguments */ load_lua_apr(L); /* load Lua/APR binding */ lua_getfield(L, -1, "serialize"); /* get apr.serialize() function */ if (!lua_isfunction(L, -1)) /* make sure we found it */ raise_error_message(L, "Failed to load apr.serialize() function!"); lua_insert(L, idx); /* move function before arguments */ lua_pop(L, 1); /* remove "apr" table from stack */ lua_call(L, num_args, 1); /* call function (propagating errors upwards) */ if (!lua_isstring(L, -1)) /* apr.serialize() should raise on errors, but just as a sanity check: */ raise_error_message(L, "Failed to serialize value(s) using apr.serialize()"); return 1; /* leave result string on top of stack */ } /* lua_apr_unserialize() - unserialize string at top of stack (pops string, pushes 0..n values). {{{1 */ int lua_apr_unserialize(lua_State *L) { int idx = lua_gettop(L); /* remember input string stack index */ load_lua_apr(L); /* load Lua/APR binding */ lua_getfield(L, -1, "unserialize"); /* get apr.unserialize() function */ if (!lua_isfunction(L, -1)) /* make sure we found it */ raise_error_message(L, "Failed to load apr.unserialize() function!"); lua_insert(L, idx); /* move function before input string */ lua_pop(L, 1); /* pop "apr" table (now at top of stack) */ lua_call(L, 1, LUA_MULTRET); /* call function with string argument (propagating errors upwards) */ return lua_gettop(L) - idx; /* return 0..n unserialized values */ } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/serialize.lua000066400000000000000000000177151220664456000173620ustar00rootroot00000000000000--[[ Serialization function for the Lua/APR binding. Last Change: November 20, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT Based on the table-to-source serializer included in Metalua, which is copyright (c) 2008-2009, Fabien Fleutot . Retrieved from https://github.com/fab13n/metalua/blob/master/src/lib/serialize.lua. Minor changes by Peter Odding to serialize function upvalues and userdata objects created by the Lua/APR binding. Inline documentation can be found in "serialize.c" because I'm too lazy to change my documentation generator... ]] local no_identity = { ['nil'] = true, ['boolean'] = true, ['number'] = true, ['string'] = true, } local function serialize(x) local gensym_max = 0 -- index of the gensym() symbol generator local seen_once = {} -- element->true set of elements seen exactly once in the table local multiple = {} -- element->varname set of elements seen more than once local nested = {} -- transient, set of elements currently being traversed local nest_points = {} local nest_patches = {} -- Generate fresh indexes to store new sub-tables: local function gensym() gensym_max = gensym_max + 1 return gensym_max end ----------------------------------------------------------------------------- -- `nest_points' are places where a (recursive) table appears within -- itself, directly or not. for instance, all of these chunks -- create nest points in table `x': -- -- "x = {}; x[x] = 1" -- "x = {}; x[1] = x" -- "x = {}; x[1] = { y = { x } }". -- -- To handle those, two tables are created by `mark_nest_point()': -- -- * `nest_points[parent]' associates all keys and values in table -- parent which create a nest_point with boolean `true' -- -- * `nest_patches' contains a list of `{ parent, key, value }' -- tuples creating a nest point. They're all dumped after all the -- other table operations have been performed. -- -- `mark_nest_point(p, k, v)' fills tables `nest_points' and -- `nest_patches' with information required to remember that -- key/value `(k,v)' creates a nest point in parent table `p'. -- It also marks `p' as occurring multiple times, since several -- references to it will be required in order to patch the nest -- points. ----------------------------------------------------------------------------- local function mark_nest_point(parent, k, v) local nk, nv = nested[k], nested[v] assert(not nk or seen_once[k] or multiple[k]) assert(not nv or seen_once[v] or multiple[v]) local parent_np = nest_points[parent] if not parent_np then parent_np = {} nest_points[parent] = parent_np end if nk then parent_np[k] = true end if nv then parent_np[v] = true end table.insert(nest_patches, { parent, k, v }) seen_once[parent] = nil multiple[parent] = true end ----------------------------------------------------------------------------- -- 1st pass, list the tables and functions which appear more than once in `x' ----------------------------------------------------------------------------- local function mark_multiple_occurrences(x) local t = type(x) if no_identity[t] then return elseif seen_once[x] then seen_once[x] = nil multiple[x] = true elseif not multiple[x] then seen_once[x] = true end if t == 'table' then nested[x] = true for k, v in pairs(x) do if nested[k] or nested[v] then mark_nest_point(x, k, v) else mark_multiple_occurrences(k) mark_multiple_occurrences(v) end end nested[x] = nil elseif t == 'function' then for i = 1, math.huge do local n, v = debug.getupvalue(x, i) if n then mark_multiple_occurrences(v) else break end end end end local dumped = {} -- multiply occurring values already dumped in localdefs local localdefs = {} -- already dumped local definitions as source code lines -- mutually recursive functions: local dump_val, dump_or_ref_val ------------------------------------------------------------------------------ -- if `x' occurs multiple times, dump the local var rather than the -- value. If it's the first time it's dumped, also dump the content -- in localdefs. ------------------------------------------------------------------------------ function dump_or_ref_val(x) if nested[x] then -- placeholder for recursive reference return 'false' elseif not multiple[x] then -- value referenced only once, dump directly return dump_val(x) else local var = dumped[x] if var then -- already referenced return '_[' .. var .. ']' else -- first occutrence, create and register reference local val = dump_val(x) var = gensym() table.insert(localdefs, '_[' .. var .. '] = ' .. val) dumped[x] = var return '_[' .. var .. ']' end end end ----------------------------------------------------------------------------- -- 2nd pass, dump the object; subparts occurring multiple times are dumped -- in local variables, which can then be referenced multiple times; -- care is taken to dump local vars in an order which respect dependencies. ----------------------------------------------------------------------------- function dump_val(x) local t = type(x) if x == nil then return 'nil' elseif t == 'number' then return x == math.huge and 'math.huge' or string.format('%.16f', x) elseif t == 'string' then return string.format('%q', x) elseif t == 'boolean' then return x and 'true' or 'false' elseif t == 'function' then local body = string.format("loadstring(%q, '@serialized')", string.dump(x)) if not debug.getupvalue(x, 1) then return body end local acc = {} -- FIXME This doesn't actually need an anonymous function, I'm just lazy. table.insert(acc, '(function()') table.insert(acc, 'local f = ' .. body) for i = 1, math.huge do local n, v = debug.getupvalue(x, i) if not n then break end table.insert(acc, string.format('debug.setupvalue(f, %i, %s)', i, dump_or_ref_val(v))) end table.insert(acc, 'return f') table.insert(acc, 'end)()') return table.concat(acc, '\n') elseif t == 'table' then local acc = {} local idx_dumped = {} local np = nest_points[x] for i, v in ipairs(x) do if np and np[v] then table.insert(acc, 'false') -- placeholder else table.insert(acc, dump_or_ref_val(v)) end idx_dumped[i] = true end for k, v in pairs(x) do if np and (np[k] or np[v]) then --check_multiple(k); check_multiple(v) -- force dumps in localdefs elseif not idx_dumped[k] then table.insert(acc, '[' .. dump_or_ref_val(k) .. '] = ' .. dump_or_ref_val(v)) end end return '{ ' .. table.concat(acc, ', ') .. ' }' elseif t == 'userdata' then local apr = require 'apr' return string.format("require('apr').deref(%q)", apr.ref(x)) else error("Can't serialize data of type " .. t) end end -- Patch the recursive table entries: local function dump_nest_patches() for _, entry in ipairs(nest_patches) do local p, k, v = unpack(entry) assert(multiple[p]) table.insert(localdefs, dump_or_ref_val(p) .. '[' .. dump_or_ref_val(k) .. '] = ' .. dump_or_ref_val(v) .. ' -- rec') end end mark_multiple_occurrences(x) local toplevel = dump_or_ref_val(x) dump_nest_patches() if next(localdefs) then -- Dump local vars containing shared or recursive parts, -- then the main table using them. return 'local _={}\n' .. table.concat(localdefs, '\n') .. '\nreturn ' .. toplevel else -- No shared part, straightforward dump: return 'return ' .. toplevel end end return serialize -- vim: ts=2 sw=2 et lua-apr-0.23.2.dfsg/src/shm.c000066400000000000000000000177761220664456000156320ustar00rootroot00000000000000/* Shared memory module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 6, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * [Shared memory] [shm] is memory that may be simultaneously accessed by * multiple programs with an intent to provide communication among them. The * Lua/APR binding represents shared memory as file objects through the * `shm:read()`, `shm:write()` and `shm:seek()` methods. * * [shm]: http://en.wikipedia.org/wiki/Shared_memory */ #include "lua_apr.h" #include typedef struct { lua_apr_refobj header; apr_pool_t *pool; apr_shm_t *handle; void *base; apr_size_t size; lua_apr_readbuf input; lua_apr_writebuf output; lua_apr_buffer *last_op; } lua_apr_shm; /* Internal functions. {{{1 */ static void init_shm(lua_State *L, lua_apr_shm *object) { object->base = apr_shm_baseaddr_get(object->handle); object->size = apr_shm_size_get(object->handle); object->last_op = &object->input.buffer; init_unmanaged_buffers(L, &object->input, &object->output, object->base, object->size); } static lua_apr_shm* check_shm(lua_State *L, int idx) { return check_object(L, idx, &lua_apr_shm_type); } static apr_status_t shm_destroy_real(lua_apr_shm *object) { apr_status_t status = APR_SUCCESS; if (object_collectable((lua_apr_refobj*)object)) { if (object->handle != NULL) { status = apr_shm_destroy(object->handle); apr_pool_destroy(object->pool); object->handle = NULL; } } release_object((lua_apr_refobj*)object); return status; } /* apr.shm_create(filename, size) -> shm object {{{1 * * Create and make accessible a shared memory segment. The @filename argument * is the file to use for shared memory on platforms that require it. The @size * argument is the desired size of the segment. * * A note about anonymous vs. named shared memory segments: Not all platforms * support anonymous shared memory segments, but in some cases it is preferred * over other types of shared memory implementations. Passing a nil @filename * parameter to this function will cause the subsystem to use anonymous shared * memory segments. If such a system is not available, the error `'ENOTIMPL'` * is returned as the third return value (the first and second being nil and an * error message string). */ int lua_apr_shm_create(lua_State *L) { apr_status_t status; lua_apr_shm *object; const char *filename; apr_size_t reqsize; filename = lua_isnil(L, 1) ? NULL : luaL_checkstring(L, 1); reqsize = luaL_checkinteger(L, 2); object = new_object(L, &lua_apr_shm_type); if (object == NULL) return push_error_memory(L); status = apr_pool_create(&object->pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); status = apr_shm_create(&object->handle, reqsize, filename, object->pool); if (status != APR_SUCCESS) return push_error_status(L, status); init_shm(L, object); return 1; } /* apr.shm_attach(filename) -> shm object {{{1 * * Attach to a shared memory segment that was created by another process. The * @filename argument is the file used to create the original segment (this * must match the original filename). On success a shared memory object is * returned, otherwise a nil followed by an error message is returned. */ int lua_apr_shm_attach(lua_State *L) { apr_status_t status; lua_apr_shm *object; const char *filename; filename = luaL_checkstring(L, 1); object = new_object(L, &lua_apr_shm_type); status = apr_pool_create(&object->pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); status = apr_shm_attach(&object->handle, filename, object->pool); if (status != APR_SUCCESS) return push_error_status(L, status); init_shm(L, object); return 1; } /* apr.shm_remove(filename) -> status {{{1 * * Remove the named resource associated with a shared memory segment, * preventing attachments to the resource, but not destroying it. On success * true is returned, otherwise a nil followed by an error message is * returned. * * This function is only supported on platforms which support name-based shared * memory segments, and will return the error code `'ENOTIMPL'` on platforms * without such support. Removing the file while the shared memory is in use is * not entirely portable, caller may use this to enhance obscurity of the * resource, but be prepared for the the call to fail, and for concurrent * attempts to create a resource of the same name to also fail. * * Note that the named resource is also removed when a shared memory object * created by `apr.shm_create()` is garbage collected. */ int lua_apr_shm_remove(lua_State *L) { apr_status_t status; const char *filename; filename = luaL_checkstring(L, 1); status = apr_shm_remove(filename, to_pool(L)); return push_status(L, status); } /* shm:read([format, ...]) -> mixed value, ... {{{1 * * This function implements the interface of Lua's `file:read()` function. */ static int shm_read(lua_State *L) { lua_apr_shm *object = check_shm(L, 1); object->last_op = &object->input.buffer; return read_buffer(L, &object->input); } /* shm:write(value [, ...]) -> status {{{1 * * This function implements the interface of Lua's `file:write()` function. */ static int shm_write(lua_State *L) { lua_apr_shm *object = check_shm(L, 1); object->last_op = &object->output.buffer; return write_buffer(L, &object->output); } /* shm:seek([whence [, offset]]) -> offset {{{1 * * This function implements the interface of Lua's `file:seek()` function. */ static int shm_seek(lua_State *L) { const char *const modes[] = { "set", "cur", "end", NULL }; lua_apr_shm *object; size_t offset; int mode; object = check_shm(L, 1); mode = luaL_checkoption(L, 2, "cur", modes); offset = luaL_optlong(L, 3, 0); if (mode == 1) { /* CUR */ offset += object->last_op->index; } else if (mode == 2) { /* END */ offset += object->last_op->limit - 1; } luaL_argcheck(L, offset >= 0, 2, "cannot seek before start of shared memory segment!"); luaL_argcheck(L, offset < object->size, 2, "cannot seek past end of shared memory segment!"); object->input.buffer.index = offset; object->output.buffer.index = offset; lua_pushinteger(L, offset); return 1; } /* shm:detach() -> status {{{1 * * Detach from a shared memory segment without destroying it. On success true * is returned, otherwise a nil followed by an error message is returned. */ static int shm_detach(lua_State *L) { apr_status_t status; lua_apr_shm *object; object = check_shm(L, 1); status = apr_shm_detach(object->handle); return push_status(L, status); } /* shm:destroy() -> status {{{1 * * Destroy a shared memory segment and associated memory. On success true is * returned, otherwise a nil followed by an error message is returned. Note * that this will be done automatically when the shared memory object is * garbage collected and has not already been destroyed. */ static int shm_destroy(lua_State *L) { lua_apr_shm *object; apr_status_t status; object = check_shm(L, 1); status = shm_destroy_real(object); return push_status(L, status); } /* shm:__tostring() {{{1 */ static int shm_tostring(lua_State *L) { lua_apr_shm *object; object = check_shm(L, 1); if (object->handle != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_shm_type.friendlyname, object); else lua_pushfstring(L, "%s (closed)", lua_apr_shm_type.friendlyname); return 1; } /* shm:__gc() {{{1 */ static int shm_gc(lua_State *L) { shm_destroy_real(check_shm(L, 1)); return 0; } /* }}}1 */ static luaL_reg shm_metamethods[] = { { "__tostring", shm_tostring }, { "__eq", objects_equal }, { "__gc", shm_gc }, { NULL, NULL } }; static luaL_reg shm_methods[] = { { "read", shm_read }, { "write", shm_write }, { "seek", shm_seek }, { "detach", shm_detach }, { "destroy", shm_destroy }, { NULL, NULL } }; lua_apr_objtype lua_apr_shm_type = { "lua_apr_shm*", "shared memory", sizeof(lua_apr_shm), shm_methods, shm_metamethods }; lua-apr-0.23.2.dfsg/src/signal.c000066400000000000000000000447101220664456000163040ustar00rootroot00000000000000/* Signal handling module for the Lua/APR binding. * * Author: Peter Odding * Last Change: June 23, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * [Signals] [signals] provide a limited form of inter-process communication. * On UNIX they are for example used to communicate to [daemons] [daemons] that * they should reload their configuration or stop gracefully. This module works * on Linux and most if not all UNIX systems but it's not very useful on * Windows, because [Windows has poor support for signals] [msdn_signals]: * * > `SIGINT` is not supported for any Win32 application, including Windows * > 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs, Win32 * > operating systems generate a new thread to specifically handle that * > interrupt. This can cause a single-thread application such as UNIX, * > to become multithreaded, resulting in unexpected behavior. * > ... * > The `SIGILL`, `SIGSEGV`, and `SIGTERM` signals are not generated under * > Windows NT. They are included for ANSI compatibility. Thus you can set * > signal handlers for these signals with signal(), and you can also * > explicitly generate these signals by calling raise(). * * The following signal related functionality is not exposed by the Lua/APR * binding because the Apache Portable Runtime doesn't wrap the required * functions: * * - APR doesn't expose [kill()] [kill] except through `process:kill()` which * only supports two signals (`SIGTERM` and `SIGKILL`) which means users of * the Lua/APR binding cannot send arbitrary signals to processes (use * [luaposix] [lposix] instead) * * - APR doesn't expose [alarm()][alarm] and Windows doesn't support it which * means the `SIGALRM` signal is useless (use [lalarm] [lalarm] instead) * * [signals]: http://en.wikipedia.org/wiki/Signal_(computing) * [daemons]: http://en.wikipedia.org/wiki/Daemon_(computing) * [msdn_signals]: http://msdn.microsoft.com/en-us/library/xdkz3x12(v=vs.71).aspx * [kill]: http://linux.die.net/man/3/kill * [lposix]: http://luaforge.net/projects/luaposix/ * [alarm]: http://linux.die.net/man/3/alarm * [lalarm]: http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/#lalarm */ #include "lua_apr.h" #include /* Internal functions. {{{1 */ #define REGISTRYKEY "Lua/APR signal handlers table" static void generic_hook(lua_State*, lua_Debug*, int); /* Generated Lua hook handlers. {{{2 */ #ifdef SIGHUP static void sighup_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 0); } #endif #ifdef SIGINT static void sigint_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 1); } #endif #ifdef SIGQUIT static void sigquit_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 2); } #endif #ifdef SIGILL static void sigill_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 3); } #endif #ifdef SIGABRT static void sigabrt_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 4); } #endif #ifdef SIGFPE static void sigfpe_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 5); } #endif #ifdef SIGKILL static void sigkill_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 6); } #endif #ifdef SIGSEGV static void sigsegv_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 7); } #endif #ifdef SIGPIPE static void sigpipe_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 8); } #endif #ifdef SIGALRM static void sigalrm_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 9); } #endif #ifdef SIGTERM static void sigterm_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 10); } #endif #ifdef SIGUSR1 static void sigusr1_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 11); } #endif #ifdef SIGUSR2 static void sigusr2_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 12); } #endif #ifdef SIGCHLD static void sigchld_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 13); } #endif #ifdef SIGCONT static void sigcont_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 14); } #endif #ifdef SIGSTOP static void sigstop_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 15); } #endif #ifdef SIGTSTP static void sigtstp_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 16); } #endif #ifdef SIGTTIN static void sigttin_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 17); } #endif #ifdef SIGTTOU static void sigttou_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 18); } #endif #ifdef SIGBUS static void sigbus_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 19); } #endif #ifdef SIGPOLL static void sigpoll_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 20); } #endif #ifdef SIGPROF static void sigprof_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 21); } #endif #ifdef SIGSYS static void sigsys_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 22); } #endif #ifdef SIGTRAP static void sigtrap_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 23); } #endif #ifdef SIGURG static void sigurg_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 24); } #endif #ifdef SIGVTALRM static void sigvtalrm_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 25); } #endif #ifdef SIGXCPU static void sigxcpu_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 26); } #endif #ifdef SIGXFSZ static void sigxfsz_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 27); } #endif #ifdef SIGIOT static void sigiot_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 28); } #endif #ifdef SIGEMT static void sigemt_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 29); } #endif #ifdef SIGSTKFLT static void sigstkflt_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 30); } #endif #ifdef SIGIO static void sigio_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 31); } #endif #ifdef SIGCLD static void sigcld_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 32); } #endif #ifdef SIGPWR static void sigpwr_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 33); } #endif #ifdef SIGINFO static void siginfo_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 34); } #endif #ifdef SIGLOST static void siglost_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 35); } #endif #ifdef SIGWINCH static void sigwinch_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 36); } #endif #ifdef SIGUNUSED static void sigunused_hook(lua_State *L, lua_Debug *ar) { generic_hook(L, ar, 37); } #endif /* Generated signal table. {{{2 */ static struct { const char *name; /* Symbolic name of signal (used in Lua) */ const int value; /* Integer code of signal (used in C) */ void (*hook)(lua_State*, lua_Debug*); /* Lua hook to be called by signal handler */ lua_State *state; /* Lua state that installed signal handler */ lua_Hook oldhook; /* Old debug hook and related variables */ int oldmask, oldcount; } signaltable[] = { # ifdef SIGHUP { "SIGHUP", SIGHUP, sighup_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGINT { "SIGINT", SIGINT, sigint_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGQUIT { "SIGQUIT", SIGQUIT, sigquit_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGILL { "SIGILL", SIGILL, sigill_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGABRT { "SIGABRT", SIGABRT, sigabrt_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGFPE { "SIGFPE", SIGFPE, sigfpe_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGKILL { "SIGKILL", SIGKILL, sigkill_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGSEGV { "SIGSEGV", SIGSEGV, sigsegv_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGPIPE { "SIGPIPE", SIGPIPE, sigpipe_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGALRM { "SIGALRM", SIGALRM, sigalrm_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGTERM { "SIGTERM", SIGTERM, sigterm_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGUSR1 { "SIGUSR1", SIGUSR1, sigusr1_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGUSR2 { "SIGUSR2", SIGUSR2, sigusr2_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGCHLD { "SIGCHLD", SIGCHLD, sigchld_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGCONT { "SIGCONT", SIGCONT, sigcont_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGSTOP { "SIGSTOP", SIGSTOP, sigstop_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGTSTP { "SIGTSTP", SIGTSTP, sigtstp_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGTTIN { "SIGTTIN", SIGTTIN, sigttin_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGTTOU { "SIGTTOU", SIGTTOU, sigttou_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGBUS { "SIGBUS", SIGBUS, sigbus_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGPOLL { "SIGPOLL", SIGPOLL, sigpoll_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGPROF { "SIGPROF", SIGPROF, sigprof_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGSYS { "SIGSYS", SIGSYS, sigsys_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGTRAP { "SIGTRAP", SIGTRAP, sigtrap_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGURG { "SIGURG", SIGURG, sigurg_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGVTALRM { "SIGVTALRM", SIGVTALRM, sigvtalrm_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGXCPU { "SIGXCPU", SIGXCPU, sigxcpu_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGXFSZ { "SIGXFSZ", SIGXFSZ, sigxfsz_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGIOT { "SIGIOT", SIGIOT, sigiot_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGEMT { "SIGEMT", SIGEMT, sigemt_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGSTKFLT { "SIGSTKFLT", SIGSTKFLT, sigstkflt_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGIO { "SIGIO", SIGIO, sigio_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGCLD { "SIGCLD", SIGCLD, sigcld_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGPWR { "SIGPWR", SIGPWR, sigpwr_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGINFO { "SIGINFO", SIGINFO, siginfo_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGLOST { "SIGLOST", SIGLOST, siglost_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGWINCH { "SIGWINCH", SIGWINCH, sigwinch_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif # ifdef SIGUNUSED { "SIGUNUSED", SIGUNUSED, sigunused_hook, NULL, NULL, 0, 0 }, # else { NULL, 0, NULL, NULL, NULL, 0, 0 }, # endif }; /* Name to table index mapping. {{{2 */ static int check_signal_name(lua_State *L, int idx) { int sigidx; const char *name; name = luaL_checkstring(L, idx); for (sigidx = 0; sigidx < count(signaltable) - 1; sigidx++) if (signaltable[sigidx].name != NULL && strcmp(name, signaltable[sigidx].name) == 0) return sigidx; return luaL_argerror(L, 1, lua_pushfstring(L, "signal %s not supported", name)); } /* Generic Lua hook. {{{2 */ static void generic_hook(lua_State *L, lua_Debug *ar, int sigidx) { int top = lua_gettop(L); lua_sethook(L, signaltable[sigidx].oldhook, signaltable[sigidx].oldmask, signaltable[sigidx].oldcount); lua_pushliteral(L, REGISTRYKEY); lua_gettable(L, LUA_REGISTRYINDEX); if (lua_istable(L, -1)) { lua_rawgeti(L, -1, sigidx); if (lua_type(L, -1) == LUA_TFUNCTION) lua_call(L, 0, 0); } lua_settop(L, top); } /* Signal handler function. {{{2 */ static void signal_function(int signo) { int sigidx; /* I've tried speeding this up by generating a switch statement but got * duplicate value errors and decided that it wasn't worth the trouble. */ for (sigidx = 0; sigidx < count(signaltable) - 1; sigidx++) { if (signo == signaltable[sigidx].value) { signaltable[sigidx].oldhook = lua_gethook(signaltable[sigidx].state); signaltable[sigidx].oldmask = lua_gethookmask(signaltable[sigidx].state); signaltable[sigidx].oldcount = lua_gethookcount(signaltable[sigidx].state); lua_sethook(signaltable[sigidx].state, signaltable[sigidx].hook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); break; } } } /* apr.signal(name [, handler]) -> status {{{1 * * Set the signal handler function for a given signal. The argument @name must * be a string with the name of the signal to handle (`apr.signal_names()` * returns a table of available names on your platform). The argument @handler * must be of type function, unless it is nil in which case default handling * is restored for the given signal. On success true is returned, otherwise a * nil followed by an error message is returned. */ int lua_apr_signal(lua_State *L) { int sigidx; /* Check arguments. */ sigidx = check_signal_name(L, 1); if (!lua_isnil(L, 2)) luaL_checktype(L, 2, LUA_TFUNCTION); /* Get the Lua table with signal handlers. */ lua_pushliteral(L, REGISTRYKEY); lua_gettable(L, LUA_REGISTRYINDEX); if (lua_isnil(L, -1)) { /* Table didn't exist yet, create it. */ lua_pop(L, 1); lua_newtable(L); /* Add the table to the registry. */ lua_pushliteral(L, REGISTRYKEY); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); } /* Save or clear the Lua side signal handler function in the table. */ lua_pushvalue(L, 2); lua_rawseti(L, -2, sigidx); /* Remember the Lua state that installed the signal handler. */ signaltable[sigidx].state = L; /* Install or clear the C side signal handler function. */ lua_pushboolean(L, apr_signal(signaltable[sigidx].value, lua_isnil(L, 2) ? SIG_DFL : signal_function) != SIG_ERR); return 1; } /* apr.signal_raise(name) -> status {{{1 * * Send a signal to *the current process*. The result is true when the call * succeeded, false otherwise. This function is useful to test your own signal * handlers: * * > = apr.signal('SIGSEGV', function() print 'almost crashed :-)' end) * true * > = apr.signal_raise('SIGSEGV') * almost crashed :-) * true * > = apr.signal('SIGSEGV', nil) * true * > = apr.signal_raise('SIGSEGV') * zsh: segmentation fault lua */ int lua_apr_signal_raise(lua_State *L) { int sigidx, status; sigidx = check_signal_name(L, 1); status = raise(signaltable[sigidx].value); lua_pushboolean(L, status == 0); return 1; } /* apr.signal_block(name) -> status {{{1 * * Block the delivery of a particular signal. On success true is returned, * otherwise a nil followed by an error message is returned. */ int lua_apr_signal_block(lua_State *L) { apr_status_t status; int sigidx; sigidx = check_signal_name(L, 1); status = apr_signal_block(signaltable[sigidx].value); return push_status(L, status); } /* apr.signal_unblock(name) -> status {{{1 * * Enable the delivery of a particular signal. On success true is returned, * otherwise a nil followed by an error message is returned. */ int lua_apr_signal_unblock(lua_State *L) { apr_status_t status; int sigidx; sigidx = check_signal_name(L, 1); status = apr_signal_unblock(signaltable[sigidx].value); return push_status(L, status); } /* apr.signal_names() -> names {{{1 * * Return a table with available signal names on your platform. The keys of the * table are the names of the signals and the values are the integer codes * associated with the signals. * * As the previous paragraph implies the result of this function can differ * depending on your operating system and processor architecture. For example * on my Ubuntu Linux 10.04 installation I get these results: * * > signals = {} * > for k, v in pairs(apr.signal_names()) do * >> table.insert(signals, { name = k, value = v }) * >> end * > table.sort(signals, function(a, b) * >> return a.value < b.value * >> end) * > for _, s in ipairs(signals) do * >> print(string.format('% 2i: %s', s.value, s.name)) * >> end * 1: SIGHUP * 2: SIGINT * 3: SIGQUIT * 4: SIGILL * 5: SIGTRAP * 6: SIGIOT * 6: SIGABRT * 7: SIGBUS * 8: SIGFPE * 9: SIGKILL * 10: SIGUSR1 * 11: SIGSEGV * 12: SIGUSR2 * 13: SIGPIPE * 14: SIGALRM * 15: SIGTERM * 16: SIGSTKFLT * 17: SIGCHLD * 17: SIGCLD * 18: SIGCONT * 19: SIGSTOP * 20: SIGTSTP * 21: SIGTTIN * 22: SIGTTOU * 23: SIGURG * 24: SIGXCPU * 25: SIGXFSZ * 26: SIGVTALRM * 27: SIGPROF * 28: SIGWINCH * 29: SIGPOLL * 29: SIGIO * 30: SIGPWR * 31: SIGSYS * * After creating the above table I was surprised to see several numbers which * have two names in the above output, but after looking up the names it turns * out that these are just synonyms. * * Note that just because a signal is included in this table doesn't * necessarily mean the signal is usable from Lua! For example [SIGALRM] * [sigalrm] is only useful when you can call the alarm() function defined by * [POSIX][posix] but that function isn't exposed by the Apache Portable * Runtime (you can use [lalarm] [lalarm] instead in this case). * * [sigalrm]: http://en.wikipedia.org/wiki/SIGALRM * [posix]: http://en.wikipedia.org/wiki/POSIX */ int lua_apr_signal_names(lua_State *L) { int sigidx; lua_newtable(L); for (sigidx = 0; sigidx < count(signaltable) - 1; sigidx++) { if (signaltable[sigidx].name != NULL) { lua_pushstring(L, signaltable[sigidx].name); lua_pushinteger(L, signaltable[sigidx].value); lua_rawset(L, -3); } } return 1; } lua-apr-0.23.2.dfsg/src/stat.c000066400000000000000000000112451220664456000157770ustar00rootroot00000000000000/* File status querying (stat()) for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 28, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include #include /* Lua/APR introduces one new field to the apr_stat() interface, which is the * filepath. It's defined to 0 so it won't influence the .wanted bitfield :) */ #define APR_FINFO_PATH 0 static const char *const options[] = { "atime", "csize", "ctime", "dev", "group", "inode", "link", "mtime", "name", "nlink", "path", "size", "type", "protection", "user", NULL }; static const apr_int32_t flags[] = { APR_FINFO_ATIME, APR_FINFO_CSIZE, APR_FINFO_CTIME, APR_FINFO_DEV, APR_FINFO_GROUP, APR_FINFO_INODE, APR_FINFO_LINK, APR_FINFO_MTIME, APR_FINFO_NAME, APR_FINFO_NLINK, APR_FINFO_PATH, APR_FINFO_SIZE, APR_FINFO_TYPE, APR_FINFO_UPROT | APR_FINFO_GPROT | APR_FINFO_WPROT, APR_FINFO_USER }; void push_stat_field(lua_State*, apr_finfo_t*, apr_int32_t, const char*); void check_stat_request(lua_State *L, lua_apr_stat_context *ctx) { apr_int32_t flag; int i; ctx->count = 0; ctx->wanted = 0; for (i = ctx->firstarg; i - ctx->firstarg <= count(flags) && !lua_isnoneornil(L, i) && i <= ctx->lastarg; i++) { ctx->wanted |= flag = flags[luaL_checkoption(L, i, NULL, options)]; if (APR_FINFO_LINK != flag) ctx->fields[ctx->count++] = flag; } if (ctx->count == 0) for (i = 0; i < count(flags); ++i) ctx->wanted |= flags[i]; } int push_stat_results(lua_State *L, lua_apr_stat_context *ctx, const char *path) { int i; if (0 == ctx->count) { lua_createtable(L, 0, ctx->count); for (i = 0; i < count(flags); i++) { if (APR_FINFO_LINK != flags[i] && (ctx->info.valid & flags[i]) == flags[i]) { lua_pushstring(L, options[i]); push_stat_field(L, &ctx->info, flags[i], path); lua_rawset(L, -3); } } return 1; } else { for (i = 0; i < ctx->count; i++) { if ((ctx->info.valid & ctx->fields[i]) == ctx->fields[i]) { push_stat_field(L, &ctx->info, ctx->fields[i], path); } else { lua_pushboolean(L, 0); } } return ctx->count; } } void push_stat_field(lua_State *L, apr_finfo_t *info, apr_int32_t which, const char *path) { switch (which) { /* user/group name */ case APR_FINFO_USER: if (!push_username(L, info->pool, info->user)) lua_pushnil(L); break; case APR_FINFO_GROUP: push_groupname(L, info->pool, info->group); break; /* dates */ case APR_FINFO_CTIME: time_push(L, info->ctime); break; case APR_FINFO_MTIME: time_push(L, info->mtime); break; case APR_FINFO_ATIME: time_push(L, info->atime); break; /* numbers */ case APR_FINFO_SIZE: lua_pushinteger(L, (lua_Integer) info->size); break; case APR_FINFO_CSIZE: lua_pushinteger(L, (lua_Integer) info->csize); break; case APR_FINFO_INODE: lua_pushinteger(L, (lua_Integer) info->inode); break; case APR_FINFO_NLINK: lua_pushinteger(L, (lua_Integer) info->nlink); break; case APR_FINFO_DEV: lua_pushinteger(L, (lua_Integer) info->device); break; /* file path / name */ case APR_FINFO_PATH: if (path && 0 != strcmp(path, ".")) { char *filepath; apr_status_t status; status = apr_filepath_merge(&filepath, path, info->name, 0, info->pool); if (APR_SUCCESS == status) { lua_pushstring(L, filepath); break; } } /* fall through */ case APR_FINFO_NAME: lua_pushstring(L, info->name); break; /* type */ case APR_FINFO_TYPE: switch (info->filetype) { case APR_LNK: lua_pushliteral(L, "link"); break; case APR_REG: lua_pushliteral(L, "file"); break; case APR_PIPE: lua_pushliteral(L, "pipe"); break; case APR_SOCK: lua_pushliteral(L, "socket"); break; case APR_DIR: lua_pushliteral(L, "directory"); break; case APR_BLK: lua_pushliteral(L, "block device"); break; case APR_CHR: lua_pushliteral(L, "character device"); break; default: lua_pushliteral(L, "unknown"); break; } break; /* protection tables */ case APR_FINFO_UPROT | APR_FINFO_GPROT | APR_FINFO_WPROT: push_protection(L, info->protection); break; /* Error in Lua/APR :( */ default: assert(0); lua_pushnil(L); } } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/str.c000066400000000000000000000132471220664456000156400ustar00rootroot00000000000000/* String routines module for the Lua/APR binding. * * Author: Peter Odding * Last Change: January 3, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include /* apr.strnatcmp(left, right) -> status {{{1 * * Do a [natural order comparison] [natsort] of two strings. Returns true when * the @left string is less than the @right string, false otherwise. This * function can be used as a callback for Lua's standard library function * `table.sort()`. * * > -- the canonical example: * > list = { 'rfc1.txt', 'rfc2086.txt', 'rfc822.txt' } * > -- collate order: * > table.sort(list) * > for _, name in ipairs(list) do print(name) end * rfc1.txt * rfc2086.txt * rfc822.txt * > -- natural order: * > table.sort(list, apr.strnatcmp) * > for _, name in ipairs(list) do print(name) end * rfc1.txt * rfc822.txt * rfc2086.txt * * [natsort]: http://sourcefrog.net/projects/natsort/ */ int lua_apr_strnatcmp(lua_State *L) { const char *a, *b; int difference; a = luaL_checkstring(L, 1); b = luaL_checkstring(L, 2); difference = apr_strnatcmp(a, b); lua_pushboolean(L, difference < 0); return 1; } /* apr.strnatcasecmp(left, right) -> status {{{1 * * Like `apr.strnatcmp()`, but ignores the case of the strings. */ int lua_apr_strnatcasecmp(lua_State *L) { const char *a, *b; int difference; a = luaL_checkstring(L, 1); b = luaL_checkstring(L, 2); difference = apr_strnatcasecmp(a, b); lua_pushboolean(L, difference < 0); return 1; } /* apr.strfsize(number [, padding]) -> readable {{{1 * * Format a binary size positive @number to a compacted human readable string. * If the optional @padding argument evaluates to true the resulting string * will be padded with spaces to make it four characters wide, otherwise no * padding will be applied. * * > = apr.strfsize(1024) * '1.0K' * > = apr.strfsize(1024 ^ 2) * '1.0M' * > = apr.strfsize(1024 ^ 3) * '1.0G' * * Here's a simplified implementation of the [UNIX] [unix] command `ls -l * --human-readable` which makes use of the @padding argument to nicely line up * the fields following the size: * * function ls(dirpath) * local directory = assert(apr.dir_open(dirpath)) * for info in directory:entries() do * io.write(info.protection, ' ') * io.write(info.user, ' ') * io.write(info.group, ' ') * io.write(apr.strfsize(info.size, true), ' ') * io.write(apr.time_format('%Y-%m-%d %H:%I', info.ctime), ' ') * io.write(info.name, '\n') * end * assert(directory:close()) * end * * This is what the result looks like for the [source code directory] [srcdir] * of the Lua/APR project: * * > ls 'lua-apr/src' * rw-r--r-- peter peter 5.4K 2011-01-02 22:10 apr.lua * rw-r--r-- peter peter 4.7K 2011-01-02 06:06 base64.c * rw-r--r-- peter peter 11K 2010-10-27 13:01 buffer.c * rw-r--r-- peter peter 13K 2011-01-02 21:09 crypt.c * rw-r--r-- peter peter 2.8K 2010-12-31 01:01 date.c * rw-r--r-- peter peter 9.4K 2011-01-01 16:04 dbm.c * rw-r--r-- peter peter 2.5K 2010-09-25 23:11 env.c * rw-r--r-- peter peter 17K 2011-01-02 22:10 errno.c * rw-r--r-- peter peter 10K 2011-01-02 22:10 filepath.c * rw-r--r-- peter peter 1.9K 2011-01-02 04:04 fnmatch.c * rw-r--r-- peter peter 12K 2010-12-31 01:01 io_dir.c * rw-r--r-- peter peter 25K 2011-01-02 04:04 io_file.c * rw-r--r-- peter peter 17K 2010-12-31 01:01 io_net.c * rw-r--r-- peter peter 4.6K 2011-01-02 22:10 io_pipe.c * rw-r--r-- peter peter 11K 2011-01-02 11:11 lua_apr.c * rw-r--r-- peter peter 9.0K 2011-01-02 11:11 lua_apr.h * rw-r--r-- peter peter 6.9K 2010-12-29 14:02 permissions.c * rw-r--r-- peter peter 26K 2011-01-02 22:10 proc.c * rw-r--r-- peter peter 866 2010-10-23 00:12 refpool.c * rw-r--r-- peter peter 4.8K 2010-12-29 14:02 stat.c * rw-r--r-- peter peter 3.5K 2011-01-02 22:10 str.c * rw-r--r-- peter peter 9.8K 2010-12-31 01:01 time.c * rw-r--r-- peter peter 4.7K 2010-09-25 23:11 uri.c * rw-r--r-- peter peter 2.5K 2010-09-25 23:11 user.c * rw-r--r-- peter peter 2.9K 2010-10-22 19:07 uuid.c * rw-r--r-- peter peter 3.8K 2011-01-02 04:04 xlate.c * * Note: It seems that `apr.strfsize()` doesn't support terabyte range sizes. * * [srcdir]: https://github.com/xolox/lua-apr/tree/master/src */ int lua_apr_strfsize(lua_State *L) { apr_off_t number; char buffer[5]; int padding, offset = 0, length = 4; number = (apr_off_t) luaL_checklong(L, 1); padding = lua_gettop(L) > 1 && lua_toboolean(L, 2); luaL_argcheck(L, number >= 0, 1, "must be non-negative"); apr_strfsize(number, buffer); while (!padding && buffer[offset] == ' ') offset++; while (!padding && buffer[length-1] == ' ') length--; lua_pushlstring(L, &buffer[offset], length - offset); return 1; } /* apr.tokenize_to_argv(cmdline) -> arguments {{{1 * * Convert the string @cmdline to a table of arguments. On success the table of * arguments is returned, otherwise a nil followed by an error message is * returned. */ int lua_apr_tokenize_to_argv(lua_State *L) { apr_status_t status; apr_pool_t *pool; const char *str; char **argv; int i; pool = to_pool(L); str = luaL_checkstring(L, 1); status = apr_tokenize_to_argv(str, &argv, pool); if (APR_SUCCESS != status) return push_error_status(L, status); lua_newtable(L); for (i = 0; NULL != argv[i]; i++) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i + 1); } return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/thread.c000066400000000000000000000247321220664456000163000ustar00rootroot00000000000000/* Multi threading module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 20, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * This is an experimental multi threading module that makes it possible to * execute Lua functions in dedicated [Lua states] [Lua_state] and [operating * system threads] [threading]. When you create a thread you can pass it any * number of arguments and when a thread exits it can return any number of * return values. For details about supported Lua values see the documentation * of the [serialization](#serialization) module. * * Please consider the following issues when using this module: * * - When you pass a userdata object to another thread you shouldn't use it * from the original thread after that, because the Lua/APR binding doesn't * protect object access with a thread safe lock. This will probably be * fixed in the near future (hey, I said it was experimental) * * - When you start a thread and let it get garbage collected without having * called `thread:join()`, the thread will be joined for you (because * failing to do so while the main thread is terminating can crash the * process) * * [Lua_state]: http://www.lua.org/manual/5.1/manual.html#lua_State * [threading]: http://en.wikipedia.org/wiki/Thread_%28computer_science%29 * [libc]: http://en.wikipedia.org/wiki/C_standard_library */ #include "lua_apr.h" #include #include #include #if APR_HAS_THREADS /* Private parts. {{{1 */ const char *status_names[] = { "init", "running", "done", "error" }; #define check_thread(L, idx) \ (lua_apr_thread_object*)check_object(L, idx, &lua_apr_thread_type) #define thread_busy(T) \ ((T)->status == TS_INIT || (T)->status == TS_RUNNING) typedef enum { TS_INIT, TS_RUNNING, TS_DONE, TS_ERROR } thread_status_t; typedef struct { lua_apr_refobj header; apr_pool_t *pool; apr_thread_t *handle; apr_threadattr_t *attr; void *input, *output; char *path, *cpath, *config; volatile thread_status_t status; int joined; } lua_apr_thread_object; /* error_handler(state) {{{2 */ /* Copied from lua-5.1.4/src/lua.c where it's called traceback() */ static int error_handler(lua_State *L) { if (!lua_isstring(L, 1)) /* 'message' not a string? */ return 1; /* keep it intact */ lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; } lua_getfield(L, -1, "traceback"); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return 1; } lua_pushvalue(L, 1); /* pass error message */ lua_pushinteger(L, 2); /* skip this function and traceback */ lua_call(L, 2, 1); /* call debug.traceback */ return 1; } /* thread_destroy(thread) {{{2 */ static void thread_destroy(lua_apr_thread_object *thread) { if (object_collectable((lua_apr_refobj*)thread)) { free(thread->output); } release_object((lua_apr_refobj*)thread); } /* thread_runner(handle, thread) {{{2 */ static void* lua_apr_cc thread_runner(apr_thread_t *handle, lua_apr_thread_object *thread) { const char *function; size_t length; lua_State *L; int status; /* The child thread is now using the thread structure. */ object_incref((lua_apr_refobj*)thread); /* Start by creating a new Lua state. */ if ((L = luaL_newstate()) == NULL) { status = TS_ERROR; thread->output = strdup("Failed to create Lua state"); } else { /* Load the standard libraries. */ luaL_openlibs(L); /* Apply package.{config,path,cpath} values from parent Lua state. */ lua_getglobal(L, "package"); lua_pushstring(L, thread->config); lua_setfield(L, -2, "config"); lua_pushstring(L, thread->path); lua_setfield(L, -2, "path"); lua_pushstring(L, thread->cpath); lua_setfield(L, -2, "cpath"); /* (0) Normalize the stack. */ lua_settop(L, 0); /* (1) Push the error handler. */ lua_pushcfunction(L, error_handler); /* (2..n) Unserialize thread function and arguments. * FIXME What if lua_apr_unserialize() raises an error? */ lua_pushstring(L, thread->input); lua_apr_unserialize(L); status = TS_INIT; /* XXX The threading module should work even if the serialization module * fails to serialize function objects, so if the first argument to * apr.thread() is a string, we convert it to a function here. */ if (lua_isstring(L, 2)) { function = lua_tolstring(L, 2, &length); if (luaL_loadbuffer(L, function, length, function)) { /* Failed to compile chunk. */ thread->output = strdup(lua_tostring(L, -1)); status = TS_ERROR; } else { /* Replace string with chunk. */ lua_replace(L, 2); } } if (status != TS_ERROR) { thread->status = TS_RUNNING; if (lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 1)) { thread->output = strdup(lua_tostring(L, -1)); status = TS_ERROR; } else { lua_apr_serialize(L, 2); thread->output = strdup(lua_tostring(L, -1)); status = TS_DONE; } } lua_close(L); } thread->status = status; thread_destroy(thread); apr_thread_exit(handle, APR_SUCCESS); /* To make the compiler happy. */ return NULL; } /* apr.thread(f [, ...]) -> thread {{{1 * * Execute the Lua function @f in a dedicated Lua state and operating system * thread. Any extra arguments are passed onto the function. On success a * thread object is returned, otherwise a nil followed by an error message is * returned. You can use `thread:join()` to wait for the thread to finish and * get the return values of the thread function. * * *This function is binary safe.* */ int lua_apr_thread(lua_State *L) { lua_apr_thread_object *thread = NULL; apr_status_t status = APR_ENOMEM; int input_idx; /* Serialize the thread function and any arguments. */ lua_apr_serialize(L, 1); input_idx = lua_gettop(L); /* Create the Lua/APR thread object. */ thread = new_object(L, &lua_apr_thread_type); if (thread == NULL) goto fail; thread->status = TS_INIT; /* Create a memory pool for the thread (freed by apr_thread_exit()). */ status = apr_pool_create(&thread->pool, NULL); if (status != APR_SUCCESS) goto fail; /* Copy the serialized thread function to the thread's memory pool. */ thread->input = apr_pstrdup(thread->pool, lua_tostring(L, input_idx)); # define get_package_value(fieldname, fieldptr) \ lua_getfield(L, -1, fieldname); \ if (lua_isstring(L, -1)) \ fieldptr = apr_pstrdup(thread->pool, lua_tostring(L, -1)); \ lua_pop(L, 1); /* Copy package.{config,path,cpath} to the thread's Lua state. */ lua_getglobal(L, "package"); if (lua_istable(L, -1)) { get_package_value("config", thread->config); get_package_value("path", thread->path); get_package_value("cpath", thread->cpath); } lua_pop(L, 1); /* Start the operating system thread. */ status = apr_threadattr_create(&thread->attr, thread->pool); if (status == APR_SUCCESS) status = apr_thread_create(&thread->handle, thread->attr, (apr_thread_start_t)thread_runner, thread, thread->pool); if (status != APR_SUCCESS) goto fail; /* Return the thread object. */ return 1; fail: if (thread != NULL) thread_destroy(thread); return push_error_status(L, status); } /* apr.thread_yield() -> nothing {{{1 * * Force the current thread to yield the processor. This causes the currently * executing thread to temporarily pause and allow other threads to execute. */ int lua_apr_thread_yield(lua_State *L) { apr_thread_yield(); return 0; } /* thread:join() -> status [, result, ...] {{{1 * * Block until a thread stops executing and return its result. If the thread * terminated with an error a nil followed by an error message is returned, * otherwise true is returned, followed by any return values of the thread * function. * * *This function is binary safe.* */ static int thread_join(lua_State *L) { lua_apr_thread_object *object; apr_status_t status, unused; object = check_thread(L, 1); lua_settop(L, 1); /* Don't join more than once. */ if (!object->joined) { status = apr_thread_join(&unused, object->handle); if (status != APR_SUCCESS) return push_error_status(L, status); object->joined = 1; } /* Push the status and any results. */ if (object->status == TS_DONE) { lua_pushboolean(L, 1); lua_pushstring(L, object->output); lua_apr_unserialize(L); } else { lua_pushboolean(L, 0); lua_pushstring(L, object->output); } return lua_gettop(L) - 1; } /* thread:status() -> status {{{1 * * Returns a string describing the state of the thread: * * - `'running'`: the thread is currently running * - `'done'`: the thread terminated successfully * - `'error'`: the thread encountered an error */ static int thread_status(lua_State *L) { lua_apr_thread_object *object; object = check_thread(L, 1); lua_pushstring(L, status_names[object->status]); return 1; } /* thread:__tostring() {{{1 */ static int thread_tostring(lua_State *L) { lua_apr_thread_object *object = check_thread(L, 1); lua_pushfstring(L, "%s (%s)", lua_apr_thread_type.friendlyname, status_names[object->status]); return 1; } /* thread:__gc() {{{1 */ static int thread_gc(lua_State *L) { lua_apr_thread_object *thread; apr_status_t status, unused; thread = check_thread(L, 1); if (!thread->joined) { fprintf(stderr, "Lua/APR joining child thread from __gc() hook ..\n"); status = apr_thread_join(&unused, thread->handle); if (status != APR_SUCCESS) { char message[LUA_APR_MSGSIZE]; apr_strerror(status, message, count(message)); fprintf(stderr, "Lua/APR failed to join thread: %s\n", message); } else if (thread->status == TS_ERROR) { fprintf(stderr, "Lua/APR thread exited with error: %s\n", (char*)thread->output); } } thread_destroy(thread); return 0; } /* Lua/APR thread object metadata {{{1 */ static luaL_Reg thread_methods[] = { { "join", thread_join }, { "status", thread_status }, { NULL, NULL } }; static luaL_Reg thread_metamethods[] = { { "__tostring", thread_tostring }, { "__eq", objects_equal }, { "__gc", thread_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_thread_type = { "lua_apr_thread_object*", /* metatable name in registry */ "thread", /* friendly object name */ sizeof(lua_apr_thread_object), /* structure size */ thread_methods, /* methods table */ thread_metamethods /* metamethods table */ }; #endif lua-apr-0.23.2.dfsg/src/thread_queue.c000066400000000000000000000162161220664456000175020ustar00rootroot00000000000000/* Thread queues module for the Lua/APR binding. * * Author: Peter Odding * Last Change: November 20, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * The valid types that can be transported through thread queues are documented * under the [serialization](#serialization) module. The example of a [multi * threaded webserver](#example_multi_threaded_webserver) uses a thread queue * to pass sockets between the main server thread and several worker threads. */ #include "lua_apr.h" #if APR_HAS_THREADS #define check_queue(L, idx) \ ((lua_apr_queue*)check_object((L), (idx), &lua_apr_queue_type)) /* Structure for thread queue objects. */ typedef struct { lua_apr_refobj header; apr_pool_t *pool; apr_queue_t *handle; } lua_apr_queue; /* Internal functions. {{{1 */ static void close_queue_real(lua_apr_queue *object) { if (object_collectable((lua_apr_refobj*)object)) { if (object->pool != NULL) { apr_pool_destroy(object->pool); object->pool = NULL; } } release_object((lua_apr_refobj*)object); } typedef apr_status_t (lua_apr_cc *apr_queue_push_func)(apr_queue_t*, void*); static int queue_push_real(lua_State *L, apr_queue_push_func cb) { lua_apr_queue *object; apr_status_t status; void *data; object = check_queue(L, 1); lua_apr_serialize(L, 2); data = strdup(lua_tostring(L, -1)); status = cb(object->handle, data); return push_status(L, status); } typedef apr_status_t (lua_apr_cc *apr_queue_pop_func)(apr_queue_t*, void**); static int queue_pop_real(lua_State *L, apr_queue_pop_func cb) { lua_apr_queue *object; apr_status_t status; void *data; lua_settop(L, 1); object = check_queue(L, 1); status = cb(object->handle, &data); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushstring(L, data); free(data); lua_apr_unserialize(L); return lua_gettop(L) - 1; } /* apr.thread_queue([capacity]) -> queue {{{1 * * Create a [FIFO] [fifo] [queue] [wp:queue]. The optional argument @capacity * controls the maximum size of the queue and defaults to 1. On success the * queue object is returned, otherwise a nil followed by an error message is * returned. * * The capacity of a thread queue cannot be changed after construction. * * [wp:fifo]: http://en.wikipedia.org/wiki/FIFO * [wp:queue]: http://en.wikipedia.org/wiki/Queue_%28abstract_data_type%29 */ int lua_apr_thread_queue(lua_State *L) { apr_status_t status; lua_apr_queue *object; unsigned int capacity; capacity = luaL_optlong(L, 1, 1); luaL_argcheck(L, capacity >= 1, 1, "capacity must be >= 1"); object = new_object(L, &lua_apr_queue_type); status = apr_pool_create(&object->pool, NULL); if (status == APR_SUCCESS) status = apr_queue_create(&object->handle, capacity, object->pool); if (status != APR_SUCCESS) return push_error_status(L, status); return 1; } /* queue:push(value [, ...]) -> status {{{1 * * Add a tuple of one or more Lua values to the queue. This call will block if * the queue is full. On success true is returned, otherwise a nil followed by * an error message and error code is returned: * * - `'EINTR'`: the blocking was interrupted (try again) * - `'EOF'`: the queue has been terminated * * *This function is binary safe.* */ static int queue_push(lua_State *L) { return queue_push_real(L, apr_queue_push); } /* queue:pop() -> value [, ...] {{{1 * * Get one or more Lua values from the queue. This call will block if the queue * is empty. On success true is returned, otherwise a nil followed by an error * message and error code is returned: * * - `'EINTR'`: the blocking was interrupted (try again) * - `'EOF'`: the queue has been terminated * * *This function is binary safe.* */ static int queue_pop(lua_State *L) { return queue_pop_real(L, apr_queue_pop); } /* queue:trypush(value [, ...]) -> status {{{1 * * Add a tuple of one or more Lua values to the queue. This call doesn't block * if the queue is full. On success true is returned, otherwise a nil followed * by an error message and error code is returned: * * - `'EINTR'`: the blocking was interrupted (try again) * - `'EAGAIN'`: the queue is full * - `'EOF'`: the queue has been terminated * * *This function is binary safe.* */ static int queue_trypush(lua_State *L) { return queue_push_real(L, apr_queue_trypush); } /* queue:trypop() -> value [, ...] {{{1 * * Get a tuple of Lua values from the queue. This call doesn't block if the * queue is empty. On success true is returned, otherwise a nil followed by an * error message and error code is returned: * * - `'EINTR'`: the blocking was interrupted (try again) * - `'EAGAIN'`: the queue is empty * - `'EOF'`: the queue has been terminated * * *This function is binary safe.* */ static int queue_trypop(lua_State *L) { return queue_pop_real(L, apr_queue_trypop); } /* queue:interrupt() -> status {{{1 * * Interrupt all the threads blocking on this queue. On success true is * returned, otherwise a nil followed by an error message is returned. */ static int queue_interrupt(lua_State *L) { apr_status_t status; lua_apr_queue *object; object = check_queue(L, 1); status = apr_queue_interrupt_all(object->handle); return push_status(L, status); } /* queue:terminate() -> status {{{1 * * Terminate the queue, sending an interrupt to all the blocking threads. On * success true is returned, otherwise a nil followed by an error message is * returned. */ static int queue_terminate(lua_State *L) { apr_status_t status; lua_apr_queue *object; object = check_queue(L, 1); status = apr_queue_term(object->handle); return push_status(L, status); } /* queue:close() -> status {{{1 * * Close the handle @queue and (if no other threads are using the queue) * destroy the queue and release the associated memory. This function always * returns true (it cannot fail). * * This will be done automatically when the @queue object is garbage collected * which means you don't need to call this unless you want to reclaim memory as * soon as possible. */ static int queue_close(lua_State *L) { close_queue_real(check_queue(L, 1)); lua_pushboolean(L, 1); return 1; } /* queue:__tostring() {{{1 */ static int queue_tostring(lua_State *L) { lua_pushfstring(L, "%s (%p)", lua_apr_queue_type.friendlyname, check_queue(L, 1)); return 1; } /* queue:__gc() {{{1 */ static int queue_gc(lua_State *L) { close_queue_real(check_queue(L, 1)); return 0; } /* }}}1 */ static luaL_Reg queue_methods[] = { { "push", queue_push }, { "pop", queue_pop }, { "trypush", queue_trypush }, { "trypop", queue_trypop }, { "interrupt", queue_interrupt }, { "terminate", queue_terminate }, { "close", queue_close }, { NULL, NULL } }; static luaL_Reg queue_metamethods[] = { { "__tostring", queue_tostring }, { "__eq", objects_equal }, { "__gc", queue_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_queue_type = { "lua_apr_queue*", /* metatable name in registry */ "thread queue", /* friendly object name */ sizeof(lua_apr_queue), /* structure size */ queue_methods, /* methods table */ queue_metamethods /* metamethods table */ }; #endif lua-apr-0.23.2.dfsg/src/time.c000066400000000000000000000230411220664456000157570ustar00rootroot00000000000000/* Time routines module for the Lua/APR binding. * * Author: Peter Odding * Last Change: December 30, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * Lua represents dates as numbers though the meaning of these numbers is not * specified. The manual does state (in the documentation for `os.time()`) that * on [POSIX] [posix], Windows and some other systems these numbers count the * number of seconds since some given start time called the epoch. This epoch * is 00:00:00 January 1, 1970 [UTC] [utc]. The Apache Portable Runtime * [represents] [apr_time_t] dates as the number of microseconds since that * same epoch. As a compromise between the two units Lua/APR uses seconds but * supports sub-second resolution in the decimal part of floating point numbers * (see [this thread] [2007-03] on [lua-l] [lua-l] for discussion about the * API). * * [posix]: http://en.wikipedia.org/wiki/POSIX * [apr_time_t]: http://apr.apache.org/docs/apr/trunk/group__apr__time.html#gdb4bde16055748190eae190c55aa02bb * [2007-03]: http://lua-users.org/lists/lua-l/2007-03/threads.html#00309 * [lua-l]: http://lua-users.org/lists/lua-l/ */ #include "lua_apr.h" #include #include /* Internal functions {{{1 */ static const struct { const char *name; int byte_offset; int value_offset; } fields[] = { { "usec", offsetof(apr_time_exp_t, tm_usec), 0 }, { "sec", offsetof(apr_time_exp_t, tm_sec), 0 }, { "min", offsetof(apr_time_exp_t, tm_min), 0 }, { "hour", offsetof(apr_time_exp_t, tm_hour), 0 }, { "day", offsetof(apr_time_exp_t, tm_mday), 0 }, { "month", offsetof(apr_time_exp_t, tm_mon), 1 }, { "year", offsetof(apr_time_exp_t, tm_year ), 1900 }, { "wday", offsetof(apr_time_exp_t, tm_wday ), 1 }, { "yday", offsetof(apr_time_exp_t, tm_yday ), 1 }, { "gmtoff", offsetof(apr_time_exp_t, tm_gmtoff), 0 }, }; void time_check_exploded(lua_State *L, int idx, apr_time_exp_t *components, int default_to_now) { int i; char *field; apr_status_t status; if (default_to_now && lua_isnoneornil(L, idx)) { status = apr_time_exp_lt(components, apr_time_now()); if (status != APR_SUCCESS) raise_error_status(L, status); } else if (lua_isnumber(L, idx)) { status = apr_time_exp_lt(components, time_get(L, idx)); if (status != APR_SUCCESS) raise_error_status(L, status); } else { luaL_checktype(L, idx, LUA_TTABLE); for (i = 0; i < count(fields); i++) { lua_getfield(L, idx, fields[i].name); field = (char*)components + fields[i].byte_offset; *(apr_int32_t*)field = lua_tointeger(L, -1) - fields[i].value_offset; lua_pop(L, 1); } lua_getfield(L, idx, "isdst"); components->tm_isdst = lua_toboolean(L, -1); lua_pop(L, 1); } } apr_time_t time_check(lua_State *L, int idx) { if (lua_isnoneornil(L, idx)) { return apr_time_now(); } else if (!lua_istable(L, idx)) { luaL_checktype(L, idx, LUA_TNUMBER); return time_get(L, idx); } else { apr_time_t time; apr_status_t status; apr_time_exp_t components; time_check_exploded(L, idx, &components, 1); status = apr_time_exp_get(&time, &components); if (status != APR_SUCCESS) raise_error_status(L, status); return time; } } int time_push(lua_State *L, apr_time_t time) { time_put(L, time); return 1; } /* apr.sleep(seconds) -> nothing {{{1 * * Sleep for the specified number of @seconds. Sub-second resolution is * supported so you can for example give 0.5 to sleep for half a second. This * function may sleep for longer than the specified time because of platform * limitations. */ int lua_apr_sleep(lua_State *L) { luaL_checktype(L, 1, LUA_TNUMBER); apr_sleep((apr_interval_time_t) time_get(L, 1)); return 0; } /* apr.time_now() -> time {{{1 * * Get the current time as the number of seconds since 00:00:00 January 1, 1970 * [UTC] [utc]. If Lua is compiled with floating point support then more * precision will be available in the decimal part of the returned number. */ int lua_apr_time_now(lua_State *L) { return time_push(L, apr_time_now()); } /* apr.time_explode([time [, timezone]]) -> components {{{1 * * Convert the numeric value @time (current time if none given) to its human * readable components. If @timezone isn't given or evaluates to false the * local timezone is used. If its a number then this number is used as the * offset in seconds from [GMT] [gmt]. The value true is treated the same as 0, * i.e. GMT. On success the table of components is returned, otherwise a nil * followed by an error message is returned. The resulting table contains the * following fields: * * - `usec` is the number of microseconds past `sec` * - `sec` is the number of seconds past `min` (0-61) * - `min` is the number of minutes past `hour` (0-59) * - `hour` is the number of hours past midnight (0-23) * - `day` is the day of the month (1-31) * - `month` is the month of the year (0-11). * - `year` is the year since 1900 * - `wday` is the number of days since Sunday (0-6) * - `yday` is the number of days since January 1 (0-365) * - `gmtoff` is the number of seconds east of [UTC] [utc] * - `isdst` is true when [daylight saving time] [dst] is in effect * * All of these fields are numbers except for `isdst` which is a boolean. * Here's an example of the output returned by `apr.time_explode()`: * * > -- Note that numeric dates are always in UTC while tables with * > -- date components are in the local timezone by default. * > components = apr.time_explode(1032030336.18671) * > = components * { * usec = 186710, * sec = 36, * min = 5, * hour = 21, * day = 14, * month = 9, * year = 2002, * wday = 7, * yday = 257, * gmtoff = 7200, -- my local timezone * isdst = true, * } * > -- To convert a table of date components back into a number * > -- you can use the apr.time_implode() function as follows: * > = apr.time_implode(components) * 1032030336.18671 * * [gmt]: http://en.wikipedia.org/wiki/Greenwich_Mean_Time * [utc]: http://en.wikipedia.org/wiki/Coordinated_Universal_Time * [dst]: http://en.wikipedia.org/wiki/Daylight_saving_time */ int lua_apr_time_explode(lua_State *L) { apr_time_exp_t components; apr_status_t status; apr_time_t time; char *field; int i; time = time_check(L, 1); if (!lua_toboolean(L, 2)) /* Explode the time according to the local timezone by default. */ status = apr_time_exp_lt(&components, time); else /* Or explode the time according to (an offset from) GMT instead. */ status = apr_time_exp_tz(&components, time, lua_isboolean(L, 2) ? 0 : (apr_int32_t) luaL_checkinteger(L, 2)); if (status != APR_SUCCESS) return push_error_status(L, status); /* Copy numeric fields of exploded time to Lua table. */ lua_createtable(L, 0, count(fields) + 1); for (i = 0; i < count(fields); i++) { field = (char*)&components + fields[i].byte_offset; lua_pushinteger(L, *(apr_int32_t*)field + fields[i].value_offset); lua_setfield(L, -2, fields[i].name); } /* Copy boolean `isdst' field. */ lua_pushboolean(L, components.tm_isdst); lua_setfield(L, -2, "isdst"); return 1; } /* apr.time_implode(components) -> time {{{1 * * Convert a table of time @components to its numeric value. On success the * time is returned, otherwise a nil followed by an error message is returned. * See `apr.time_explode()` for a list of supported components. */ int lua_apr_time_implode(lua_State *L) { apr_status_t status; apr_time_exp_t components = { 0 }; apr_time_t time; time_check_exploded(L, 1, &components, 0); status = apr_time_exp_gmt_get(&time, &components); if (status != APR_SUCCESS) return push_error_status(L, status); return time_push(L, time); } /* apr.time_format(format [, time]) -> formatted {{{1 * * Format @time (current time if none given) according to string @format. On * success the formatted time is returned, otherwise a nil followed by an error * message is returned. The two special formats `'ctime'` and `'rfc822'` result * in a fixed length string of 24 or 29 characters in length. The @time * argument may be either a number or a table with components like those * returned by `apr.time_explode()`. * * > = apr.time_format('%Y-%m-%d %H:%I:%S', apr.time_now()) * '2010-09-25 17:05:08' * > = apr.time_format('ctime', apr.time_now()) * 'Sat Sep 25 17:26:22 2010' * > = apr.time_format('rfc822', apr.time_now()) * 'Sat, 25 Sep 2010 15:26:36 GMT' */ int lua_apr_time_format(lua_State *L) { char formatted[1024]; apr_status_t status; const char *format; luaL_checktype(L, 1, LUA_TSTRING); format = lua_tostring(L, 1); if (strcmp(format, "ctime") == 0) { status = apr_ctime(formatted, time_check(L, 2)); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, formatted, APR_CTIME_LEN - 1); return 1; } else if (strcmp(format, "rfc822") == 0) { status = apr_rfc822_date(formatted, time_check(L, 2)); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, formatted, APR_RFC822_DATE_LEN - 1); return 1; } else { apr_time_exp_t components = { 0 }; apr_size_t length = count(formatted); time_check_exploded(L, 2, &components, 1); status = apr_strftime(formatted, &length, length, format, &components); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, formatted, length); return 1; } } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/uri.c000066400000000000000000000111551220664456000156230ustar00rootroot00000000000000/* Uniform resource identifier parsing module for the Lua/APR binding. * * Author: Peter Odding * Last Change: September 25, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include #include const static struct { const char *name; const int offset; } fields[] = { { "scheme", offsetof(apr_uri_t, scheme ) }, { "hostinfo", offsetof(apr_uri_t, hostinfo) }, { "user", offsetof(apr_uri_t, user ) }, { "password", offsetof(apr_uri_t, password) }, { "hostname", offsetof(apr_uri_t, hostname) }, { "port", offsetof(apr_uri_t, port_str) }, { "path", offsetof(apr_uri_t, path ) }, { "query", offsetof(apr_uri_t, query ) }, { "fragment", offsetof(apr_uri_t, fragment) } }; /* apr.uri_parse(uri) -> components {{{1 * * Parse the [Uniform Resource Identifier] [uri] @uri. On success a table of * components is returned, otherwise a nil followed by an error message is * returned. The table of components can have the following fields, all * strings: * * - `scheme` is the part of the URI before `://` (as in `http`, `ftp`, etc.) * - `user` is the user name, as in `scheme://user:pass@host:port/` * - `password` is the password, as in `scheme://user:pass@host:port/` * - `hostinfo` is the combined `[user[:password]@]hostname[:port]` * - `hostname` is the host name or IP address * - `port` is the port number * - `path` is the request path (`/` if only `scheme://hostname` was given) * - `query` is everything after a `?` in the path, if present * - `fragment` is the trailing `#fragment` string, if present * * [uri]: http://en.wikipedia.org/wiki/Uniform_Resource_Identifier */ int lua_apr_uri_parse(lua_State *L) { apr_status_t status; apr_pool_t *memory_pool; apr_uri_t components = { NULL }; const char *string; int i; memory_pool = to_pool(L); string = luaL_checkstring(L, 1); status = apr_uri_parse(memory_pool, string, &components); if (status != APR_SUCCESS) return push_error_status(L, status); lua_newtable(L); for (i = 0; i < count(fields); i++) { char *field = *(char **) ((char *) &components + fields[i].offset); if (field && *field) { lua_pushstring(L, fields[i].name); lua_pushstring(L, field); lua_rawset(L, -3); } } return 1; } /* apr.uri_unparse(components [, option]) -> uri {{{1 * * Convert a table of [URI] [uri] @components into a URI string. On success the * URI string is returned, otherwise a nil followed by an error message is * returned. The list of fields in the @components table is available in the * documentation for `apr.uri_parse()`. The argument @option may be one of the * following: * * - `hostinfo` to unparse the components `[user[:password]@]hostname[:port]` * - `pathinfo` to unparse the components `path[?query[#fragment]]` */ int lua_apr_uri_unparse(lua_State *L) { const char *options[] = { "hostinfo", "pathinfo", "default" }; const int values[] = { APR_URI_UNP_OMITPATHINFO | APR_URI_UNP_REVEALPASSWORD, APR_URI_UNP_OMITSITEPART, APR_URI_UNP_REVEALPASSWORD }; apr_uri_t components = { 0 }; apr_pool_t *memory_pool; int i, flags = 0; memory_pool = to_pool(L); luaL_checktype(L, 1, LUA_TTABLE); flags = values[luaL_checkoption(L, 2, "default", options)]; for (i = 0; i < count(fields); i++) { lua_getfield(L, 1, fields[i].name); if (lua_isstring(L, -1)) { char **field = (char **)((char *) &components + fields[i].offset); *field = apr_pstrdup(memory_pool, lua_tostring(L, -1)); } lua_pop(L, 1); } /* .port_str and .port must both be set, otherwise :port * will not be included in the unparsed components! (I think) */ if (components.port_str) components.port = (apr_port_t) atoi(components.port_str); lua_pushstring(L, apr_uri_unparse(memory_pool, &components, flags)); return 1; } /* apr.uri_port_of_scheme(scheme) -> port {{{1 * * Return the default port for the given [URI] [uri] @scheme string. [Since at * least APR 1.2.8] [uri_ports] the following schemes are supported: `acap`, * `ftp`, `gopher`, `http`, `https`, `imap`, `ldap`, `nfs`, `nntp`, `pop`, * `prospero`, `rtsp`, `sip`, `snews`, `ssh`, `telnet`, `tip`, `wais`, * `z39.50r` and `z39.50s`. * * [uri_ports]: http://svn.apache.org/viewvc/apr/apr/trunk/uri/apr_uri.c?view=markup#l43 */ int lua_apr_uri_port_of_scheme(lua_State *L) { const char *scheme; int port; scheme = luaL_checkstring(L, 1); port = apr_uri_port_of_scheme(scheme); if (0 == port) return 0; lua_pushnumber(L, port); return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/user.c000066400000000000000000000046451220664456000160100ustar00rootroot00000000000000/* User/group identification module for the Lua/APR binding. * * Author: Peter Odding * Last Change: September 25, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include /* apr.user_get() -> username, groupname {{{1 * * Get the username and groupname of the calling process. On success the * username and groupname are returned, otherwise a nil followed by an error * message is returned. */ int lua_apr_user_get(lua_State *L) { apr_status_t status; apr_pool_t *pool; apr_uid_t uid; apr_gid_t gid; char *username, *groupname; # if APR_HAS_USER pool = to_pool(L); status = apr_uid_current(&uid, &gid, pool); if (APR_SUCCESS == status) status = apr_uid_name_get(&username, uid, pool); if (APR_SUCCESS == status) status = apr_gid_name_get(&groupname, gid, pool); if (APR_SUCCESS != status) return push_error_status(L, status); lua_pushstring(L, username); lua_pushstring(L, groupname); return 2; # else raise_error_status(L, APR_ENOTIMPL); return 0; # endif } /* apr.user_homepath_get(username) -> homepath {{{1 * * Get the [home directory] [home] for the named user. On success the directory * pathname is returned, otherwise a nil followed by an error message is * returned. * * [home]: http://en.wikipedia.org/wiki/Home_directory */ int lua_apr_user_homepath_get(lua_State *L) { apr_status_t status; apr_pool_t *pool; const char *name; char *path; # if APR_HAS_USER pool = to_pool(L); name = luaL_checkstring(L, 1); status = apr_uid_homepath_get(&path, name, pool); if (APR_SUCCESS != status) return push_error_status(L, status); lua_pushstring(L, path); return 1; # else raise_error_status(L, APR_ENOTIMPL); return 0; # endif } /* Push name for userid */ int push_username(lua_State *L, apr_pool_t *pool, apr_uid_t uid) { char *username; # if APR_HAS_USER if (APR_SUCCESS == apr_uid_name_get(&username, uid, pool)) lua_pushstring(L, username); else lua_pushnil(L); # else lua_pushnil(L); # endif return 1; } /* Push name for groupid */ int push_groupname(lua_State *L, apr_pool_t *pool, apr_gid_t gid) { char *groupname; # if APR_HAS_USER if (APR_SUCCESS == apr_gid_name_get(&groupname, gid, pool)) lua_pushstring(L, groupname); else lua_pushnil(L); # else lua_pushnil(L); # endif return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/uuid.c000066400000000000000000000054751220664456000160020ustar00rootroot00000000000000/* Universally unique identifiers module for the Lua/APR binding. * * Author: Peter Odding * Last Change: October 22, 2010 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * [Universally unique identifiers] [uuid] are a standard for generating unique * strings that are specific to the machine on which they are generated and/or * the time at which they are generated. They can be used as primary keys in * databases and are used to uniquely identify file system types and instances * on modern operating systems. This is what a standard format UUID looks like: * * > = apr.uuid_format(apr.uuid_get()) * '0ad5d4a4-591e-41f7-8be4-07d7961a8079' * * [uuid]: http://en.wikipedia.org/wiki/Universally_unique_identifier */ #include "lua_apr.h" #include #define APR_UUID_LENGTH sizeof(apr_uuid_t) /* apr.uuid_get() -> binary {{{1 * * Generate and return a UUID as a binary string of 16 bytes. */ int lua_apr_uuid_get(lua_State *L) { apr_uuid_t uuid; apr_uuid_get(&uuid); lua_pushlstring(L, (const char *) uuid.data, sizeof uuid); return 1; } /* apr.uuid_format(binary) -> formatted {{{1 * * Format a UUID of 16 bytes following the standard format of 32 hexadecimal * digits, displayed in 5 groups separated by hyphens, in the form `8-4-4-4-12` * for a total of 36 characters, like `f5dc3464-6c8f-654e-a407-b15b7a30f038`. * On success the formatted UUID is returned, otherwise a nil followed by an * error message is returned. */ int lua_apr_uuid_format(lua_State *L) { size_t length; const char *uuid; char formatted[APR_UUID_FORMATTED_LENGTH + 1]; uuid = luaL_checklstring(L, 1, &length); if (APR_UUID_LENGTH != length) { const char *msg = "expected string of %d characters"; luaL_argerror(L, 1, lua_pushfstring(L, msg, APR_UUID_LENGTH)); } /* pointer to structure == pointer to first element */ apr_uuid_format(formatted, (const apr_uuid_t *) uuid); lua_pushlstring(L, formatted, APR_UUID_FORMATTED_LENGTH); return 1; } /* apr.uuid_parse(formatted) -> binary {{{1 * * Parse a standard format UUID and return its 16-byte equivalent. On success * the parsed UUID is returned, otherwise a nil followed by an error message is * returned. */ int lua_apr_uuid_parse(lua_State *L) { apr_status_t status; size_t length; const char *formatted; apr_uuid_t uuid; formatted = luaL_checklstring(L, 1, &length); if (APR_UUID_FORMATTED_LENGTH != length) { const char *msg = "expected string of %d characters"; luaL_argerror(L, 1, lua_pushfstring(L, msg, APR_UUID_FORMATTED_LENGTH)); } status = apr_uuid_parse(&uuid, formatted); if (status != APR_SUCCESS) return push_error_status(L, status); lua_pushlstring(L, (const char *) uuid.data, APR_UUID_LENGTH); return 1; } /* vim: set ts=2 sw=2 et tw=79 fen fdm=marker : */ lua-apr-0.23.2.dfsg/src/xlate.c000066400000000000000000000074451220664456000161500ustar00rootroot00000000000000/* Character encoding translation module for the Lua/APR binding. * * Author: Peter Odding * Last Change: February 13, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT */ #include "lua_apr.h" #include /* Internal functions {{{1 */ static const char *check_codepage(lua_State *L, int idx) { const char *codepage = luaL_checkstring(L, idx); return strcmp(codepage, "locale") == 0 ? APR_LOCALE_CHARSET : codepage; } /* apr.xlate(input, from, to) -> translated {{{1 * * Translate a string of text from one [character encoding] [charenc] to * another. The @from and @to arguments are strings identifying the source and * target character encoding. The special value `'locale'` indicates the * character set of the [current locale] [locale]. On success the translated * string is returned, otherwise a nil followed by an error message is * returned. * * Which character encodings are supported by `apr.xlate()` is system dependent * because APR can use both the system's [iconv] [iconv] implementation and the * bundled library [apr-iconv] [apr_iconv]. To get a list of valid character * encoding names you can look through the [apr-iconv/ccs] [iconv_ccs] and * [apr-iconv/ces] [iconv_ces] directories (those are links to the web * interface of the apr-iconv repository). * * [charenc]: http://en.wikipedia.org/wiki/Character_encoding * [locale]: http://en.wikipedia.org/wiki/Locale * [iconv]: http://en.wikipedia.org/wiki/Iconv * [apr_iconv]: http://apr.apache.org/docs/apr-iconv/trunk/group__apr__iconv.html * [iconv_ccs]: http://svn.apache.org/viewvc/apr/apr-iconv/trunk/ccs/ * [iconv_ces]: http://svn.apache.org/viewvc/apr/apr-iconv/trunk/ces/ */ int lua_apr_xlate(lua_State *L) { apr_pool_t *pool; const char *input, *frompage, *topage; size_t length, bufsize, extra; apr_xlate_t *convset; apr_status_t status; apr_size_t todo, unused; char *output, *temp; pool = to_pool(L); input = luaL_checklstring(L, 1, &length); frompage = check_codepage(L, 2); topage = check_codepage(L, 3); /* Apparently apr-iconv doesn't like empty input strings. */ if (length == 0) { lua_pushliteral(L, ""); return 1; } /* Initialize the output buffer and related variables. */ output = malloc(bufsize = length); if (output == NULL) { status = APR_ENOMEM; goto fail; } todo = unused = length; /* Initialize the translation context. */ status = apr_xlate_open(&convset, topage, frompage, pool); if (status != APR_SUCCESS) goto fail; /* Perform the conversion in one or more passes. */ for (;;) { status = apr_xlate_conv_buffer(convset, &input[length - todo], &todo, &output[bufsize - unused], &unused); if (status != APR_SUCCESS) goto fail; else if (todo == 0) break; /* Grow the output buffer by one third. */ extra = bufsize < 10 ? 10 : bufsize / 3; temp = realloc(output, bufsize + extra); if (temp == NULL) { status = APR_ENOMEM; goto fail; } output = temp; bufsize += extra; unused += extra; } /* Correctly terminate the output buffer for some multibyte character set encodings. */ status = apr_xlate_conv_buffer(convset, NULL, NULL, &output[bufsize - unused], &unused); if (status != APR_SUCCESS) goto fail; /* Close the translation context. */ status = apr_xlate_close(convset); if (status != APR_SUCCESS) goto fail; lua_pushlstring(L, output, bufsize - unused); free(output); /* I'm not sure whether any resources remain in memory after the call to * apr_xlate_close(). Just to make sure, we clear the global memory pool * now instead of waiting until the next time it's used. */ apr_pool_clear(pool); return 1; fail: free(output); apr_pool_clear(pool); return push_status(L, status); } lua-apr-0.23.2.dfsg/src/xml.c000066400000000000000000000231771220664456000156330ustar00rootroot00000000000000/* XML parsing module for the Lua/APR binding. * * Authors: * - zhiguo zhao * - Peter Odding * Last Change: June 16, 2011 * Homepage: http://peterodding.com/code/lua/apr/ * License: MIT * * This module enables parsing of [XML] [xml] documents. Unlike [LuaExpat] * [lxp] the parsers returned by `apr.xml()` don't use callbacks, instead they * parse XML into a [document object model] [dom] which is then exposed to Lua. * Because of this you can't use `apr.xml()` for incremental parsing. To parse * an XML document you follow these steps: * * 1. Create an XML parser object by calling `apr.xml()` * 2. Parse the document by calling `xml_parser:feed()` repeatedly until the * full document has been parsed * 3. Signal to the parser that the full document has been parsed by calling * `xml_parser:done()` * 4. Get the parse information by calling `xml_parser:getinfo()` * * Right now the only way to get the parse information is by calling * `xml_parser:getinfo()` which converts the information to a Lua table * following the [Lua object model] [lom] defined by [LuaExpat] [lxp]. The Lua * object model is a mapping of XML to Lua tables that's not 100% complete * (e.g. it doesn't include namespaces) but makes it a lot easier to deal with * XML in Lua. * * In the future this module might expose the full XML parse tree to Lua as * userdata objects, so that Lua has access to all parse information. This * would also make it possible to expose the [apr\_xml\_to\_text()] * [xml_to_text] function. * * [xml]: http://en.wikipedia.org/wiki/XML * [lxp]: http://www.keplerproject.org/luaexpat/ * [lom]: http://www.keplerproject.org/luaexpat/lom.html * [dom]: http://en.wikipedia.org/wiki/XML#Document_Object_Model_.28DOM.29 * [xml_to_text]: http://apr.apache.org/docs/apr/trunk/group___a_p_r___util___x_m_l.html#g4485edce130dc1e9a3da3a633a75ffb3 */ #include "lua_apr.h" #include #include typedef struct { lua_apr_refobj header; apr_pool_t *pool; apr_xml_parser *parser; apr_xml_doc *doc; } lua_apr_xml_object; typedef enum { CHECK_NONE, CHECK_PARSER, CHECK_DOCUMENT, } object_state; /* Internal functions. {{{1 */ static lua_apr_xml_object *check_xml_parser(lua_State *L, int idx, object_state state) { lua_apr_xml_object *object; object = check_object(L, idx, &lua_apr_xml_type); if (state == CHECK_PARSER && object->parser == NULL) luaL_error(L, "attempt to use a closed XML parser"); if (state == CHECK_DOCUMENT && object->doc == NULL) luaL_error(L, "no parse information available"); return object; } static int push_xml_status(lua_State *L, lua_apr_xml_object *object, apr_status_t status) { if (status == APR_SUCCESS) { lua_pushboolean(L, 1); return 1; } else { char message[LUA_APR_MSGSIZE]; apr_xml_parser_geterror(object->parser, message, sizeof(message)); lua_pushnil(L); lua_pushstring(L, message); return 2; } } static void reverse_table(lua_State *L, int idx, int len) { int i, j; for (i = 1, j = len; i < j; i++, j--) { lua_rawgeti(L, idx, i); lua_rawgeti(L, idx, j); lua_rawseti(L, idx, i); lua_rawseti(L, idx, j); } } static void dump_xml(lua_State *L, apr_xml_elem *elem) { apr_xml_attr *attr; apr_xml_elem *child; apr_text *text; int i; luaL_checktype(L, -1, LUA_TTABLE); if (elem->name != NULL) { lua_pushstring(L, "tag"); lua_pushstring(L, elem->name); lua_rawset(L, -3); } if (elem->attr != NULL) { lua_newtable(L); i = 1; attr = elem->attr; while (attr != NULL) { lua_pushstring(L, attr->name); lua_rawseti(L, -2, i); lua_pushstring(L, attr->name); lua_pushstring(L, attr->value); lua_rawset(L, -3); attr = attr->next; i++; } /* XXX Reverse the order of the attributes in the array part of the table. * The apr_xml.h header doesn't document that attributes are reversed, in * fact the apr_xml_elem.attr field is documented as the "first attribute", * but in the definition of start_handler() in the apr_xml.c implementation * it _is_ mentioned that attributes end up in reverse order. */ reverse_table(L, lua_gettop(L), i - 1); lua_setfield(L, -2, "attr"); } i = 1; if (elem->first_child != NULL) { child = elem->first_child; while (child != NULL) { lua_newtable(L); dump_xml(L, child); lua_rawseti(L, -2, i); child = child->next; i++; } } else { text = elem->first_cdata.first; while (text != NULL) { lua_pushstring(L, text->text); lua_rawseti(L, -2, i); text = text->next; i++; } } } static void xml_close_real(lua_apr_xml_object *object) { if (object->parser != NULL) { object->parser = NULL; apr_pool_destroy(object->pool); object->pool = NULL; } } /* apr.xml([filename]) -> xml_parser {{{1 * * Create an XML parser. If the optional string @filename is given, the file * pointed to by @filename will be parsed. On success the parser object is * returned, otherwise a nil followed by an error message is returned. */ int lua_apr_xml(lua_State *L) { lua_apr_xml_object *object; apr_status_t status; const char *filename; filename = luaL_optstring(L, 1, NULL); object = new_object(L, &lua_apr_xml_type); if (object == NULL) return push_error_memory(L); status = apr_pool_create(&object->pool, NULL); if (status != APR_SUCCESS) return push_error_status(L, status); if (filename == NULL) { object->parser = apr_xml_parser_create(object->pool); if (object->parser == NULL) return push_error_memory(L); } else { apr_finfo_t info; apr_file_t *xmlfd; status = apr_file_open(&xmlfd, filename, APR_FOPEN_READ, 0, object->pool); if (status != APR_SUCCESS) return push_status(L, status); status = apr_file_info_get(&info, APR_FINFO_SIZE, xmlfd); if (status != APR_SUCCESS) { apr_file_close(xmlfd); return push_status(L, status); } status = apr_xml_parse_file(object->pool, &object->parser, &object->doc, xmlfd, (apr_size_t)info.size); apr_file_close(xmlfd); if (status != APR_SUCCESS) return push_xml_status(L, object, status); } return 1; } /* xml_parser:feed(input) -> status {{{1 * * Feed the string @input into the XML parser. On success true is returned, * otherwise a nil followed by an error message is returned. */ static int xml_feed(lua_State *L) { lua_apr_xml_object *object; apr_status_t status; apr_size_t size; const char *data; object = check_xml_parser(L, 1, CHECK_PARSER); data = luaL_checklstring(L, 2, &size); status = apr_xml_parser_feed(object->parser, data, size); return push_xml_status(L, object, status); } /* xml_parser:done() -> status {{{1 * * Terminate the parsing and save the resulting parse information. On success * true is returned, otherwise a nil followed by an error message is returned. */ static int xml_done(lua_State *L) { lua_apr_xml_object *object; apr_status_t status; object = check_xml_parser(L, 1, CHECK_PARSER); status = apr_xml_parser_done(object->parser, &object->doc); return push_xml_status(L, object, status); } /* xml_parser:geterror() -> message {{{1 * * Fetch additional error information from the parser after one of its methods * has failed. */ static int xml_geterror(lua_State *L) { lua_apr_xml_object *object; char message[LUA_APR_MSGSIZE]; object = check_xml_parser(L, 1, CHECK_PARSER); apr_xml_parser_geterror(object->parser, message, sizeof(message)); lua_pushstring(L, message); return 1; } /* xml_parser:getinfo() -> table {{{1 * * Convert the parse information to a Lua table following the * [Lua Object Model] [lom] defined by [LuaExpat] [lxp]. */ static int xml_getinfo(lua_State *L) { lua_apr_xml_object *object; object = check_xml_parser(L, 1, CHECK_DOCUMENT); lua_newtable(L); dump_xml(L, object->doc->root); return 1; } /* xml_parser:close() -> status {{{1 * * Close the XML parser and destroy any parse information. This will be done * automatically when the @xml_parser object is garbage collected which means * you don't need to call this unless you want to reclaim memory as soon as * possible (e.g. because you just parsed a large XML document). */ static int xml_close(lua_State *L) { lua_apr_xml_object *object; object = check_xml_parser(L, 1, CHECK_NONE); xml_close_real(object); lua_pushboolean(L, 1); return 1; } /* tostring(xml_parser) -> string {{{1 */ static int xml_tostring(lua_State *L) { lua_apr_xml_object *object; object = check_xml_parser(L, 1, CHECK_NONE); if (object->parser != NULL) lua_pushfstring(L, "%s (%p)", lua_apr_xml_type.friendlyname, object); else lua_pushfstring(L, "%s (closed)", lua_apr_xml_type.friendlyname); return 1; } /* xml_parser:__gc() {{{1 */ static int xml_gc(lua_State *L) { lua_apr_xml_object *object = check_xml_parser(L, 1, CHECK_NONE); if (object_collectable((lua_apr_refobj*)object)) xml_close_real(object); release_object((lua_apr_refobj*)object); return 0; } /* }}}1 */ static luaL_reg xml_methods[] = { { "feed", xml_feed }, { "done", xml_done }, { "getinfo", xml_getinfo }, { "geterror", xml_geterror }, { "close", xml_close }, { NULL, NULL } }; static luaL_reg xml_metamethods[] = { { "__tostring", xml_tostring }, { "__eq", objects_equal }, { "__gc", xml_gc }, { NULL, NULL } }; lua_apr_objtype lua_apr_xml_type = { "lua_apr_xml_object*", /* metatable name in registry */ "xml parser", /* friendly object name */ sizeof(lua_apr_xml_object), /* structure size */ xml_methods, /* methods table */ xml_metamethods /* metamethods table */ }; lua-apr-0.23.2.dfsg/test/000077500000000000000000000000001220664456000150455ustar00rootroot00000000000000lua-apr-0.23.2.dfsg/test/base64.lua000066400000000000000000000023731220664456000166410ustar00rootroot00000000000000--[[ Unit tests for the Base64 encoding module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Sample data from http://en.wikipedia.org/wiki/Base64#Examples local plain = 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.' local coded = 'TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=' -- Check that Base64 encoding returns the expected result. assert(apr.base64_encode(plain) == coded) -- Check that Base64 decoding returns the expected result. assert(apr.base64_decode(coded) == plain) lua-apr-0.23.2.dfsg/test/crypt.lua000066400000000000000000000037051220664456000167160ustar00rootroot00000000000000--[[ Unit tests for the cryptography module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Sample data from http://en.wikipedia.org/wiki/MD5#MD5_hashes -- and http://en.wikipedia.org/wiki/SHA1#Example_hashes -- Check that MD5 hashing returns the expected result. assert(apr.md5 '' == 'd41d8cd98f00b204e9800998ecf8427e') assert(apr.md5 'The quick brown fox jumps over the lazy dog' == '9e107d9d372bb6826bd81d3542a419d6') assert(apr.md5 'The quick brown fox jumps over the lazy eog' == 'ffd93f16876049265fbaef4da268dd0e') local pass, salt = 'password', 'salt' hash = apr.md5_encode(pass, salt) -- Test that MD5 passwords can be validated. assert(apr.password_validate(pass, hash)) -- Test that SHA1 hashing returns the expected result. assert(apr.sha1 'The quick brown fox jumps over the lazy dog' == '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') assert(apr.sha1 'The quick brown fox jumps over the lazy cog' == 'de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3') -- Test the incremental MD5 message digest interface. local context = assert(apr.md5_init()) assert(context:update 'The quick brown fox jumps over the lazy dog') assert(context:digest() == '9e107d9d372bb6826bd81d3542a419d6') assert(context:reset()) assert(context:update 'The quick brown fox jumps over the lazy eog') assert(context:digest() == 'ffd93f16876049265fbaef4da268dd0e') -- Test the incremental SHA1 message digest interface. local context = assert(apr.sha1_init()) assert(context:update 'The quick brown fox jumps over the lazy dog') assert(context:digest() == '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') assert(context:reset()) assert(context:update 'The quick brown fox jumps over the lazy cog') assert(context:digest() == 'de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3') lua-apr-0.23.2.dfsg/test/date.lua000066400000000000000000000030131220664456000164620ustar00rootroot00000000000000--[[ Unit tests for the date parsing module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- The following tests were copied from http://svn.apache.org/viewvc/apr/apr/trunk/test/testdate.c?view=markup for i, rfc_pair in ipairs { { "Mon, 27 Feb 1995 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, { "Fri, 1 Jul 2005 11:34:25 -0400", "Fri, 01 Jul 2005 15:34:25 GMT" }, { "Monday, 27-Feb-95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, { "Tue, 4 Mar 1997 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, { "Mon, 27 Feb 95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" }, { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" }, { "Mon, 27 Feb 95 20:49 GMT", "Mon, 27 Feb 1995 20:49:00 GMT" }, { "Tue, 4 Mar 97 12:43 GMT", "Tue, 04 Mar 1997 12:43:00 GMT" } } do local time = assert(apr.date_parse_rfc(rfc_pair[1])) assert(apr.time_format('rfc822', time) == rfc_pair[2]) end -- The tests for apr_date_parse_http() are far too complex to reproduce in Lua -- so instead here's a round trip of one of the examples in the documentation: local date = 'Sun, 06 Nov 1994 08:49:37 GMT' assert(apr.time_format('rfc822', apr.date_parse_http(date)) == date) lua-apr-0.23.2.dfsg/test/dbd-child.lua000066400000000000000000000172741220664456000173750ustar00rootroot00000000000000-- Based on http://svn.apache.org/viewvc/apr/apr/trunk/test/testdbd.c?view=markup local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- APR 1.2 compatibility? local APR_12_COMPAT = apr.strnatcmp(apr.version_get().apr, '1.3') local helpers = require 'apr.test.helpers' local driver = assert(apr.dbd 'sqlite3') assert(driver:open ':memory:') assert(driver:driver() == 'sqlite3') -- Check that the "connection" is alive. assert(driver:check()) -- The SQLite driver uses a single database. assert(not driver:dbname 'anything') -- Print the SQLite version (may be helpful in debugging). local resultset = driver:select 'SELECT sqlite_version()' helpers.message('\rRunning dbd tests using SQLite %s driver: ', resultset:tuple() or '?') -- Helpers {{{1 function check_label(object, pattern) local label = assert(tostring(object)) assert(label:find(pattern)) end check_label(driver, '^database driver %([x%x]+%)$') local function delete_rows() local status, affected_rows = assert(driver:query 'DELETE FROM apr_dbd_test') assert(affected_rows == 26) end local function count_rows() local results = assert(driver:select 'SELECT COUNT (*) FROM apr_dbd_test') return results:tuple() + 0 end -- Create table. {{{1 assert(driver:query [[ CREATE TABLE apr_dbd_test ( col1 varchar(40) not null, col2 varchar(40), col3 integer) ]]) -- Insert rows using prepared statement. {{{1 local prepared_statement = assert(driver:prepare [[ INSERT INTO apr_dbd_test VALUES (%s, %s, %i) ]]) check_label(prepared_statement, '^prepared statement %([x%x]+%)$') for i = string.byte 'a', string.byte 'z' do local c = string.char(i) local status, nrows -- Test both statement:query() interfaces. if i % 2 == 0 then status, nrows = assert(prepared_statement:query { c, i, i }) else status, nrows = assert(prepared_statement:query(c, i, i)) end assert(status and nrows == 1) end -- Test transactions and rolling back. {{{1 assert(driver:transaction_start()) if not APR_12_COMPAT then assert(driver:transaction_mode 'rollback') end assert(count_rows() == 26) delete_rows() assert(count_rows() == 0) if APR_12_COMPAT then -- Trigger an error to rollback the transaction :-) (APR 1.2 doesn't have transaction_mode()). assert(not driver:query 'DROP TABLE presumably_non_existing_table') end assert(driver:transaction_end()) assert(count_rows() == 26) -- Make sure prepared_statement:query() rejects invalid values correctly. {{{1 local prepared_statement = assert(driver:prepare 'INSERT INTO apr_dbd_test VALUES (%s, %s, %i)') local status, message = pcall(function() prepared_statement:query('', 1, {}) end) assert(not status) assert(message:find 'bad argument #3') local status, message = pcall(function() prepared_statement:query { '', {}, 1 } end) assert(not status) assert(message:find 'bad argument #1') assert(message:find 'invalid value at index 2') -- Test resultset:tuples() iterator. {{{1 local results = assert(driver:select [[ SELECT col1, col2, col3 FROM apr_dbd_test ORDER BY col1 ]]) check_label(results, '^result set %([x%x]+%)$') local expected = string.byte 'a' for col1, col2, col3 in results:tuples() do assert(col1 == string.char(expected)) assert(tonumber(col2) == expected) assert(tonumber(col3) == expected) expected = expected + 1 end assert(expected == (string.byte 'z' + 1)) -- Test resultset:tuple() function. {{{1 -- Tuple containing one number. {{{2 local results = assert(driver:select 'SELECT 42') -- Check the number of results. assert(#results == 1) -- Check the resulting tuple. helpers.checktuple({ '42' }, results:tuple(1)) -- Check that just one tuple is returned. assert(not results:tuple()) -- Tuple containing two numbers. {{{2 local results = assert(driver:select 'SELECT 42, 24') assert(#results == 1) helpers.checktuple({ '42', '24' }, results:tuple(1)) assert(not results:tuple()) -- Tuple containing number and string. {{{2 local results = assert(driver:select [[ SELECT 42, 'hello world!' ]]) assert(#results == 1) helpers.checktuple({ '42', 'hello world!' }, results:tuple(1)) assert(not results:tuple()) -- The following is only available since APR 1.3. if not APR_12_COMPAT then -- Named tuple containing number and string. {{{2 local results = assert(driver:select [[ SELECT 42 AS "num", 'hello world!' AS "str" ]]) assert(#results == 1) helpers.checktuple({ 'num', 'str' }, results:columns()) assert(not results:columns(0)) assert(results:columns(1) == 'num') assert(results:columns(2) == 'str') assert(not results:columns(3)) helpers.checktuple({ '42', 'hello world!' }, results:tuple(1)) assert(not results:tuple()) -- Result set with multiple tuples. {{{2 local results = assert(driver:select [[ SELECT col1, col2, col3 FROM apr_dbd_test ORDER BY col1 ]]) local expected = string.byte 'a' helpers.checktuple({ 'col1', 'col2', 'col3' }, results:columns()) while true do local col1, col2, col3 = results:tuple() if not col1 then break end assert(col1 == string.char(expected)) assert(tonumber(col2) == expected) assert(tonumber(col3) == expected) expected = expected + 1 end assert(expected == (string.byte 'z' + 1)) -- Test resultset:rows() iterator. {{{1 local results = assert(driver:select [[ SELECT col1, col2, col3 FROM apr_dbd_test ORDER BY col1 ]]) local expected = string.byte 'a' for row in results:rows() do assert(helpers.deepequal({ col1 = string.char(expected), col2 = tostring(expected), col3 = tostring(expected) }, row)) expected = expected + 1 end assert(expected == (string.byte 'z' + 1)) -- Test resultset:row() function. {{{1 -- Basic usage. local results = assert(driver:select [[ SELECT 42 AS "num", 'hello world!' AS "str" ]]) assert(#results == 1) assert(helpers.deepequal({ num = '42', str = 'hello world!' }, results:row(1))) assert(not results:row()) -- NULL translates to nil. local results = assert(driver:select [[ SELECT 42 AS "num", 'hello world!' AS "str", NULL AS "whatever" ]]) assert(#results == 1) assert(helpers.deepequal({ num = '42', str = 'hello world!' }, results:row(1))) assert(not results:row()) -- True and false translate to 0 and 1. local results = assert(driver:select [[ SELECT (1 == 1) AS "t", (1 == 2) AS "f" ]]) assert(#results == 1) assert(helpers.deepequal({ t = '1', f = '0' }, results:row(1))) -- Test resultset:pairs() iterator. {{{1 local results = assert(driver:select [[ SELECT col1, col2, col3 FROM apr_dbd_test ORDER BY col1 ]]) local ii = 1 local expected = string.byte 'a' for i, row in results:pairs() do assert(helpers.deepequal({ col1 = string.char(expected), col2 = tostring(expected), col3 = tostring(expected) }, row)) assert(i == ii) expected = expected + 1 ii = ii + 1 end assert(expected == (string.byte 'z' + 1)) end -- Delete all rows in table. {{{1 delete_rows() -- Drop table. {{{1 assert(driver:query [[ DROP TABLE apr_dbd_test ]]) -- Make sure prepared statements & result sets are invalidated when driver is reinitialized. {{{1 local function check_reinitialized(cb) local status, message = pcall(cb) assert(not status) assert(message:find 'database driver has been reinitialized') end local results = driver:select 'SELECT 1, 2, 3' assert(apr.type(results) == 'result set') helpers.checktuple({ '1', '2', '3' }, results:tuple(1)) local statement = driver:prepare 'SELECT 1, 2, 3' assert(apr.type(statement) == 'prepared statement') local statement_results = assert(statement:select()) assert(apr.type(statement_results) == 'result set') driver:close() check_reinitialized(function() results:tuple() end) check_reinitialized(function() statement:select() end) lua-apr-0.23.2.dfsg/test/dbd.lua000066400000000000000000000007751220664456000163120ustar00rootroot00000000000000--[[ Unit tests for the relational database module of the Lua/APR binding. Author: Peter Odding Last Change: July 2, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script executes the real test in dbd-child.lua as a child process. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' return helpers.ld_preload_trick 'dbd-child.lua' lua-apr-0.23.2.dfsg/test/dbm.lua000066400000000000000000000024371220664456000163200ustar00rootroot00000000000000--[[ Unit tests for the DBM module of the Lua/APR binding. Author: Peter Odding Last Change: June 30, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local dbmfile = helpers.tmpname() local dbm = assert(apr.dbm_open(dbmfile, 'n')) local dbmkey, dbmvalue = 'the key', 'the value' assert(not dbm:firstkey()) -- nothing there yet assert(dbm:store(dbmkey, dbmvalue)) local function checkdbm() assert(dbm:exists(dbmkey)) assert(dbm:fetch(dbmkey) == dbmvalue) assert(dbm:firstkey() == dbmkey) assert(not dbm:nextkey(dbmkey)) -- only 1 record exists end checkdbm() assert(dbm:close()) local file1, file2 = assert(apr.dbm_getnames(dbmfile)) assert(apr.stat(file1, 'type') == 'file') assert(not file2 or apr.stat(file2, 'type') == 'file') dbm = assert(apr.dbm_open(dbmfile, 'w')) checkdbm() assert(dbm:delete(dbmkey)) assert(not dbm:fetch(dbmkey)) assert(not dbm:firstkey()) -- Test tostring(dbm). assert(tostring(dbm):find '^dbm %([x%x]+%)$') assert(dbm:close()) assert(tostring(dbm):find '^dbm %(closed%)$') -- Cleanup. apr.file_remove(file1) if file2 then apr.file_remove(file2) end lua-apr-0.23.2.dfsg/test/env-child.lua000066400000000000000000000005011220664456000174150ustar00rootroot00000000000000local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local valid_key = 'LUA_APR_MAGIC_ENV_KEY' local invalid_key = 'LUA_APR_INVALID_ENV_KEY' assert(apr.env_get(valid_key) == apr._VERSION) assert(not apr.env_get(invalid_key)) apr.sleep(1) os.exit(42) lua-apr-0.23.2.dfsg/test/env.lua000066400000000000000000000033721220664456000163450ustar00rootroot00000000000000--[[ Unit tests for the environment manipulation module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Based on http://svn.apache.org/viewvc/apr/apr/trunk/test/testenv.c?view=markup local TEST_ENVVAR_NAME = "apr_test_envvar" local TEST_ENVVAR2_NAME = "apr_test_envvar2" local TEST_ENVVAR_VALUE = "Just a value that we'll check" -- Test that environment variables can be set. assert(apr.env_set(TEST_ENVVAR_NAME, TEST_ENVVAR_VALUE)) -- Test that environment variables can be read. assert(apr.env_get(TEST_ENVVAR_NAME)) assert(apr.env_get(TEST_ENVVAR_NAME) == TEST_ENVVAR_VALUE) -- Test that environment variables can be deleted. assert(apr.env_delete(TEST_ENVVAR_NAME)) assert(not apr.env_get(TEST_ENVVAR_NAME)) -- http://issues.apache.org/bugzilla/show_bug.cgi?id=40764 -- Set empty string and test that status is OK. assert(apr.env_set(TEST_ENVVAR_NAME, "")) assert(apr.env_get(TEST_ENVVAR_NAME)) assert(apr.env_get(TEST_ENVVAR_NAME) == "") -- Delete environment variable and retest. assert(apr.env_delete(TEST_ENVVAR_NAME)) assert(not apr.env_get(TEST_ENVVAR_NAME)) -- Set second variable and test. assert(apr.env_set(TEST_ENVVAR2_NAME, TEST_ENVVAR_VALUE)) assert(apr.env_get(TEST_ENVVAR2_NAME)) assert(apr.env_get(TEST_ENVVAR2_NAME) == TEST_ENVVAR_VALUE) -- Finally, test ENOENT (first variable) followed by second != ENOENT. assert(not apr.env_get(TEST_ENVVAR_NAME)) assert(apr.env_get(TEST_ENVVAR2_NAME)) assert(apr.env_get(TEST_ENVVAR2_NAME) == TEST_ENVVAR_VALUE) -- Cleanup. assert(apr.env_delete(TEST_ENVVAR2_NAME)) lua-apr-0.23.2.dfsg/test/filepath.lua000066400000000000000000000066321220664456000173530ustar00rootroot00000000000000--[[ Unit tests for the file path manipulation module of the Lua/APR binding. Author: Peter Odding Last Change: November 6, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Test apr.filepath_root(). {{{1 if apr.platform_get() == 'WIN32' then assert(apr.filepath_root 'c:/foo/bar' == 'c:/') else -- Doesn't really do anything useful on UNIX :-P assert(apr.filepath_root '/foo/bar' == '/') end -- Test apr.filepath_parent(). {{{1 for _, path in ipairs { 'foo/bar/baz', -- clean and simple path with 3 segments 'foo//bar//baz///' -- same path with some empty segments (should be ignored) } do local root = apr.platform_get() == 'WIN32' and 'c:/' or '/' local abs = function(s) return apr.filepath_merge(root, s) end local p1, n1 = apr.filepath_parent(abs(path)) local p2, n2 = apr.filepath_parent(p1) local p3, n3 = apr.filepath_parent(p2) local p4, n4 = apr.filepath_parent(p3) assert(p4 == root and n4 == '') assert(p3 == root and n3 == 'foo') assert(p2 == abs 'foo/' and n2 == 'bar') assert(p1 == abs 'foo/bar/' and n1 == 'baz') end -- Test apr.filepath_name(). {{{1 assert(apr.filepath_name('/usr/bin/lua') == 'lua') local parts = { apr.filepath_name('/home/xolox/.vimrc', true) } assert(#parts == 2 and parts[1] == '.vimrc' and parts[2] == '') parts = { apr.filepath_name('index.html.en', true) } assert(#parts == 2 and parts[1] == 'index.html' and parts[2] == '.en') -- Test apr.filepath_merge(). {{{1 if apr.platform_get() == 'WIN32' then assert(apr.filepath_merge('c:/', 'foo') == 'c:/foo') else assert(apr.filepath_merge('/foo', 'bar') == '/foo/bar') end -- Test apr.filepath_list_split()/merge(). {{{1 -- Based on http://svn.apache.org/viewvc/apr/apr/trunk/test/testpath.c?view=markup. local PSEP, DSEP local p = apr.platform_get() if p == 'WIN32' or p == 'NETWARE' or p == 'OS2' then PSEP, DSEP = ';', '\\' else PSEP, DSEP = ':', '/' end local PX = "" local P1 = "first path" local P2 = "second" .. DSEP .. "path" local P3 = "th ird" .. DSEP .. "path" local P4 = "fourth" .. DSEP .. "pa th" local P5 = "fifthpath" local parts_in = { P1, P2, P3, PX, P4, P5 } local path_in = table.concat(parts_in, PSEP) local parts_out = { P1, P2, P3, P4, P5 } local path_out = table.concat(parts_out, PSEP) -- list_split_multi do local pathelts = assert(apr.filepath_list_split(path_in)) assert(#parts_out == #pathelts) for i = 1, #pathelts do assert(parts_out[i] == pathelts[i]) end end -- list_split_single for i = 1, #parts_in do local pathelts = assert(apr.filepath_list_split(parts_in[i])) if parts_in[i] == '' then assert(#pathelts == 0) else assert(#pathelts == 1) assert(parts_in[i] == pathelts[1]) end end -- list_merge_multi do local pathelts = {} for i = 1, #parts_in do pathelts[i] = parts_in[i] end local liststr = assert(apr.filepath_list_merge(pathelts)) assert(liststr == path_out) end -- list_merge_single for i = 1, #parts_in do local liststr = assert(apr.filepath_list_merge{ parts_in[i] }) if parts_in[i] == '' then assert(liststr == '') else assert(liststr == parts_in[i]) end end -- Test apr.filepath_which() and apr.filepath_executable(). {{{1 local lua_program = assert(apr.filepath_which 'lua') assert(apr.filepath_executable(lua_program)) lua-apr-0.23.2.dfsg/test/fnmatch.lua000066400000000000000000000021701220664456000171700ustar00rootroot00000000000000--[[ Unit tests for the filename matching module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Check that the ?, *, and [] wild cards are supported. assert(apr.fnmatch('lua_apr.?', 'lua_apr.c')) assert(apr.fnmatch('lua_apr.?', 'lua_apr.h')) assert(apr.fnmatch('lua_apr.[ch]', 'lua_apr.h')) assert(not apr.fnmatch('lua_apr.[ch]', 'lua_apr.l')) assert(not apr.fnmatch('lua_apr.?', 'lua_apr.cc')) assert(apr.fnmatch('lua*', 'lua51')) -- Check that filename matching is case sensitive by default. assert(not apr.fnmatch('lua*', 'LUA51')) -- Check that case insensitive filename matching works. assert(apr.fnmatch('lua*', 'LUA51', true)) -- Check that special characters in filename matching are detected. assert(not apr.fnmatch_test('lua51')) assert(apr.fnmatch_test('lua5?')) assert(apr.fnmatch_test('lua5*')) assert(apr.fnmatch_test('[lL][uU][aA]')) assert(not apr.fnmatch_test('+-^#@!%')) lua-apr-0.23.2.dfsg/test/getopt.lua000066400000000000000000000035551220664456000170620ustar00rootroot00000000000000--[[ Unit tests for command argument parsing module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local function testopts(context) context.arguments[0] = 'getopt' local config = { silent = false, args = context.arguments } local opts, args = assert(apr.getopt(context.usage, config)) assert(helpers.deepequal(opts, context.expected_opts)) assert(helpers.deepequal(args, context.expected_args)) end -- Short options (option letters) only. testopts { usage = [[ -s only an option letter -a=? short option with argument ]], arguments = { 'arg1', '-s', 'arg2', '-a5' }, expected_opts = { s = 1, a = '5' }, expected_args = { 'arg1', 'arg2' } } -- Long option names only. testopts { usage = [[ --long long option name --arg=? long option with argument ]], arguments = { '--long', 'arg1', '--arg=yes', 'arg2' }, expected_opts = { long = 1, arg = 'yes' }, expected_args = { 'arg1', 'arg2' } } -- Options with aliases. testopts { usage = [[ -b, --both option letter and name -a, --arg=? aliased + argument ]], arguments = { '-b', 'arg1', '--arg=yes', 'arg2' }, expected_opts = { b = 1, both = 1, a = 'yes', arg = 'yes' }, expected_args = { 'arg1', 'arg2' } } -- Repeating options. testopts { usage = [[ -v, --verbose increase verbosity -a, --arg=? add value to list ]], arguments = { '-vv', 'a1', '--verbose', 'a2', '-av1', '-a', 'v2', '--arg', 'v3', '--arg=v4', 'a3' }, expected_opts = { v = 3, verbose = 3, a = { 'v1', 'v2', 'v3', 'v4' }, arg = { 'v1', 'v2', 'v3', 'v4' } }, expected_args = { 'a1', 'a2', 'a3' } } lua-apr-0.23.2.dfsg/test/helpers.lua000066400000000000000000000113311220664456000172110ustar00rootroot00000000000000--[[ Test infrastructure for the Lua/APR binding. Author: Peter Odding Last Change: November 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = {} function print(...) local t = {} for i = 1, select('#', ...) do t[#t + 1] = tostring(select(i, ...)) end io.stderr:write(table.concat(t, ' ') .. '\n') end function helpers.pack(...) -- {{{1 return { n = select('#', ...), ... } end function helpers.unpack(t) -- {{{1 return unpack(t, 1, t.n) end function helpers.message(s, ...) -- {{{1 io.stderr:write(string.format(s, ...)) io.stderr:flush() end function helpers.warning(s, ...) -- {{{1 io.stderr:write("\nWarning: ", string.format(s, ...)) io.stderr:flush() end function helpers.soft_assert(tuple, extramsg) -- {{{1 local status, details = helpers.unpack(tuple) if not status then helpers.warning("Soft assertion failed with \"%s\"! (%s)\n", details, extramsg) end end function helpers.try(body, errorhandler) -- {{{1 local status, value = xpcall(body, debug.traceback) if status then return true end errorhandler(value) return false end function helpers.filedefined() -- {{{1 local info = assert(debug.getinfo(2, 'S')) return info.source:sub(2) end function helpers.deepequal(a, b) -- {{{1 if type(a) ~= 'table' or type(b) ~= 'table' then return a == b else for k, v in pairs(a) do if not helpers.deepequal(v, b[k]) then return false end end for k, v in pairs(b) do if not helpers.deepequal(v, a[k]) then return false end end return true end end function helpers.checktuple(expected, ...) -- {{{1 local received = helpers.pack(...) assert(received.n == #expected) for i = 1, #expected do assert(expected[i] == received[i]) end end local testscripts = apr.filepath_parent(helpers.filedefined()) function helpers.scriptpath(name) -- {{{1 return assert(apr.filepath_merge(testscripts, name)) end function helpers.ld_preload_trick(script) -- {{{1 -- XXX This hack is needed to make the tests pass on Ubuntu 10.04 and probably -- also other versions of Ubuntu and Debian? The Lua/APR documentation for the -- DBD module contains some notes about this, here's a direct link: -- http://peterodding.com/code/lua/apr/docs/#debugging_dso_load_failed_errors -- Include the libapr-1.so and libaprutil-1.so libraries in $LD_PRELOAD if -- they exist in the usual Debian location. local libs = apr.filepath_list_split(apr.env_get 'LD_PRELOAD' or '') for _, libname in ipairs { '/usr/lib/libapr-1.so.0', '/usr/lib/libaprutil-1.so.0' } do if apr.stat(libname, 'type') == 'file' then table.insert(libs, libname) end end apr.env_set('LD_PRELOAD', apr.filepath_list_merge(libs)) -- Now run the test in a child process where $LD_PRELOAD applies. local child = assert(apr.proc_create 'lua') assert(child:cmdtype_set 'shellcmd/env') assert(child:exec { helpers.scriptpath(script) }) local dead, reason, code = assert(child:wait(true)) return reason == 'exit' and code == 0 end function helpers.wait_for(signalfile, timeout) -- {{{1 local starttime = apr.time_now() while apr.time_now() - starttime < timeout do apr.sleep(0.25) if apr.stat(signalfile, 'type') == 'file' then return true end end end local tmpnum = 1 local tmpdir = assert(apr.temp_dir_get()) local function tmpname(tmpnum) return apr.filepath_merge(tmpdir, 'lua-apr-tempfile-' .. tmpnum) end function helpers.tmpname() -- {{{1 local file = tmpname(tmpnum) apr.file_remove(file) tmpnum = tmpnum + 1 return file end function helpers.cleanup() -- {{{1 for i = 1, tmpnum do apr.file_remove(tmpname(i)) end end function helpers.readfile(path) -- {{{1 local handle = assert(io.open(path, 'r')) local data = assert(handle:read '*all') assert(handle:close()) return data end function helpers.writefile(path, data) -- {{{1 local handle = assert(io.open(path, 'w')) assert(handle:write(data)) assert(handle:close()) end function helpers.writable(directory) -- {{{1 local entry = apr.filepath_merge(directory, 'io_dir_writable_check') local status = pcall(helpers.writefile, entry, 'something') if status then os.remove(entry) end return status end local escapes = { ['\r'] = '\\r', ['\n'] = '\\n', ['"'] = '\\"', ['\0'] = '\\0' } function helpers.formatvalue(v) -- {{{1 if type(v) == 'number' then local s = string.format('%.99f', v) return s:find '%.' and (s:gsub('0+$', '0')) or s elseif type(v) == 'string' then return '"' .. v:gsub('[\r\n"%z]', escapes) .. '"' else return tostring(v) end end -- }}}1 return helpers lua-apr-0.23.2.dfsg/test/http.lua000066400000000000000000000157521220664456000165410ustar00rootroot00000000000000--[[ Unit tests for the HTTP request parsing module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' if not apr.parse_headers then helpers.warning "HTTP request parsing module not available!\n" return false end local function nl2crlf(s) return (s:gsub('\r?\n', '\r\n')) end -- Test apr.parse_query_string() {{{1 local expected = { alpha = 'one', beta = 'two', omega = 'last' } local actual = assert(apr.parse_query_string 'alpha=one&beta=two;omega=last') assert(helpers.deepequal(expected, actual)) local expected = { key = { '1', '2', '3' }, novalue = true } local actual = assert(apr.parse_query_string 'key=1;key=2;key=3;novalue') assert(helpers.deepequal(expected, actual)) -- Test apr.parse_cookie_header() {{{1 -- Netscape cookies local nscookies = 'a=1; foo=bar; fl=left; fr=right;bad; ns=foo=1&bar=2,frl=right-left; flr=left-right; fll=left-left; good_one=1;=;bad' local cookies, msg, code = assert(apr.parse_cookie_header(nscookies)) assert(code == 'NOTOKEN') assert(cookies.bad == nil) -- ignore wacky cookies that don't have an '=' sign assert(helpers.deepequal({ a = '1', ns = 'foo=1&bar=2', -- accept wacky cookies that contain multiple '=' foo = 'bar', fl = 'left', fr = 'right', frl = 'right-left', flr = 'left-right', fll = 'left-left', good_one = '1', }, cookies)) -- RFC cookies local rfccookies = '$Version=1; first=a;$domain=quux;second=be,$Version=1;third=cie' local cookies, msg, code = assert(apr.parse_cookie_header(rfccookies)) assert(not (msg or code)) assert(helpers.deepequal({ first = 'a', second = 'be', third = 'cie', }, cookies)) -- Invalid cookies. local wpcookies = 'wordpressuser_c580712eb86cad2660b3601ac04202b2=admin; wordpresspass_c580712eb86cad2660b3601ac04202b2=7ebeeed42ef50720940f5b8db2f9db49; rs_session=59ae9b8b503e3af7d17b97e7f77f7ea5; dbx-postmeta=grabit=0-,1-,2-,3-,4-,5-,6-&advancedstuff=0-,1+,2-' local cookies, msg, code = apr.parse_cookie_header(wpcookies) assert(code == 'NOTOKEN') local cgcookies1 = 'UID=MTj9S8CoAzMAAFEq21YAAAAG|c85a9e59db92b261408eb7539ff7f949b92c7d58; $Version=0;SID=MTj9S8CoAzMAAFEq21YAAAAG|c85a9e59db92b261408eb7539ff7f949b92c7d58;$Domain=www.xxxx.com;$Path=/' local cookies, msg, code = apr.parse_cookie_header(cgcookies1) assert(code == 'MISMATCH') local cgcookies2 = 'UID=Gh9VxX8AAAIAAHP7h6AAAAAC|2e809a9cc99c2dca778c385ebdefc5cb86c95dc3; SID=Gh9VxX8AAAIAAHP7h6AAAAAC|2e809a9cc99c2dca778c385ebdefc5cb86c95dc3; $Version=1' local cookies, msg, code = apr.parse_cookie_header(cgcookies2) assert(code == 'MISMATCH') local cgcookies3 = 'UID=hCijN8CoAzMAAGVDO2QAAAAF|50299f079343fd6146257c105b1370f2da78246a; SID=hCijN8CoAzMAAGVDO2QAAAAF|50299f079343fd6146257c105b1370f2da78246a; $Path="/"; $Domain="www.xxxx.com"' local cookies, msg, code = apr.parse_cookie_header(cgcookies3) assert(code == 'MISMATCH') -- Valid cookie. local cgcookies4 = 'SID=66XUEH8AAAIAAFmLLRkAAAAV|2a48c4ae2e9fb8355e75192db211f0779bdce244; UID=66XUEH8AAAIAAFmLLRkAAAAV|2a48c4ae2e9fb8355e75192db211f0779bdce244; __utma=144149162.4479471199095321000.1234471650.1234471650.1234471650.1; __utmb=144149162.24.10.1234471650; __utmc=144149162; __utmz="144149162.1234471650.1.1.utmcsr=szukaj.xxxx.pl|utmccn=(referral)|utmcmd=referral|utmcct=/internet/0,0.html"' local cookies, msg, code = apr.parse_cookie_header(cgcookies4) assert(type(cookies) == 'table') assert(not (msg or code)) -- Test apr.parse_headers() {{{1 local expected = { ['Host'] = 'lua-users.org', ['User-Agent'] = 'Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13', ['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', ['Accept-Language'] = 'nl,en-us;q=0.7,en;q=0.3', ['Accept-Encoding'] = 'gzip,deflate', ['Accept-Charset'] = 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', ['Keep-Alive'] = '115', ['Connection'] = 'keep-alive', ['Cookie'] = 'wiki=randkey&944319634&rev&1&id&4216', } local actual = assert(apr.parse_headers(nl2crlf [[ Host: lua-users.org User-Agent: Mozilla/5.0 (X11; U; Linux i686; nl; rv:1.9.2.13) Gecko/20101206 Ubuntu/10.04 (lucid) Firefox/3.6.13 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: nl,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Cookie: wiki=randkey&944319634&rev&1&id&4216 ]])) assert(helpers.deepequal(expected, actual)) -- Test apr.parse_multipart() {{{1 local expected = { field1 = { 'Joe owes =80100.', ['content-disposition'] = 'form-data; name="field1"', ['content-transfer-encoding'] = 'quoted-printable', ['content-type'] = 'text/plain;charset=windows-1250' }, pics = { 'file1.txt', '... contents of file1.txt ...\r\n', ['Content-Type'] = 'text/plain', ['content-disposition'] = 'form-data; name="pics"; filename="file1.txt"' }, [''] = { 'Joe owes =80100.', ['content-disposition'] = 'form-data; name=""', ['content-transfer-encoding'] = 'quoted-printable', ['content-type'] = 'text/plain;\r\n charset=windows-1250' } } local actual = assert(apr.parse_multipart(nl2crlf [[ --AaB03x content-disposition: form-data; name="field1" content-type: text/plain;charset=windows-1250 content-transfer-encoding: quoted-printable Joe owes =80100. --AaB03x content-disposition: form-data; name="pics"; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --AaB03x content-disposition: form-data; name="" content-type: text/plain; charset=windows-1250 content-transfer-encoding: quoted-printable Joe owes =80100. --AaB03x-- ]], 'multipart/form-data; charset="iso-8859-1"; boundary="AaB03x"')) assert(helpers.deepequal(expected, actual)) -- Test apr.header_attribute() {{{1 local header = 'text/plain; boundary="-foo-", charset=ISO-8859-1'; local value, msg, code = apr.header_attribute(header, 'none') assert(code == 'NOATTR') local value, msg, code = apr.header_attribute(header, 'set') assert(code == 'NOATTR') assert(apr.header_attribute(header, 'boundary') == '-foo-') assert(apr.header_attribute(header, 'charset') == 'ISO-8859-1') local header = 'max-age=20; no-quote="...' assert(apr.header_attribute(header, 'max-age') == '20') local value, msg, code = apr.header_attribute(header, 'age') assert(code == 'BADSEQ') local value, msg, code = apr.header_attribute(header, 'no-quote') assert(code == 'BADSEQ') -- Test apr.uri_encode() and apr.uri_decode() {{{1 local reserved = { ['!'] = '%21', ['*'] = '%2A', ["'"] = '%27', ['('] = '%28', [')'] = '%29', [';'] = '%3B', [':'] = '%3A', ['@'] = '%40', ['&'] = '%26', ['='] = '%3D', ['+'] = '%2B', ['$'] = '%24', [','] = '%2C', ['/'] = '%2F', ['?'] = '%3F', ['#'] = '%23', ['['] = '%5B', [']'] = '%5D' } for plain, encoded in pairs(reserved) do assert(apr.uri_encode(plain) == encoded) assert(apr.uri_encode(plain) == encoded) end lua-apr-0.23.2.dfsg/test/init.lua000066400000000000000000000046331220664456000165210ustar00rootroot00000000000000--[[ Driver script for the unit tests of the Lua/APR binding. Author: Peter Odding Last Change: November 13, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT Because the unit tests for the Lua/APR binding are included as installable modules, it's easy to run the test suite once you've installed the Lua/APR binding. Just execute the following command from a terminal: lua -e "require 'apr.test' ()" --]] -- TODO Cleanup and extend the tests for `filepath.c'. -- TODO Add tests for file:seek() (tricky to get right!) -- TODO Add tests for apr.glob()! -- Names of modules for which tests have been written (the individual lines -- enable automatic rebasing between git feature branches and master branch). local modules = { 'base64', 'crypt', 'date', 'dbd', 'dbm', 'env', 'filepath', 'fnmatch', 'getopt', 'http', 'io_dir', 'io_file', 'io_net', 'ldap', 'memcache', 'misc', 'pollset', 'proc', 'serialize', 'shm', 'signal', 'str', 'thread', 'thread_queue', 'time', 'uri', 'user', 'uuid', 'xlate', 'xml' } local modname = ... return function() local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local success = true for _, testname in ipairs(modules) do local modname = modname .. '.' .. testname package.loaded[modname] = nil helpers.message("Running %s tests: ", testname) local starttime = apr.time_now() local status, result = pcall(require, modname) if status and result ~= false then -- All tests passed. local elapsed = apr.time_now() - starttime if elapsed >= 0.5 then helpers.message("OK (%.2fs)\n", elapsed) else helpers.message "OK\n" end elseif status then -- Soft failure (anticipated). helpers.message("Skipped!\n") else -- Hard failure. helpers.message("Failed! (%s)\n", result) success = false end package.loaded[modname] = nil -- Garbage collect unreferenced objects before testing the next module. collectgarbage 'collect' collectgarbage 'collect' end -- Cleanup temporary files. helpers.cleanup() helpers.message "Done!\n" -- Exit the interpreter (started with lua -e "require 'apr.test' ()"). os.exit(success and 0 or 1) end -- vim: ts=2 sw=2 et lua-apr-0.23.2.dfsg/test/io_buffer.lua000066400000000000000000000027411220664456000175140ustar00rootroot00000000000000--[[ Unit tests for the buffered I/O interface of the Lua/APR binding. Author: Peter Odding Last Change: June 15, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local helpers = require 'apr.test.helpers' local verbosity = 0 local function testformat(apr_file, lua_file, format) if verbosity >= 1 then helpers.message("Testing file:read(%s) ..\n", format) end repeat local lua_value = lua_file:read(format) if verbosity >= 2 then helpers.message("file:read(%s) = %s\n", format, helpers.formatvalue(lua_value)) end local apr_value = apr_file:read(format) if lua_value ~= apr_value then helpers.warning("Wrong result for file:read(%s)!\nLua value: %s\nAPR value: %s\n", format, helpers.formatvalue(lua_value), helpers.formatvalue(apr_value)) helpers.warning("Lua position: %i, APR position: %i\n", lua_file:seek 'cur', apr_file:seek 'cur') helpers.warning("Remaining data in Lua file: %s\n", helpers.formatvalue(lua_file:read '*a')) helpers.warning("Remaining data in APR file: %s\n", helpers.formatvalue(apr_file:read '*a')) os.exit(1) end until (format == '*a' and lua_value == '') or not lua_value end return function(test_file, apr_object) local lua_file = assert(io.open(test_file)) for _, format in pairs { '*n', '*l', '*a', 1, 2, 3, 4, 5, 10, 20, 50, 100 } do testformat(apr_object, lua_file, format) apr_object:seek('set', 0) lua_file:seek('set', 0) end end lua-apr-0.23.2.dfsg/test/io_dir.lua000066400000000000000000000113021220664456000170120ustar00rootroot00000000000000--[[ Unit tests for the directory manipulation module of the Lua/APR binding. Author: Peter Odding Last Change: November 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Make sure apr.temp_dir_get() returns an existing, writable directory local directory = assert(apr.temp_dir_get()) assert(helpers.writable(directory)) -- Create a temporary workspace directory for the following tests math.randomseed(os.time()) local io_dir_tests = apr.filepath_merge(directory, string.format('lua-apr-io_dir_tests-%i', math.random(1e9))) assert(apr.dir_make(io_dir_tests)) -- Change to the temporary workspace directory local cwd_save = assert(apr.filepath_get()) assert(apr.filepath_set(io_dir_tests)) -- Test dir_make() assert(apr.dir_make 'foobar') assert(helpers.writable 'foobar') -- Test dir_remove() assert(apr.dir_remove 'foobar') assert(not helpers.writable 'foobar') -- Test dir_make_recursive() and dir_remove_recursive() assert(apr.dir_make_recursive 'foo/bar/baz') assert(helpers.writable 'foo/bar/baz') assert(apr.dir_remove_recursive 'foo') assert(not helpers.writable 'foo') -- Random selection of Unicode from my music library :-) local msi = 'Mindless Self Indulgence - Despierta Los Niños' local manu_chao = 'Manu Chao - Próxima Estación; Esperanza' local cassius = 'Cassius - Au Rêve' local yoko_kanno = '菅野 よう子' local nonascii = { msi, manu_chao, cassius, yoko_kanno } -- Workarounds for Unicode normalization on Mac OS X. {{{1 -- Mac OS X apparently applies Unicode normalization on file system level. This -- means you can write a file without getting any errors, but when you check -- for the file later it doesn't exist (because the normalized form differs -- from the original form and the normalized form is reported back by the OS). -- See also issue 10 on GitHub: https://github.com/xolox/lua-apr/issues/10. -- The following table maps the titles above to their normalized form. local nonascii_normalized = { -- Technically it's superstition that made me write out these normalized -- forms as sequences of bytes. I did so because the visual differences -- between the normalized forms and the original track titles above are so -- small it hurts my head :-( [string.char(77, 105, 110, 100, 108, 101, 115, 115, 32, 83, 101, 108, 102, 32, 73, 110, 100, 117, 108, 103, 101, 110, 99, 101, 32, 45, 32, 68, 101, 115, 112, 105, 101, 114, 116, 97, 32, 76, 111, 115, 32, 78, 105, 110, 204, 131, 111, 115)] = msi, [string.char(77, 97, 110, 117, 32, 67, 104, 97, 111, 32, 45, 32, 80, 114, 111, 204, 129, 120, 105, 109, 97, 32, 69, 115, 116, 97, 99, 105, 111, 204, 129, 110, 59, 32, 69, 115, 112, 101, 114, 97, 110, 122, 97)] = manu_chao, [string.char(67, 97, 115, 115, 105, 117, 115, 32, 45, 32, 65, 117, 32, 82, 101, 204, 130, 118, 101)] = cassius, } local warned_about_normalization = false local function handle_normalized_forms(s) if nonascii_normalized[s] then if not warned_about_normalization then helpers.warning "Detected Unicode normalization on file system level, applying workaround... (you're probably on Mac OS X)\n" warned_about_normalization = true end return nonascii_normalized[s] else return s end end -- }}}1 for _, name in ipairs(nonascii) do assert(apr.dir_make(name)) -- Using writable() here won't work because the APR API deals with UTF-8 -- while the Lua API does not, which makes the strings non-equal... :-) assert(assert(apr.stat(name, 'type')) == 'directory') end -- Test apr.dir_open() and directory methods. local dir = assert(apr.dir_open '.') local entries = {} for name in dir:entries 'name' do entries[#entries+1] = handle_normalized_forms(name) end assert(dir:rewind()) local rewinded = {} for name in dir:entries 'name' do rewinded[#rewinded+1] = handle_normalized_forms(name) end assert(tostring(dir):find '^directory %([x%x]+%)$') assert(dir:close()) assert(tostring(dir):find '^directory %(closed%)$') table.sort(nonascii) table.sort(entries) table.sort(rewinded) if not pcall(function() for i = 1, math.max(#nonascii, #entries, #rewinded) do assert(nonascii[i] == entries[i]) assert(entries[i] == rewinded[i]) end end) then error("Directory traversal returned incorrect result?\n" .. 'Input strings: "' .. table.concat(nonascii, '", "') .. '"\n' .. 'Directory entries: "' .. table.concat(entries, '", "') .. '"\n' .. 'Rewinded entries: "' .. table.concat(rewinded, '", "') .. '"') end -- Remove temporary workspace directory assert(apr.filepath_set(cwd_save)) assert(apr.dir_remove_recursive(io_dir_tests)) lua-apr-0.23.2.dfsg/test/io_file-bidi_pipes.lua000066400000000000000000000006311220664456000212630ustar00rootroot00000000000000local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local stdin = assert(apr.pipe_open_stdin()) local stdout = assert(apr.pipe_open_stdout()) local stderr = assert(apr.pipe_open_stderr()) while true do local input = stdin:read() if not input then break end stdout:write(input:lower(), '\n') stderr:write(input:upper(), '\n') end lua-apr-0.23.2.dfsg/test/io_file-named_pipe.lua000066400000000000000000000005061220664456000212560ustar00rootroot00000000000000local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local namedpipe = assert(table.remove(arg, 1)) local namedmsg = assert(table.concat(arg, ' ')) local handle = assert(apr.file_open(namedpipe, 'w')) assert(handle:write(namedmsg)) assert(handle:close()) lua-apr-0.23.2.dfsg/test/io_file.lua000066400000000000000000000156671220664456000171750ustar00rootroot00000000000000--[[ Unit tests for the file I/O handling module of the Lua/APR binding. Author: Peter Odding Last Change: December 6, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local selfpath = helpers.filedefined() local testdata = [[ 1 3.1 100 0xCAFEBABE 0xDEADBEEF 3.141592653589793115997963468544185161590576171875 this line is in fact not a number :-) that was an empty line ]] -- Test the stat() function. {{{1 local info = apr.stat(selfpath) assert(type(info) == 'table') assert(info.name == 'io_file.lua') assert(info.path:find 'io_file%.lua$') assert(info.type == 'file') assert(info.size >= 1024 * 5) assert(info.mtime >= 1293510503) assert(info.nlink >= 1) assert(type(info.inode) == 'number') assert(type(info.dev) == 'number') assert(info.protection:find '^[-r][-w][-xSs][-r][-w][-xSs][-r][-w][-xTt]$') -- Test the alternative stat() interface. {{{1 assert(apr.stat(selfpath, 'type') == 'file') assert(apr.stat(selfpath, 'name') == 'io_file.lua') local selfdir = apr.filepath_parent(selfpath) local kind, size, prot = apr.stat(selfdir, 'type', 'size', 'protection') assert(kind == 'directory') assert(type(size) == 'number') assert(prot:find '^[-r][-w][-xSs][-r][-w][-xSs][-r][-w][-xTt]$') -- Test apr.file_perms_set(). {{{1 local tempname = assert(helpers.tmpname()) helpers.writefile(tempname, 'something') local status, errmsg, errcode = apr.file_perms_set(tempname, 'rw-rw----') if errcode ~= 'ENOTIMPL' then assert(apr.stat(tempname, 'protection') == 'rw-rw----') assert(apr.file_perms_set(tempname, 'ug=r,o=')) assert(apr.stat(tempname, 'protection') == 'r--r-----') end -- Test apr.file_copy(). {{{1 local copy1 = assert(helpers.tmpname()) helpers.writefile(copy1, testdata) local copy2 = assert(helpers.tmpname()) assert(apr.file_copy(copy1, copy2)) assert(testdata == helpers.readfile(copy2)) -- Test apr.file_append(). {{{1 assert(apr.file_append(copy1, copy2)) assert(helpers.readfile(copy2) == testdata:rep(2)) -- Test apr.file_rename(). {{{1 assert(apr.file_rename(copy1, copy2)) assert(not apr.stat(copy1)) assert(helpers.readfile(copy2) == testdata) -- Test apr.file_mtime_set(). {{{1 local mtime = math.random(0, apr.time_now()) assert(apr.stat(copy2, 'mtime') ~= mtime) assert(apr.file_mtime_set(copy2, mtime)) assert(apr.stat(copy2, 'mtime') == mtime) -- Test apr.file_attrs_set(). {{{1 local status, errmsg, errcode = apr.file_perms_set(copy2, 'ug=rw,o=') if errcode ~= 'ENOTIMPL' then assert(apr.stat(copy2, 'protection'):find '^.w..w....$') assert(apr.file_attrs_set(copy2, { readonly=true })) assert(apr.stat(copy2, 'protection'):find '^.[^w]..[^w]....$') end -- Test file:stat(). {{{1 local handle = assert(apr.file_open(copy2)) assert(handle:stat('type') == 'file') assert(handle:stat('size') >= #testdata) -- Test file:lines(). {{{1 local lines = {} for line in assert(handle:lines()) do lines[#lines + 1] = line end for line in testdata:gmatch '[^\n]+' do local otherline = table.remove(lines, 1) if otherline == '' then -- the pattern above ignores the empty line otherline = table.remove(lines, 1) end assert(line == otherline) end assert(#lines == 0) -- Test file:truncate(). {{{1 local file_to_truncate = helpers.tmpname() helpers.writefile(file_to_truncate, '1234567890') assert(apr.file_truncate(file_to_truncate, 10)) assert(helpers.readfile(file_to_truncate) == '1234567890') assert(apr.file_truncate(file_to_truncate, 5)) assert(helpers.readfile(file_to_truncate) == '12345') assert(apr.file_truncate(file_to_truncate)) assert(helpers.readfile(file_to_truncate) == '') -- Test tostring(file). {{{1 assert(tostring(handle):find '^file %([x%x]+%)$') assert(handle:close()) assert(tostring(handle):find '^file %(closed%)$') -- Test file:fd_get() and apr.file_open(fd). {{{1 local fname = assert(helpers.tmpname()) local msg = 'So does it expose file descriptors?' local writehandle = assert(io.open(fname, 'w')) assert(writehandle:write(msg)) assert(writehandle:close()) local readhandle = assert(apr.file_open(fname)) if readhandle.fd_get then -- file:fd_get() is supported. local fd = assert(readhandle:fd_get()) assert(type(fd) == 'number') local newhandle = assert(apr.file_open(fd)) assert(msg == assert(newhandle:read())) assert(newhandle:close()) end -- Test file:read(), file:write() and file:seek() {{{1 local maxmultiplier = 20 for testsize = 1, maxmultiplier do local testdata = testdata:rep(testsize) -- message("Testing file I/O on a file of %i bytes (step %i/%i)..\n", #testdata, testsize, maxmultiplier) local testlines = {} for l in testdata:gmatch '[^\r\n]*' do table.insert(testlines, l) end -- Write test data to file, execute buffered I/O tests. local tempname = helpers.tmpname() helpers.writefile(tempname, testdata) local test_buffer = require(((...):gsub('io_file$', 'io_buffer'))) test_buffer(tempname, assert(apr.file_open(tempname, 'r'))) -- Perform write tests. local lua_file = assert(helpers.tmpname()) local apr_file = assert(helpers.tmpname()) local function write_all(lua_handle, apr_handle) assert(lua_handle:write(testdata)) assert(apr_handle:write(testdata)) end local function write_blocks(lua_handle, apr_handle) local i = 1 local bs = 1 repeat assert(lua_handle:write(testdata:sub(i, i + bs))) assert(apr_handle:write(testdata:sub(i, i + bs))) i = i + bs + 1 bs = bs * 2 until i > #testdata end local function write_lines(lua_handle, apr_handle) for _, line in ipairs(testlines) do assert(lua_handle:write(line, '\n')) assert(apr_handle:write(line, '\n')) end end for i, mode in ipairs { 'w', 'wb' } do for j, writemethod in ipairs { write_all, write_blocks, write_lines } do local lua_handle = assert(io.open(lua_file, mode)) -- TODO test b mode local apr_handle = assert(apr.file_open(apr_file, mode)) -- helpers.message("Testing file:write() mode %i, method %i ..", i, j) writemethod(lua_handle, apr_handle) assert(lua_handle:close()) assert(apr_handle:close()) for _, format in ipairs { '*l', '*a' } do lua_handle = assert(io.open(lua_file, 'r')) apr_handle = assert(apr.file_open(apr_file, 'r')) while true do local lua_value = lua_handle:read(format) local apr_value = apr_handle:read(format) if lua_value ~= apr_value then helpers.warning("Buggy output from file:write()?!\nLua value: %s\nAPR value: %s\n", helpers.formatvalue(lua_value), helpers.formatvalue(apr_value)) end assert(lua_value == apr_value) if not lua_value or (format == '*a' and lua_value == '') then break end end assert(lua_handle:close()) assert(apr_handle:close()) end end end assert(os.remove(lua_file)) assert(os.remove(apr_file)) end lua-apr-0.23.2.dfsg/test/io_net-server.lua000066400000000000000000000010161220664456000203270ustar00rootroot00000000000000local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local server = assert(apr.socket_create()) assert(server:bind('*', arg[1])) assert(server:listen(1)) -- Signal to the test suite that we've initialized successfully? local handle = assert(io.open(arg[2], 'w')) assert(handle:write 'DONE') assert(handle:close()) local client = assert(server:accept()) for line in client:lines() do assert(client:write(line:upper(), '\n')) end assert(client:close()) lua-apr-0.23.2.dfsg/test/io_net.lua000066400000000000000000000052541220664456000170330ustar00rootroot00000000000000--[[ Unit tests for the network I/O handling module of the Lua/APR binding. Author: Peter Odding Last Change: December 7, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Test apr.hostname_get(), apr.host_to_addr() and apr.addr_to_host(). {{{1 local hostname = assert(apr.hostname_get()) local rdns_ok = false for i, address in ipairs { assert(apr.host_to_addr(hostname)) } do if apr.addr_to_host(address) then rdns_ok = true end end if not rdns_ok then helpers.warning "Soft assertion failed: Reverse DNS of local host name failed!\n" end -- Test socket:bind(), socket:listen() and socket:accept(). {{{1 local server = assert(apr.proc_create 'lua') local port = math.random(10000, 50000) local signalfile = helpers.tmpname() local scriptfile = helpers.scriptpath 'io_net-server.lua' assert(server:cmdtype_set 'shellcmd/env') assert(server:exec { scriptfile, port, signalfile }) assert(helpers.wait_for(signalfile, 15), "Failed to initialize " .. scriptfile) local client = assert(apr.socket_create()) assert(client:connect('localhost', port)) for _, msg in ipairs { 'First line', 'Second line', 'Third line' } do assert(client:write(msg, '\n')) assert(msg:upper() == assert(client:read())) end -- Test socket:fd_get() and socket:fd_set(). {{{1 local fd = assert(client:fd_get()) local thread = assert(apr.thread(function() -- Load the Lua/APR binding. local apr = require 'apr' -- Convert file descriptor to socket. local client = assert(apr.socket_create()) assert(client:fd_set(fd)) local msg = 'So does it expose file descriptors?' assert(client:write(msg, '\n')) assert(msg:upper() == assert(client:read())) -- Test tostring(socket). assert(tostring(client):find '^socket %([x%x]+%)$') assert(client:close()) assert(tostring(client):find '^socket %(closed%)$') end)) assert(thread:join()) -- Test UDP server socket using socket:recvfrom() . {{{1 local udp_port = math.random(10000, 50000) local udp_socket = assert(apr.socket_create 'udp') assert(udp_socket:bind('*', udp_port)) local server = assert(apr.thread(function() local client, data = assert(udp_socket:recvfrom()) assert(client.address == '127.0.0.1') assert(client.port >= 1024) assert(data == 'booyah!') end)) local client = assert(apr.thread(function() local apr = require 'apr' local socket = assert(apr.socket_create 'udp') assert(socket:connect('127.0.0.1', udp_port)) assert(socket:write 'booyah!') assert(socket:close()) end)) assert(server:join()) assert(client:join()) lua-apr-0.23.2.dfsg/test/ldap-child.lua000066400000000000000000000155301220664456000175550ustar00rootroot00000000000000--[[ Unit tests for the LDAP connection handling module of the Lua/APR binding. Author: Peter Odding Last Change: December 3, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT The LDAP client tests need access to an LDAP server so if you want to run these tests you have to define the following environment variables: - LUA_APR_LDAP_URL is a URL indicating SSL, host name and port - LUA_APR_LDAP_WHO is the distinguished name used to bind (login) - LUA_APR_LDAP_PASSWD is the password used to bind (login) - LUA_APR_LDAP_BASE is the base of the directory (required to search) To enable the add()/modify()/compare()/delete() tests you will need to define the following environment variable to the indicated value: - LUA_APR_LDAP_WRITE_ALLOWED=yes --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Enable overriding of test configuration using environment variables. local SERVER = apr.env_get 'LUA_APR_LDAP_URL' local ACCOUNT = apr.env_get 'LUA_APR_LDAP_WHO' or nil local PASSWD = apr.env_get 'LUA_APR_LDAP_PASSWD' or nil local BASE = apr.env_get 'LUA_APR_LDAP_BASE' or nil local WRITE_ALLOWED = apr.env_get 'LUA_APR_LDAP_WRITE_ALLOWED' == 'yes' -- Test apr.ldap_url_check(). {{{1 assert(apr.ldap_url_check 'ldap://root.openldap.org/dc=openldap,dc=org' == 'ldap') assert(apr.ldap_url_check 'ldapi://root.openldap.org/dc=openldap,dc=org' == 'ldapi') assert(apr.ldap_url_check 'ldaps://root.openldap.org/dc=openldap,dc=org' == 'ldaps') assert(not apr.ldap_url_check 'http://root.openldap.org/dc=openldap,dc=org') -- Test apr.ldap_url_parse(). {{{1 local url = 'ldap://root.openldap.org/dc=openldap,dc=org' local components = assert(apr.ldap_url_parse(url)) assert(components.scheme == 'ldap') assert(components.host == 'root.openldap.org') assert(components.port == 389) assert(components.scope == 'sub') assert(components.dn == 'dc=openldap,dc=org') assert(components.crit_exts == 0) -- Test apr.ldap_info(). {{{1 local info, errmsg = apr.ldap_info() if not info then helpers.warning "apr.ldap_info() failed, I'm guessing you don't have an LDAP library installed?\n" os.exit(1) end assert(type(info) == 'string' and info ~= '') -- Print the LDAP SDK being used (may be helpful in debugging). info = info:gsub('^APR LDAP: Built with ', '') helpers.message("\rRunning ldap tests using %s: ", info) -- Test apr.ldap(). {{{1 local ldap_conn = assert(apr.ldap(SERVER)) -- Test tostring(ldap_conn). assert(tostring(ldap_conn):match '^LDAP connection %([0x%x]+%)$') assert(apr.type(ldap_conn) == 'LDAP connection') -- Test ldap_conn:bind(). {{{1 local status, errmsg = ldap_conn:bind(ACCOUNT, PASSWD) if not status then helpers.warning("Failed to bind to LDAP server, I'm assuming it's not available (reason: %s)\n", errmsg) os.exit(1) end -- Test ldap_conn:option_get() and ldap_conn:option_set(). {{{1 assert(ldap_conn:option_set('timeout', 0.5)) assert(ldap_conn:option_set('network-timeout', 0.5)) for option, typename in pairs { ['defbase'] = 'string', ['deref'] = 'number', ['network-timeout'] = 'number', ['protocol-version'] = 'number', ['refhop-limit'] = 'number', ['referrals'] = 'boolean', ['restart'] = 'boolean', ['size-limit'] = 'number', ['time-limit'] = 'number', ['timeout'] = 'number', ['uri'] = 'string', } do local value = ldap_conn:option_get(option) if value ~= nil then assert(type(value) == typename) local status, errmsg = ldap_conn:option_set(option, value) if not status then -- I've made this a warning instead of an error because I'm not even sure -- if all options can be set and whether this goes for all SDKs. helpers.warning("Failed to set LDAP option %s to %s! (reason: %s)\n", option, tostring(value), errmsg) end end end -- Skip search tests when $LUA_APR_LDAP_BASE isn't set. {{{1 if not BASE then helpers.warning "Please set $LUA_APR_LDAP_BASE to enable the LDAP search tests ..\n" assert(ldap_conn:unbind()) return end -- Test ldap_conn:search(). {{{1 local attributes = {} local valuetypes = {} for dn, attrs in ldap_conn:search { scope = 'sub', base = BASE } do assert(attrs.objectClass, "LDAP search result without objectClass?!") for k, v in pairs(attrs) do local t = type(v) attributes[k] = (attributes[k] or 0) + 1 valuetypes[t] = (valuetypes[t] or 0) + 1 end end -- Assuming the search matched some entries... if next(valuetypes) then -- Check that the supported value types were tested. assert(valuetypes.table > 0, "No table attributes (multiple values for one attribute) in LDAP directory?!") assert(valuetypes.string > 0, "No string attributes in LDAP directory?!") assert(valuetypes.string > valuetypes.table, "Expecting more string than table attributes?!") end -- Again, assuming the search matched some entries... if next(attributes) then -- Check that some common attributes were found. assert(attributes.cn > 0, "No common names matched in LDAP directory?!") assert(attributes.sn > 0, "No last names matched in LDAP directory?!") assert(attributes.givenName > 0, "No first names matched in LDAP directory?!") end -- Skip modification tests when $LUA_APR_LDAP_WRITE_ALLOWED isn't set. {{{1 if not WRITE_ALLOWED then helpers.warning "Please set $LUA_APR_LDAP_WRITE_ALLOWED=yes to enable the LDAP modification tests ..\n" assert(ldap_conn:unbind()) return end local NEW_USER_GN = 'Lua/APR' local NEW_USER_SN = 'Test User' local NEW_USER_CN = 'lua_apr_testuser_1' local NEW_USER_DN = 'cn=' .. NEW_USER_CN .. ',' .. BASE local RENAMED_RDN = 'cn=lua_apr_testuser_2' local RENAMED_DN = RENAMED_RDN .. ',' .. BASE -- Cleanup records from previous (failed) runs. ldap_conn:delete(NEW_USER_DN)() ldap_conn:delete(RENAMED_DN)() -- Test ldap_conn:add(). {{{1 assert(ldap_conn:add(NEW_USER_DN, { objectClass = { 'top', 'person', 'organizationalPerson', 'inetOrgPerson' }, cn = NEW_USER_CN, sn = NEW_USER_SN, givenName = NEW_USER_GN, })()) -- Test ldap_conn:modify(). {{{1 local function test_modify(operation, attribute, old_value, new_value) -- Apply the modification. assert(ldap_conn:modify(NEW_USER_DN, { operation, [attribute] = new_value })()) -- Check that the modification was applied successfully. assert(ldap_conn:compare(NEW_USER_DN, attribute, new_value)() == true) end -- TODO More tests, also for '+' and '-' operations. test_modify('=', 'givenName', NEW_USER_GN, NEW_USER_GN .. ' (modified)') -- Test ldap_conn:rename() and ldap_conn:delete(). {{{1 assert(ldap_conn:rename(NEW_USER_DN, RENAMED_RDN)()) -- copy record / create another reference. assert(ldap_conn:compare(RENAMED_DN, 'sn', NEW_USER_SN)() == true) -- Test ldap_conn:delete(). {{{1 assert(ldap_conn:delete(RENAMED_DN)()) assert(ldap_conn:compare(RENAMED_DN, 'sn', NEW_USER_SN)() ~= true) -- Test ldap_conn:unbind(). {{{1 assert(ldap_conn:unbind()) lua-apr-0.23.2.dfsg/test/ldap.lua000066400000000000000000000011431220664456000164670ustar00rootroot00000000000000--[[ Unit tests for the LDAP connection handling module of the Lua/APR binding. Author: Peter Odding Last Change: October 29, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script executes the real test in ldap-child.lua as a child process. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' if not apr.ldap then helpers.warning "LDAP module not available!\n" return false end return helpers.ld_preload_trick 'ldap-child.lua' lua-apr-0.23.2.dfsg/test/memcache.lua000066400000000000000000000121711220664456000173140ustar00rootroot00000000000000--[[ Unit tests for the relational database module of the Lua/APR binding. Authors: - zhiguo zhao - Peter Odding Last Change: December 3, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT These tests are based on http://svn.apache.org/viewvc/apr/apr/trunk/test/testmemcache.c?view=markup. If you have memcached running on a remote machine you can set the environment variable LUA_APR_MEMCACHE_HOST to the host name or IP-address of the server. You can also set LUA_APR_MEMCACHE_PORT to change the port number. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- You might have to change these depending on your environment. local server_host = apr.env_get 'LUA_APR_MEMCACHE_HOST' or '127.0.0.1' local default_port = apr.env_get 'LUA_APR_MEMCACHE_PORT' or 11211 local max_servers = 10 -- Test data. local prefix = 'testmemcache' local TDATA_SIZE = 500 local txt = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at' .. 'lacus in ligula hendrerit consectetuer. Vestibulum tristique odio' .. 'iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non,' .. 'neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum' .. 'nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat' .. 'tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis' .. 'tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in,' .. 'convallis id, iaculis feugiat cras amet.' -- Create a memcached client object. local client = assert(apr.memcache(max_servers)) assert(apr.type(client) == 'memcache client') assert(tostring(client):find '^memcache client %([x%x]+%)$') local server = assert(client:add_server(server_host, default_port)) assert(client:enable_server(server)) -- Test metadata (server version and statistics). local version, message, code = client:version(server) if code == 'ECONNREFUSED' then helpers.warning("Looks like memcached isn't available! (%s)\n", message) return false end assert(type(version) == 'string') -- Print the Memcached server version (may be helpful in debugging). helpers.message('\rRunning memcache tests against %s server: ', version) local stats = assert(client:stats(server)) assert(type(stats) == 'table') assert(stats.version == version) assert(stats.pid >= 0) assert(stats.time >= 0) assert(stats.rusage_user >= 0) assert(stats.rusage_system >= 0) assert(stats.curr_items >= 0) assert(stats.total_items >= 0) assert(stats.bytes >= 0) assert(stats.curr_connections >= 0) assert(stats.total_connections >= 0) assert(stats.connection_structures >= 0) assert(stats.cmd_get >= 0) assert(stats.cmd_set >= 0) assert(stats.get_hits >= 0) assert(stats.get_misses >= 0) assert(stats.evictions >= 0) assert(stats.bytes_read >= 0) assert(stats.bytes_written >= 0) assert(stats.limit_maxbytes >= 0) assert(stats.threads >= 0) -- Generate test data from the lorem ipsum text above. local testpairs = {} math.randomseed(os.time()) for i = 1, TDATA_SIZE do testpairs[prefix .. i] = txt:sub(1, math.random(1, #txt)) end local function delete(client, key) -- clean up. if not client:delete(key) then -- https://github.com/xolox/lua-apr/issues/5#issuecomment-2106284 assert(client:delete(key, 0)) end end -- Test client:add(), client:replace(), client:get() and client:delete(). for key, value in pairs(testpairs) do -- doesn't exist yet, fail. assert(not client:replace(key, value)) -- doesn't exist yet, succeed. assert(client:add(key, value)) helpers.checktuple({ true, value }, assert(client:get(key))) -- exists now, succeed. assert(client:replace(key, 'new')) -- make sure its different. helpers.checktuple({ true, 'new' }, assert(client:get(key))) -- exists now, fail. assert(not client:add(key, value)) -- clean up. delete(client, key) local status, value = client:get(key) assert(status and not value) end -- Test client:incr() and client:decr(). local value = 271 assert(client:set(prefix, value)) for i = 1, TDATA_SIZE do local increment = math.random(1, TDATA_SIZE) value = value + increment assert(client:incr(prefix, increment) == value) local status, strval = assert(client:get(prefix)) assert(tonumber(strval) == value) local decrement = math.random(1, value) value = value - decrement assert(client:decr(prefix, decrement) == value) local status, strval = assert(client:get(prefix)) assert(tonumber(strval) == value) end delete(client, prefix) -- Test server management functions. for i = 1, max_servers - 1 do local port = default_port + i local fake_server = assert(client:add_server(server_host, port)) assert(apr.type(fake_server) == 'memcache server') assert(tostring(fake_server):find '^memcache server %([x%x]+%)$') assert(client:find_server(server_host, port)) assert(client:enable_server(fake_server)) local hash = client:hash(prefix) assert(hash > 0) assert(apr.type(client:find_server_hash(hash)) == 'memcache server') assert(client:disable_server(fake_server)) end lua-apr-0.23.2.dfsg/test/misc.lua000066400000000000000000000022611220664456000165040ustar00rootroot00000000000000--[[ Unit tests for the miscellaneous routines of the Lua/APR binding. Author: Peter Odding Last Change: July 1, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Test apr.type() local selfpath = helpers.filedefined() assert(apr.type(apr.file_open(selfpath)) == 'file') assert(apr.type(apr.socket_create()) == 'socket') assert(apr.type(apr.proc_create 'test') == 'process') assert(apr.type(apr.dir_open '.') == 'directory') -- Test apr.version_get() local v = apr.version_get() assert(v.apr:find '^%d+%.%d+%.%d+$') assert(v.aprutil == nil or v.aprutil:find '^%d+%.%d+%.%d+$') assert(v.apreq == nil or v.apreq:find '^%d+%.%d+%.%d+$') -- Test status_to_name() (indirectly). assert(select(3, apr.stat("I assume this won't exist")) == 'ENOENT') -- Test apr.os_default/locale_encoding() local default = apr.os_default_encoding() local locale = apr.os_locale_encoding() assert(type(default) == 'string' and default:find '%S') assert(type(locale) == 'string' and locale:find '%S') lua-apr-0.23.2.dfsg/test/pollset.lua000066400000000000000000000046171220664456000172420ustar00rootroot00000000000000--[[ Unit tests for the pollset module of the Lua/APR binding. Author: Peter Odding Last Change: November 20, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local apr = require 'apr' local SERVER_PORT = math.random(10000, 40000) local NUM_CLIENTS = 25 local main, server_loop, client_loop function main() -- {{{1 local server_thread = assert(apr.thread(server_loop)) apr.sleep(0.25) local client_threads = {} for i = 1, NUM_CLIENTS do table.insert(client_threads, assert(apr.thread(client_loop))) end local _, served_clients = assert(server_thread:join()) for i = 1, NUM_CLIENTS do assert(client_threads[i]:join()) end assert(served_clients == NUM_CLIENTS) end function server_loop() -- {{{1 local apr = require 'apr' -- Create the pollset object (+1 for the server socket). local pollset = assert(apr.pollset(NUM_CLIENTS + 1)) -- Create a server socket. local server = assert(apr.socket_create()) assert(server:bind('*', SERVER_PORT)) assert(server:listen(NUM_CLIENTS)) -- Add the server socket to the pollset. assert(pollset:add(server, 'input')) -- Loop to handle connections. local counter = 0 while counter < NUM_CLIENTS do local readable = assert(pollset:poll(-1)) for _, socket in ipairs(readable) do if socket == server then local client = assert(server:accept()) assert(pollset:add(client, 'input')) else assert('first request line' == assert(socket:read())) assert(socket:write 'first response line\n') assert('second request line' == assert(socket:read())) assert(socket:write 'second response line\n') assert(pollset:remove(socket)) assert(socket:close()) counter = counter + 1 end end end -- Remove the server socket from the pollset. assert(pollset:remove(server)) assert(server:close()) -- Destroy the pollset. assert(pollset:destroy()) return counter end function client_loop() -- {{{1 local apr = require 'apr' local socket = assert(apr.socket_create()) assert(socket:connect('127.0.0.1', SERVER_PORT)) assert(socket:write 'first request line\n') assert('first response line' == assert(socket:read())) assert(socket:write 'second request line\n') assert('second response line' == assert(socket:read())) assert(socket:close()) end -- }}} main() -- vim: ts=2 sw=2 et tw=79 fen fdm=marker lua-apr-0.23.2.dfsg/test/proc.lua000066400000000000000000000066321220664456000165220ustar00rootroot00000000000000--[[ Unit tests for the process handling module of the Lua/APR binding. Author: Peter Odding Last Change: June 23, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local function newchild(cmdtype, script, env) local child = assert(apr.proc_create 'lua') assert(child:cmdtype_set(cmdtype)) if env then child:env_set(env) end assert(child:io_set('child-block', 'parent-block', 'parent-block')) assert(child:exec { helpers.scriptpath(script) }) return child, assert(child:in_get()), assert(child:out_get()), assert(child:err_get()) end -- Test bidirectional pipes. {{{1 local child, stdin, stdout, stderr = newchild('shellcmd/env', 'io_file-bidi_pipes.lua') local testmsg = "Is There Anyone Out There?!" assert(stdin:write(testmsg)); assert(stdin:close()) assert(stdout:read() == testmsg:lower()) assert(stderr:read() == testmsg:upper()) -- Test tostring(process). {{{1 assert(tostring(child):find '^process %([x%x]+%)$') -- Test child environment manipulation. {{{1 local child = newchild('shellcmd', 'test-child-env.lua', { LUA_APR_MAGIC_ENV_KEY = apr._VERSION, -- This is the only thing we're interested in testing… SystemRoot = apr.env_get 'SystemRoot', -- needed on Windows XP, without it code = -1072365564 below }) local done, why, code = assert(child:wait(true)) assert(done == true) assert(why == 'exit') -- TODO I thought I'd finally fixed the "incorrect subprocess return codes" -- problem but it's back; now it only triggers when I run the test suite -- under Lua/APR on Linux installed through LuaRocks :-\ -- assert(code == 42) -- Test apr.proc_fork() when supported. {{{1 if apr.proc_fork then local forked_file, forked_text = assert(helpers.tmpname()), 'hello from forked child!' local process, context = assert(apr.proc_fork()) if context == 'child' then helpers.writefile(forked_file, forked_text) os.exit(0) elseif context == 'parent' then assert(helpers.wait_for(forked_file, 10), "Forked child failed to create file?!") assert(helpers.readfile(forked_file) == forked_text) end end -- Test apr.namedpipe_create(). {{{1 local namedpipe = helpers.tmpname() local namedmsg = "Hello world over a named pipe!" local status, errmsg, errcode = apr.namedpipe_create(namedpipe) if errcode ~= 'ENOTIMPL' then local child = assert(apr.proc_create 'lua') assert(child:cmdtype_set('shellcmd/env')) assert(child:exec { helpers.scriptpath 'io_file-named_pipe.lua', namedpipe, namedmsg }) local handle = assert(apr.file_open(namedpipe, 'r')) assert(namedmsg == handle:read()) assert(handle:close()) end --[[ TODO Investigate escaping problem in apr_proc_create() ?! I originally used the following message above: local namedmsg = "Hello world over a named pipe! :-)" Which caused the following error message: /bin/sh: Syntax error: ")" unexpected Using strace as follows I can see the escaping is lost: $ strace -vfe trace=execve -s 250 lua etc/tests.lua [pid 30868] execve("/bin/sh", ["/bin/sh", "-c", "lua etc/test-namedpipe.lua /tmp/lua-apr-tempfile-66 Hello world over a named pipe! :-)"], [...]) = 0 After removing the smiley the syntax errors disappeared but the words in "namedmsg" are received as individual arguments by the test-namedpipe.lua script :-\ --]] lua-apr-0.23.2.dfsg/test/serialize.lua000066400000000000000000000071721220664456000175460ustar00rootroot00000000000000--[[ Tests for the serialization function of the Lua/APR binding. Author: Peter Odding Last Change: November 20, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT ]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end function main() -- Test single, scalar values. {{{1 assert(roundtrip(nil), "Failed to serialize nil value") assert(roundtrip(true), "Failed to serialize true value") assert(roundtrip(false), "Failed to serialize false value") assert(roundtrip(0), "Failed to serialize number value (0)") assert(roundtrip(1), "Failed to serialize number value (1)") assert(roundtrip(-1), "Failed to serialize number value (-1)") assert(roundtrip(math.pi), "Failed to serialize number value (math.pi)") assert(roundtrip(math.huge), "Failed to serialize number value (math.huge)") assert(roundtrip(''), "Failed to serialize empty string") assert(roundtrip('simple'), "Failed to serialize simple string ('simple')") assert(roundtrip('foo\nbar\rbaz\0qux'), "Failed to serialize complex string ('foo\\nbar\\rbaz\\0qux')") -- Test multiple scalar values (a tuple). {{{1 assert(roundtrip(true, false, nil, 13), "Failed to serialize tuple with nil value") -- Test tables (empty, list, dictionary, nested). {{{1 assert(roundtrip({}), "Failed to serialize empty table") assert(roundtrip({1, 2, 3, 4, 5}), "Failed to serialize list like table ({1, 2, 3, 4, 5})") assert(roundtrip({pi=math.pi}), "Failed to serialize table ({pi=3.14})") assert(roundtrip({nested={42}}), "Failed to serialize nested table ({nested={42}})") -- Test tables with cycles. {{{1 local a, b = {}, {}; a.b, b.a = b, a local chunk = apr.serialize(a, b) local a2, b2 = apr.unserialize(chunk) assert(a2.b == b2 and b2.a == a2) -- Test simple Lua function. {{{1 assert(roundtrip(function() return 42 end), "Failed to serialize simple function (return 42)") -- Test Lua function with scalar upvalue. {{{1 local simple_upvalue = 42 assert(roundtrip(function() return simple_upvalue end), "Failed to serialize function with scalar upvalue") -- Test Lua function with multiple upvalues. {{{1 local a, b, c, d = 1, 9, 8, 6 assert(roundtrip(function() return a, b, c, d end), "Failed to serialize function with multiple upvalues") -- Test Lua function with complex upvalues. {{{1 local nested = {1, 2, 3, 4, 5} local complex_upvalue = {pi=math.pi, string=name_of_upvalue, nested=nested} assert(roundtrip(function() return nested, complex_upvalue end), "Failed to serialize function with complex upvalues") -- Test Lua/APR userdata. {{{1 local object = apr.pipe_open_stdin() local data = apr.serialize(object) local result = apr.unserialize(data) assert(object == result, "Failed to preserve userdata identity!") end function pack(...) return { n = select('#', ...), ... } end function roundtrip(...) return deepequals(pack(...), pack(apr.unserialize(apr.serialize(...)))) end function deepequals(a, b) if a == b then return true end local at, bt = type(a), type(b) if at ~= bt then return false end if at == 'function' then -- Compare functions based on return values. return deepequals(pack(a()), pack(b())) end if at ~= 'table' then -- Everything except functions and tables can be compared literally. return a == b end -- Compare the two tables by iterating the keys of both tables. for k, v in pairs(a) do if not deepequals(v, b[k]) then return false end end for k, v in pairs(b) do if not deepequals(v, a[k]) then return false end end return true end main() lua-apr-0.23.2.dfsg/test/shm-child.lua000066400000000000000000000011041220664456000174140ustar00rootroot00000000000000local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local shm_file = assert(apr.shm_attach(arg[1])) local tmp_file = assert(io.open(arg[2])) assert(shm_file:write(tmp_file:read('*a'))) -- You don't actually have to call this, I'm -- just testing that it works as advertised :-) assert(shm_file:detach()) -- Check that removing works on supported platforms. local status, errmsg, errcode = apr.shm_remove(arg[1]) if errcode ~= 'EACCES' then assert(status, errmsg) assert(not apr.shm_attach(arg[1])) end lua-apr-0.23.2.dfsg/test/shm.lua000066400000000000000000000023741220664456000163450ustar00rootroot00000000000000--[[ Unit tests for the shared memory module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local testdata = [[ 1 3.1 100 0xCAFEBABE 0xDEADBEEF 3.141592653589793115997963468544185161590576171875 this line is in fact not a number :-) that was an empty line]] -- Write test data to file. local tmp_path = helpers.tmpname() helpers.writefile(tmp_path, testdata) -- Create shared memory segment. local shm_path = assert(helpers.tmpname()) local shm_file = assert(apr.shm_create(shm_path, #testdata)) assert(tostring(shm_file):find '^shared memory %([0x%x]+%)$') -- Launch child process. local child = assert(apr.proc_create('lua')) assert(child:cmdtype_set 'shellcmd/env') assert(child:exec { helpers.scriptpath 'shm-child.lua', shm_path, tmp_path }) assert(child:wait(true)) -- Execute buffered I/O tests. local test_buffer = require(((...):gsub('shm$', 'io_buffer'))) test_buffer(tmp_path, shm_file) -- Destroy the shared memory segment. assert(shm_file:destroy()) lua-apr-0.23.2.dfsg/test/signal.lua000066400000000000000000000054241220664456000170320ustar00rootroot00000000000000--[[ Unit tests for the signal handling module of the Lua/APR binding. Author: Peter Odding Last Change: July 3, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT I wanted to write this test as follows: Start a child process that listens for SIGKILL and/or SIGQUIT, kill the child process using process:kill() and check that the child process received the signals. Unfortunately it doesn't... The only other useful way I could think of to test that signals work is what I've now implemented in this test: Listen for SIGCHLD, start and then kill a child process and check that the parent process received SIGCHLD. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- The ISO C standard only requires the signal names SIGABRT, SIGFPE, SIGILL, -- SIGINT, SIGSEGV, and SIGTERM to be defined (and these are in fact the only -- signal names defined on Windows). local names = apr.signal_names() assert(names.SIGABRT) assert(names.SIGFPE) assert(names.SIGILL) assert(names.SIGINT) assert(names.SIGSEGV) assert(names.SIGTERM) -- apr.signal() tests using apr.signal_raise(). {{{1 local got_sigabrt = false apr.signal('SIGABRT', function() got_sigabrt = true end) assert(apr.signal_raise 'SIGABRT') assert(got_sigabrt) local got_sigterm = false apr.signal('SIGTERM', function() got_sigterm = true end) assert(apr.signal_raise 'SIGTERM') assert(got_sigterm) -- apr.signal() tests using real signals. {{{1 if apr.platform_get() ~= 'WIN32' then -- Spawn a child process that dies. local function spawn() local child = assert(apr.proc_create 'lua') assert(child:cmdtype_set 'program/env/path') assert(child:exec { '-e', 'os.exit(0)' }) assert(child:wait(true)) end -- Use apr.signal() to listen for dying child processes. local got_sigchild = false apr.signal('SIGCHLD', function() got_sigchild = true end) -- Create and kill a child process. spawn() -- Make sure we got the signal. assert(got_sigchild) -- Test that apr.signal_block() blocks the signal. got_sigchild = false assert(apr.signal_block 'SIGCHLD') -- Create and kill a child process. spawn() -- Make sure we didn't get the signal. assert(not got_sigchild) -- Test that apr.signal_unblock() unblocks the signal. assert(apr.signal_unblock 'SIGCHLD') -- Create and kill a child process. spawn() -- Make sure we got the signal. assert(got_sigchild) -- Test that signal handlers can be disabled. apr.signal('SIGCHLD', nil) got_sigchild = false -- Create and then kill a child process. spawn() -- Make sure the old signal handler was not executed. assert(not got_sigchild) end lua-apr-0.23.2.dfsg/test/str.lua000066400000000000000000000024601220664456000163620ustar00rootroot00000000000000--[[ Unit tests for the string routines module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Test natural comparison. local filenames = { 'rfc2086.txt', 'rfc1.txt', 'rfc822.txt' } table.sort(filenames, apr.strnatcmp) assert(filenames[1] == 'rfc1.txt') assert(filenames[2] == 'rfc822.txt') assert(filenames[3] == 'rfc2086.txt') -- Test case insensitive natural comparison. local filenames = { 'RFC2086.txt', 'RFC1.txt', 'rfc822.txt' } table.sort(filenames, apr.strnatcasecmp) assert(filenames[1] == 'RFC1.txt') assert(filenames[2] == 'rfc822.txt') assert(filenames[3] == 'RFC2086.txt') -- Test binary size formatting. assert(apr.strfsize(1024^1) == '1.0K') assert(apr.strfsize(1024^2) == '1.0M') assert(apr.strfsize(1024^3) == '1.0G') -- Test command line tokenization. local command = [[ program argument1 "argument 2" 'argument 3' argument\ 4 ]] local cmdline = assert(apr.tokenize_to_argv(command)) assert(cmdline[1] == 'program') assert(cmdline[2] == 'argument1') assert(cmdline[3] == 'argument 2') assert(cmdline[4] == 'argument 3') assert(cmdline[5] == 'argument 4') lua-apr-0.23.2.dfsg/test/thread-child.lua000066400000000000000000000041301220664456000200760ustar00rootroot00000000000000--[[ Unit tests for the multi threading module of the Lua/APR binding. Author: Peter Odding Last Change: November 20, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script is executed as a child process by thread.lua. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Check that yield() exists, can be called and does mostly nothing :-) assert(select('#', apr.thread_yield()) == 0) -- Test thread creation. local threadfile = helpers.tmpname() local thread = assert(apr.thread(function() local handle = assert(io.open(threadfile, 'w')) assert(handle:write 'hello world!') assert(handle:close()) end)) assert(thread:join()) -- Check that the file was actually created inside the thread. assert(helpers.readfile(threadfile) == 'hello world!') -- Test that package.config, package.path and package.cpath are preserved. local config, path, cpath = package.config, package.path, package.cpath local thread = assert(apr.thread(function() assert(package.config == config, "apr.thread() failed to preserve package.config") assert(package.path == path, "apr.thread() failed to preserve package.path") assert(package.cpath == cpath, "apr.thread() failed to preserve package.cpath") end)) assert(thread:join()) -- Test module loading and multiple return values. local thread = assert(apr.thread(function() local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end return apr.version_get().apr end)) helpers.checktuple({ true, apr.version_get().apr }, assert(thread:join())) -- Test thread:status() local thread = assert(apr.thread(function() local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end apr.sleep(1) end)) while assert(thread:status()) == 'init' do apr.sleep(0.1) end assert('running' == assert(thread:status())) assert(thread:join()) assert('done' == assert(thread:status())) lua-apr-0.23.2.dfsg/test/thread.lua000066400000000000000000000015331220664456000170210ustar00rootroot00000000000000--[[ Unit tests for the multi threading module of the Lua/APR binding. Author: Peter Odding Last Change: November 20, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script runs the multi threading tests in a child process to protect the test suite from crashing on unsupported platforms. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' if not apr.thread then helpers.warning "Multi threading module not available!\n" return false end local child = assert(apr.proc_create 'lua') assert(child:cmdtype_set 'shellcmd/env') assert(child:exec { helpers.scriptpath 'thread-child.lua' }) local dead, reason, code = assert(child:wait(true)) return reason == 'exit' and code == 0 lua-apr-0.23.2.dfsg/test/thread_queue-child.lua000066400000000000000000000050561220664456000213120ustar00rootroot00000000000000--[[ Unit tests for the thread queues module of the Lua/APR binding. Author: Peter Odding Last Change: November 20, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script is executed as a child process by thread_queue.lua. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Create a thread queue with space for one tuple. local queue = assert(apr.thread_queue(1)) -- Test that the queue starts empty. assert(not queue:trypop()) -- Pass the thread queue to a thread. local thread = assert(apr.thread(function() local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' helpers.try(function() -- Scalar values. assert(queue:push(nil)) assert(queue:push(false)) assert(queue:push(true)) assert(queue:push(42)) assert(queue:push(math.pi)) assert(queue:push "hello world through a queue!") -- Tuples. assert(queue:push(true, false, 13, math.huge, _VERSION)) -- Object values. assert(queue:push(queue)) assert(queue:push(apr.pipe_open_stdin())) assert(queue:push(apr.socket_create())) end, function(errmsg) helpers.message("Thread queue tests failed in child thread: %s\n", errmsg) assert(queue:terminate()) end) end)) helpers.try(function() -- Check the sequence of supported value types. assert(queue:pop() == nil) assert(queue:pop() == false) assert(queue:pop() == true) assert(queue:pop() == 42) assert(queue:pop() == math.pi) assert(queue:pop() == "hello world through a queue!") -- Check that multiple values are supported. local expected = { true, false, 13, math.huge, _VERSION } helpers.checktuple(expected, assert(queue:pop())) -- These test that Lua/APR objects can be passed between threads and that -- objects which are really references __equal the object they reference. assert(assert(queue:pop()) == queue) assert(apr.type(queue:pop()) == 'file') assert(apr.type(queue:pop()) == 'socket') -- Now make sure the queue is empty again. assert(not queue:trypop()) -- Make sure trypush() works as expected. assert(queue:push(1)) -- the thread queue is now full assert(not queue:trypush(2)) -- thus trypush() should fail assert(thread:join()) end, function(errmsg) helpers.message("Thread queue tests failed in parent thread: %s\n", errmsg) assert(queue:terminate()) os.exit(1) end) lua-apr-0.23.2.dfsg/test/thread_queue.lua000066400000000000000000000015331220664456000202250ustar00rootroot00000000000000--[[ Unit tests for the thread queues module of the Lua/APR binding. Author: Peter Odding Last Change: May 15, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT This script runs the thread queue tests in a child process to protect the test suite from crashing on unsupported platforms. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' if not apr.thread_queue then helpers.warning "Thread queues module not available!\n" return false end local child = assert(apr.proc_create 'lua') assert(child:cmdtype_set 'shellcmd/env') assert(child:exec { helpers.scriptpath 'thread_queue-child.lua' }) local dead, reason, code = assert(child:wait(true)) return reason == 'exit' and code == 0 lua-apr-0.23.2.dfsg/test/time.lua000066400000000000000000000032441220664456000165110ustar00rootroot00000000000000--[[ Unit tests for the time routines module of the Lua/APR binding. Author: Peter Odding Last Change: June 16, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Based on http://svn.apache.org/viewvc/apr/apr/trunk/test/testtime.c?view=markup. local now = 1032030336186711 / 1000000 -- Check that apr.time_now() more or less matches os.time() assert(math.abs(os.time() - apr.time_now()) <= 2) -- apr.time_explode() using apr_time_exp_lt() local posix_exp = os.date('*t', now) local xt = assert(apr.time_explode(now)) -- apr_time_exp_lt() for k, v in pairs(posix_exp) do assert(v == xt[k]) end -- apr.time_implode() on a local time table (ignores floating point precision -- because on my laptop "now" equals 1032030336.186711 while "imp" equals -- 1032037536.186710) local imp = assert(apr.time_implode(xt)) -- apr_time_exp_gmt_get() assert(math.floor(now) == math.floor(imp)) -- apr.time_implode() on a GMT time table local xt = assert(apr.time_explode(now, true)) -- apr_time_exp_gmt() local imp = assert(apr.time_implode(xt)) -- apr_time_exp_gmt_get() assert(math.floor(now) == math.floor(imp)) -- Test apr.time_format() (example from http://en.wikipedia.org/wiki/Unix_time) assert(apr.time_format('rfc822', 1000000000) == 'Sun, 09 Sep 2001 01:46:40 GMT') assert(apr.time_format('%Y-%m', 1000000000) == '2001-09') -- Test that apr.sleep() supports sub second resolution. local before = apr.time_now() apr.sleep(0.25) local after = apr.time_now() assert(string.format('%.1f', after - before):find '^0%.[123]$') lua-apr-0.23.2.dfsg/test/uri.lua000066400000000000000000000024611220664456000163520ustar00rootroot00000000000000--[[ Unit tests for the URI parsing module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local hostinfo = 'scheme://user:pass@host:80' local pathinfo = '/path/file?query-param=value#fragment' local input = hostinfo .. pathinfo -- Parse a URL into a table of components. local parsed = assert(apr.uri_parse(input)) -- Validate the parsed URL fields. assert(parsed.scheme == 'scheme') assert(parsed.user == 'user') assert(parsed.password == 'pass') assert(parsed.hostname == 'host') assert(parsed.port == '80') assert(parsed.hostinfo == 'user:pass@host:80') assert(parsed.path == '/path/file') assert(parsed.query == 'query-param=value') assert(parsed.fragment == 'fragment') -- Check that complete and partial URL `unparsing' works. assert(apr.uri_unparse(parsed) == input) assert(apr.uri_unparse(parsed, 'hostinfo') == hostinfo) assert(apr.uri_unparse(parsed, 'pathinfo') == pathinfo) -- Make sure uri_port_of_scheme() works. assert(apr.uri_port_of_scheme 'ssh' == 22) assert(apr.uri_port_of_scheme 'http' == 80) assert(apr.uri_port_of_scheme 'https' == 443) lua-apr-0.23.2.dfsg/test/user.lua000066400000000000000000000031661220664456000165340ustar00rootroot00000000000000--[[ Unit tests for the user/group identification module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT Note that these tests don't assert() on anything useful because that would make it impossible to run the Lua/APR test suite in "chrooted" build environments and such.. --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' -- Get the name and primary group of the current user. local apr_user, apr_group = assert(apr.user_get()) assert(type(apr_user) == 'string' and apr_user ~= '') assert(type(apr_group) == 'string' and apr_group ~= '') local function report(...) helpers.warning(...) helpers.message("This might not be an error, e.g. when using a chroot, which is why the tests will continue as normal.\n") end -- Try to match the result of apr.user_get() against $USER. local env_user = apr.env_get 'USER' or apr.env_get 'USERNAME' or '' if apr_user ~= env_user then report("$USER == %q but apr.user_get() == %q\n", env_user, apr_user) return false end -- Try to match the result of apr.user_homepath_get() against $HOME. local function normpath(p) return assert(apr.filepath_merge('', p, 'native')) end local env_home = normpath(apr.env_get 'HOME' or apr.env_get 'USERPROFILE' or '') local apr_home = normpath(assert(apr.user_homepath_get(apr_user))) if apr_home ~= env_home then report("$HOME == %q but apr.user_homepath_get(%q) == %q\n", env_home, apr_user, apr_home) return false end lua-apr-0.23.2.dfsg/test/uuid.lua000066400000000000000000000022421220664456000165160ustar00rootroot00000000000000--[[ Unit tests for the universally unique identifiers module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end -- Check that apr.uuid_get() returns at least 500 KB of unique strings. local set = {} assert(pcall(function() for i = 1, 32000 do uuid = assert(apr.uuid_get()) assert(not set[uuid], 'duplicate UUID!') set[uuid] = true end end)) -- I can't find any binary/formatted example UUIDs on the internet and don't -- really know how to make the following tests useful. At least they illustrate -- the purpose… -- Check that apr.uuid_format() works. assert(apr.uuid_format(('\0'):rep(16)) == '00000000-0000-0000-0000-000000000000') assert(apr.uuid_format(('\255'):rep(16)) == 'ffffffff-ffff-ffff-ffff-ffffffffffff') -- Check that apr.uuid_parse() works. assert(apr.uuid_parse '00000000-0000-0000-0000-000000000000' == ('\0'):rep(16)) assert(apr.uuid_parse 'ffffffff-ffff-ffff-ffff-ffffffffffff' == ('\255'):rep(16)) lua-apr-0.23.2.dfsg/test/xlate.lua000066400000000000000000000022121220664456000166620ustar00rootroot00000000000000--[[ Unit tests for the character encoding translation module of the Lua/APR binding. Author: Peter Odding Last Change: July 3, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local utf8 = "Edelwei\195\159" local utf7 = "Edelwei+AN8-" local latin1 = "Edelwei\223" local latin2 = "Edelwei\223" -- 1. Identity transformation: UTF-8 -> UTF-8 assert(utf8 == assert(apr.xlate(utf8, 'UTF-8', 'UTF-8'))) -- 2. UTF-8 <-> ISO-8859-1 assert(latin1 == assert(apr.xlate(utf8, 'UTF-8', 'ISO-8859-1'), "(known to fail on Windows)")) assert(utf8 == assert(apr.xlate(latin1, 'ISO-8859-1', 'UTF-8'))) -- 3. ISO-8859-1 <-> ISO-8859-2, identity assert(latin2 == assert(apr.xlate(latin1, 'ISO-8859-1', 'ISO-8859-2'))) assert(latin1 == assert(apr.xlate(latin2, 'ISO-8859-2', 'ISO-8859-1'))) -- 4. Transformation using character set aliases assert(utf7 == assert(apr.xlate(utf8, 'UTF-8', 'UTF-7'))) assert(utf8 == assert(apr.xlate(utf7, 'UTF-7', 'UTF-8'))) lua-apr-0.23.2.dfsg/test/xml.lua000066400000000000000000000037221220664456000163540ustar00rootroot00000000000000--[[ Unit tests for the XML parsing module of the Lua/APR binding. Author: Peter Odding Last Change: March 27, 2011 Homepage: http://peterodding.com/code/lua/apr/ License: MIT --]] local status, apr = pcall(require, 'apr') if not status then pcall(require, 'luarocks.require') apr = require 'apr' end local helpers = require 'apr.test.helpers' local function parse_xml(text) local parser = assert(apr.xml()) assert(parser:feed(text)) assert(parser:done()) local info = assert(parser:getinfo()) assert(parser:close()) return info end -- Empty root element. assert(helpers.deepequal(parse_xml '', { tag = 'elem' })) -- Element with a single attribute. assert(helpers.deepequal(parse_xml '', { tag = 'elem', attr = { 'name', name = 'value' } })) -- Element with multiple attributes. assert(helpers.deepequal(parse_xml '', { tag = 'elem', attr = { 'name', 'a2', 'a3', name = 'value', a2 = '2', a3 = '3' }})) -- Element with text child node. assert(helpers.deepequal(parse_xml 'text', { tag = 'elem', 'text' })) -- Element with child element. assert(helpers.deepequal(parse_xml '', { tag = 'elem', { tag = 'child' } })) -- Element with child element that contains a text node. assert(helpers.deepequal(parse_xml 'text', { tag = 'parent', { tag = 'child', 'text' } })) -- Create a temporary XML file to test the alternative constructor. local xml_path = helpers.tmpname() helpers.writefile(xml_path, 'text') local parser = assert(apr.xml(xml_path)) assert(helpers.deepequal(parser:getinfo(), { tag = 'parent', { tag = 'child', 'text' } })) -- Check that tostring(apr.xml()) works as expected. local parser = assert(apr.xml()) assert(tostring(parser):find '^xml parser %([x%x]+%)$') assert(parser:close()) assert(tostring(parser):find '^xml parser %(closed%)$')