Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1,8 @@
root = true
[*]
indent_style = tab
indent_size = 4
tab_width = 4
trim_trailing_whitespace = true
insert_final_newline = true

View file

@ -0,0 +1,18 @@
---
name: Ask a question
about: Ask a general Premake-related question to the community
title: ''
labels: question
assignees: ''
---
_Before asking a new question, please [use the issue search feature](https://github.com/premake/premake-core/issues) to see if your question has already been asked. Help us help you!_
**What's your question?**
A short, concise question for the community. To get the best answers, be clear about what you're asking, what kind of responses you hope to receive, and how you intend to use the information.
**Anything else we should know?**
Add any other background or context about your question here.
*(You can now [support Premake on our OpenCollective](https://opencollective.com/premake). Your contributions help us spend more time responding to questions like these!)*

View file

@ -0,0 +1,27 @@
---
name: Get help
about: Get help using Premake and its scripting features
title: ''
labels: support-request
assignees: ''
---
_Before opening a new issue, please [use the issue search feature](https://github.com/premake/premake-core/issues) to see if a similar issue already exists. If not, please help us help you by filling in the template below._
**What are you trying to do?**
A short, concise description of the outcome you are trying to achieve, ex. "Add build settings to a specific file".
**What problem are you having?**
A clear and concise description of the problem that is blocking you from your desired outcome, ex. "Premake is crashing with this error message: ..." or "I don't know how to do it."
**What have you tried so far?**
Describe any steps you've already taken to try to get past this issue.
**What version of Premake are you using?**
`premake5 --version` will show you the version. If you are running a "-dev" version, please make sure you are up to date with the latest master branch.
**Anything else we should know?**
Add any other context about the problem here.
*(You can now [support Premake on our OpenCollective](https://opencollective.com/premake). Your contributions help us spend more time responding to issues like these!)*

View file

@ -0,0 +1,30 @@
---
name: Report a bug
about: Something need fixing or improvement? Let us know!
title: ''
labels: bug
assignees: ''
---
_Before opening a new bug report, please read [Reporting Bugs](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md#reporting-bugs) and consider if this is something [you can contribute](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md#contributing-a-fix-or-feature) yourself. If this a new bug, help us help you by filling in the template below._
**What seems to be the problem?**
A clear and concise description of the bug, ex. "It crashes when I try to run it" or "There doesn't seem to be any way to do ...". If you are reporting a crash, be sure to include any error messages and stack trace information. Use [code blocks](https://help.github.com/en/articles/creating-and-highlighting-code-blocks) to format code and console output nicely.
**What did you expect to happen?**
A clear and concise description of what you expected to happen.
**What have you tried so far?**
Describe any steps you've taken to try to solve or workaround the bug.
**How can we reproduce this?**
Please provide a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) we can use to replicate the problem in our own development environments. Use [code blocks](https://help.github.com/en/articles/creating-and-highlighting-code-blocks) to format code and console output nicely.
**What version of Premake are you using?**
`premake5 --version` will show you the version. If you are running a "-dev" version, please make sure you are up to date with the latest master branch.
**Anything else we should know?**
Add any other context about the problem here.
*(You can now [support Premake on our OpenCollective](https://opencollective.com/premake). Your contributions help us spend more time responding to issues like these!)*

View file

@ -0,0 +1,24 @@
---
name: Request a feature
about: Suggest a new feature or enhancement
title: ''
labels: enhancement
assignees: ''
---
_Before opening a new feature request, please read [Requesting New Features](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md#requesting-new-features) and consider if this is something [you can contribute](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md#contributing-a-fix-or-feature) yourself. If this a new request, help us help you by filling in the template below._
**What problem will this solve?**
A clear and concise description of the problem this new feature is meant to solve, ex. "I'm always frustrated when [...]" or "Add support for this new toolset [...]". Please limit your request to a single feature; create multiple feature requests instead.
**What might be a solution?**
A clear and concise description of what you want to happen. If you are proposing changes to Premake's scripting APIs, provide an example of how your new feature might look when scripted. Use [code blocks](https://help.github.com/en/articles/creating-and-highlighting-code-blocks) to format your examples nicely.
**What other alternatives have you already considered?**
A clear and concise description of any alternative solutions or features you've considered.
**Anything else we should know?**
Add any other context or screenshots about the feature request here.
*(You can now [support Premake on our OpenCollective](https://opencollective.com/premake). Your contributions help us spend more time responding to requests like these!)*

View file

@ -0,0 +1,22 @@
**What does this PR do?**
Thanks for the contribution! Please provide a concise description of the problem this request solves.
**How does this PR change Premake's behavior?**
Are there any breaking changes? Will any existing behavior change?
**Anything else we should know?**
Add any other context about your changes here.
**Did you check all the boxes?**
- [ ] Focus on a single fix or feature; remove any unrelated formatting or code changes
- [ ] Add unit tests showing fix or feature works; all tests pass
- [ ] Mention any [related issues](https://github.com/premake/premake-core/issues) (put `closes #XXXX` in comment to auto-close issue when PR is merged)
- [ ] Follow our [coding conventions](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md#coding-conventions)
- [ ] Minimize the number of commits
- [ ] Align [documentation](https://github.com/premake/premake-core/tree/master/website) to your changes
*You can now [support Premake on our OpenCollective](https://opencollective.com/premake). Your contributions help us spend more time responding to requests like these!*

View file

@ -0,0 +1,73 @@
name: CI Workflow
on: [push, pull_request]
jobs:
linux:
runs-on: ubuntu-latest
strategy:
matrix:
config: [debug, release]
platform: [x64]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: make -f Bootstrap.mak linux PLATFORM=${{ matrix.platform }} CONFIG=${{ matrix.config }}
- name: Test
run: bin/${{ matrix.config }}/premake5 test --test-all
- name: Docs check
run: bin/${{ matrix.config }}/premake5 docs-check
- name: Upload Artifacts
if: matrix.config == 'release'
uses: actions/upload-artifact@v2
with:
name: premake-linux-${{ matrix.platform }}
path: bin/${{ matrix.config }}/
macosx:
runs-on: macos-latest
strategy:
matrix:
config: [debug, release]
platform: [x64]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: make -f Bootstrap.mak macosx PLATFORM=${{ matrix.platform }} CONFIG=${{ matrix.config }}
- name: Test
run: bin/${{ matrix.config }}/premake5 test --test-all
- name: Docs check
run: bin/${{ matrix.config }}/premake5 docs-check
- name: Upload Artifacts
if: matrix.config == 'release'
uses: actions/upload-artifact@v2
with:
name: premake-macosx-${{ matrix.platform }}
path: bin/${{ matrix.config }}/
windows:
runs-on: windows-latest
strategy:
matrix:
config: [debug, release]
platform: [Win32, x64]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64
nmake -f Bootstrap.mak MSDEV=vs2019 windows-msbuild PLATFORM=${{ matrix.platform }} CONFIG=${{ matrix.config }}
shell: cmd
- name: Test
run: bin\${{ matrix.config }}\premake5 test --test-all
shell: cmd
- name: Docs check
run: bin\${{ matrix.config }}\premake5 docs-check
shell: cmd
- name: Upload Artifacts
if: matrix.config == 'release'
uses: actions/upload-artifact@v2
with:
name: premake-windows-${{ matrix.platform }}
path: bin\${{ matrix.config }}\

View file

@ -0,0 +1,55 @@
name: Website
on:
push:
paths: ['website/**']
pull_request:
paths: ['website/**']
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Test Build
run: |
cd website
npm install
npm run build
publish:
if: github.repository_owner == 'premake' && github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Add key to allow access to repository
env:
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
run: |
mkdir -p ~/.ssh
ssh-keyscan github.com >> ~/.ssh/known_hosts
echo "${{ secrets.WEBSITE_DEPLOY_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
cat <<EOT >> ~/.ssh/config
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_rsa
EOT
- name: Release to premake.github.io
env:
USE_SSH: true
GIT_USER: git
DEPLOYMENT_BRANCH: master
run: |
git config --global user.email "actions@gihub.com"
git config --global user.name "gh-actions"
cd website
npm install
npx docusaurus deploy

View file

@ -0,0 +1,44 @@
syntax: glob
.DS_Store
*.bak
*.orig
*~
build
bin
obj
release
ipch
src/scripts.c
**.lnt
**.vlstatus
Makefile
*.make
*.xcodeproj
*.xcworkspace
*.swp
*.sdf
*.sln
*.suo
*.ncb
*.vcproj*
*.vcxproj*
*.VC.opendb
*.VC.db
*.opensdf
*.workspace
*.project
*.tags
*.sublime-*
.cproject
.settings
.buildpath
*.bbprojectsettings
Scratchpad.txt
Unix Worksheet.worksheet
project.bbprojectdata
Premake4.tmproj

View file

@ -0,0 +1,101 @@
PREMAKE BUILD INSTRUCTIONS
Premake is written in a mix of C and Lua. A small host executable,
written in C, launches the app and prepares the environment, at which
point control is handed off to a Lua script. Almost all of Premake is
written in Lua scripts, which allow it to be easily extended and
customized. The catch is that it is slightly more complicated to build
it than your typical C/C++ application.
If you find all of this very confusing and need some help, visit the
Premake website for help and community links. We will be glad to help!
BUILDING FROM A SOURCE PACKAGE
If you downloaded a source code package (as opposed to pulling the sources
directory from the repository) you will find project files for all of the
officially supported toolsets in the build/ folder. Build the release
configuration and you will be ready to go. For makefiles:
$ cd build/gmake2.unix
$ make config=release
The binaries will be placed in the ./bin/release directory.
BUILDING FROM THE REPOSITORY
If you have pulled sources from the Premake source repository, you can
use `Bootstrap.mak` to generate your first premake executable:
$ make -f Bootstrap.mak PLATFORM
Where PLATFORM can be osx or linux.
On Windows with Visual Studio use nmake:
$ nmake -f Bootstrap.mak windows
Or on Windows with MinGW use mingw32-make:
$ CC=mingw32-gcc mingw32-make -f Bootstrap.mak mingw
If your toolset is not supported by the bootstrap Makefile, you will need
to embed the scripts into a C source file so they may be built into the
executable, and also generate the project files for your chosen toolset. In
order do either of these things, you will need a working Premake executable.
The easiest way to get an executable is to download one of the prebuilt
binaries from the project website. If that isn't possible, or if not binary
is provided for your platform, you can build from a source package as
described above, as they also include pre-generated project files.
Once you have a working Premake available, you can generate the project
files for your toolset by running a command like the following in the
top-level Premake directory:
$ premake5 gmake2 # for makefiles
$ premake5 vs2012 # for a Visual Studio 2012 solution
$ premake --help # to see a list of supported toolsets
If this is the first time you have built Premake, or if you have made
changes to the Lua scripts, you should prepare them to be embedded into the
Premake executable.
$ premake5 embed
This creates a C file (at src/host/scripts.c) which contains all of the
Lua scripts as static string buffers. These then get compiled into the
executable, which is how we get away with shipping a single file instead
of a whole bunch of scripts.
You should now have a solution/makefile/workspace in the top-level folder,
which you can go ahead and build.
RUNNING THE TESTS
Once you have built an executable, you can verify it by running Premake's
unit test suites. From the top-level Premake folder, run:
$ bin/release/premake5 test
RUNTIME SCRIPT LOADING
If you are modifying or extending Premake, you can skip the embedding
and compilation steps and run the scripts directly from the disk. This
removes the build from the change-build-test cycle and really speeds up
development.
If you are running Premake from the top of its own source tree (where its
premake5.lua is located) you will get this behavior automatically. If you
are running Premake from some other location, use the --scripts option to
provide the path to that top-level folder:
$ bin/release/premake5 --scripts=../path/to/premake test
If you find yourself doing this repeatedly, or if you want Premake to be
able to find other, custom scripts, you can also set a search path with the
PREMAKE_PATH environment variable. Set it just like you would set your
system PATH variable.

View file

@ -0,0 +1,165 @@
@ECHO OFF
SETLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
REM ===========================================================================
SET SelfPath="%0"
SET VsWherePath="C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe"
REM ===========================================================================
SET vsversion=%1
IF "%vsversion%" == "" (
CALL :BootstrapLatest
EXIT /B %ERRORLEVEL%
)
IF "%vsversion%" == "vs2010" (
CALL :LegacyVisualBootstrap "%vsversion%" "100"
) ELSE IF "%vsversion%" == "vs2012" (
CALL :LegacyVisualBootstrap "%vsversion%" "110"
) ELSE IF "%vsversion%" == "vs2013" (
CALL :LegacyVisualBootstrap "%vsversion%" "120"
) ELSE IF "%vsversion%" == "vs2015" (
CALL :LegacyVisualBootstrap "%vsversion%" "140"
) ELSE IF "%vsversion%" == "vs2017" (
CALL :VsWhereVisualBootstrap "%vsversion%" "15.0" "16.0"
) ELSE IF "%vsversion%" == "vs2019" (
CALL :VsWhereVisualBootstrap "%vsversion%" "16.0" "17.0"
) ELSE IF "%vsversion%" == "vs2022" (
CALL :VsWhereVisualBootstrap "%vsversion%" "17.0" "18.0"
) ELSE (
ECHO Unrecognized Visual Studio version %vsversion%
EXIT /B 2
)
REM On error, pause to allow user to notice it if script was launched through explorer
IF %ERRORLEVEL% NEQ 0 (
PAUSE
)
EXIT /B %ERRORLEVEL%
REM ===========================================================================
REM Utils
REM ===========================================================================
REM %1: PremakeVsVersion -> ex: vs2015
REM %2: VsVersion envvar -> ex: 140
:LegacyVisualBootstrap
SET "VsVersion_NoPoint=%~2"
SET "VsEnvVar=VS%VsVersion_NoPoint%COMNTOOLS"
SET "VsPath=!%VsEnvVar%!"
IF NOT EXIST "%VsPath%vsdevcmd.bat" (
ECHO Could not find vsdevcmd.bat to setup Visual Studio environment
EXIT /B 2
)
CALL "%VsPath%vsdevcmd.bat" && nmake MSDEV="%~1" -f Bootstrap.mak windows
EXIT /B %ERRORLEVEL%
REM :LegacyVisualBootstrap
REM ===========================================================================
REM %1: PremakeVsVersion -> ex: vs2010
REM %2: VisualStudio-style VSversionMin -> ex: 15.0
REM %3: VisualStudio-style VSversionMax -> ex: 16.0
:VsWhereVisualBootstrap
SET "PremakeVsVersion=%~1"
SET "VsVersionMin=%~2"
SET "VsVersionMax=%~3"
REM ref: https://github.com/Microsoft/vswhere/wiki/Start-Developer-Command-Prompt
IF NOT EXIST %VsWherePath% (
ECHO Could not find vswhere.exe
EXIT /B 2
)
SET VsWhereCmdLine="!VsWherePath! -nologo -latest -version [%VsVersionMin%,%VsVersionMax%) -property installationPath"
FOR /F "usebackq delims=" %%i in (`!VsWhereCmdLine!`) DO (
IF EXIST "%%i\VC\Auxiliary\Build\vcvars32.bat" (
CALL "%%i\VC\Auxiliary\Build\vcvars32.bat" && nmake MSDEV="%PremakeVsVersion%" -f Bootstrap.mak windows
EXIT /B %ERRORLEVEL%
)
)
ECHO Could not find vcvars32.bat to setup Visual Studio environment
EXIT /B 2
REM :VsWhereVisualBootstrap
REM ===========================================================================
:BootstrapLatest
IF EXIST %VsWherePath% (
REM First try for not legacy Visual Studios ( >vs2017 )
SET VsWhereCmdLine="!VsWherePath! -nologo -latest -property catalog.productLineVersion"
FOR /F "usebackq delims=" %%i in (`!VsWhereCmdLine!`) DO (
CALL %SelfPath% vs%%i
EXIT /B %ERRORLEVEL%
)
)
SET LegacyVSVersions=
REM Get latest Visual Studio legacy version
REM For all env var starting with VS
FOR /F "usebackq delims==" %%i in (`SET VS`) DO (
REM Check if env var match pattern VS*COMNTOOLS (ie: VS140COMNTOOLS)
ECHO "%%i" | FINDSTR /R /C:VS.*COMNTOOLS >nul && (
SET "LegacyVSVersions=%%i"
)
)
REM Strip VS
SET LegacyVSVersions=%LegacyVSVersions:VS=%
REM Strip COMNTOOLS
SET LegacyVSVersions=%LegacyVSVersions:COMNTOOLS=%
SET "VsVersionMap=140-vs2015;120-vs2013;110-vs2012;100-vs2010"
CALL SET PremakeVsVersion=%%VsVersionMap:*%LegacyVSVersions%-=%%
SET PremakeVsVersion=%PremakeVsVersion:;=&REM.%
IF NOT "%PremakeVsVersion%" == "" (
CALL %SelfPath% %PremakeVsVersion%
EXIT /B %ERRORLEVEL%
)
ECHO Could not find a Visual Studio installation
EXIT /B 2
REM :BootstrapLatest
REM ===========================================================================
REM SETLOCAL ENABLEDELAYEDEXPANSION
ENDLOCAL
REM SETLOCAL
ENDLOCAL

View file

@ -0,0 +1,153 @@
MSDEV = vs2012
CONFIG = release
PLATFORM = x86
LUA_DIR = contrib/lua/src
LUASHIM_DIR = contrib/luashim
SRC = src/host/*.c \
$(LUA_DIR)/lapi.c \
$(LUA_DIR)/lbaselib.c \
$(LUA_DIR)/lbitlib.c \
$(LUA_DIR)/lcode.c \
$(LUA_DIR)/lcorolib.c \
$(LUA_DIR)/lctype.c \
$(LUA_DIR)/ldblib.c \
$(LUA_DIR)/ldebug.c \
$(LUA_DIR)/ldo.c \
$(LUA_DIR)/ldump.c \
$(LUA_DIR)/lfunc.c \
$(LUA_DIR)/lgc.c \
$(LUA_DIR)/linit.c \
$(LUA_DIR)/liolib.c \
$(LUA_DIR)/llex.c \
$(LUA_DIR)/lmathlib.c \
$(LUA_DIR)/lmem.c \
$(LUA_DIR)/loadlib.c \
$(LUA_DIR)/lobject.c \
$(LUA_DIR)/lopcodes.c \
$(LUA_DIR)/loslib.c \
$(LUA_DIR)/lparser.c \
$(LUA_DIR)/lstate.c \
$(LUA_DIR)/lstring.c \
$(LUA_DIR)/lstrlib.c \
$(LUA_DIR)/ltable.c \
$(LUA_DIR)/ltablib.c \
$(LUA_DIR)/ltm.c \
$(LUA_DIR)/lundump.c \
$(LUA_DIR)/lutf8lib.c \
$(LUA_DIR)/lvm.c \
$(LUA_DIR)/lzio.c \
HOST_PLATFORM= none
.PHONY: default none clean nix-clean windows-clean \
mingw-clean mingw macosx macosx-clean osx-clean osx \
linux-clean linux bsd-clean bsd solaris-clean solaris \
haiku-clean haiku windows-base windows windows-msbuild
default: $(HOST_PLATFORM)
none:
@echo "Please do"
@echo " nmake -f Bootstrap.mak windows"
@echo "or"
@echo " CC=mingw32-gcc mingw32-make -f Bootstrap.mak mingw CONFIG=x64"
@echo "or"
@echo " make -f Bootstrap.mak HOST_PLATFORM"
@echo "where HOST_PLATFORM is one of these:"
@echo " osx linux bsd"
@echo ""
@echo "To clean the source tree, run the same command by adding a '-clean' suffix to the target name."
@echo "Example"
@echo " make -f Bootstrap.mak HOST_PLATFORM-clean"
clean:
@echo "Please run the same command used for building by adding a '-clean' suffix to the target name."
@echo " nmake -f Bootstrap.mak windows-clean"
@echo "or"
@echo " CC=mingw32-gcc mingw32-make -f Bootstrap.mak mingw-clean CONFIG=x64"
@echo "or"
@echo " make -f Bootstrap.mak HOST_PLATFORM-clean"
@echo "where HOST_PLATFORM is one of these:"
@echo " osx linux bsd"
nix-clean:
$(SILENT) rm -rf ./bin
$(SILENT) rm -rf ./build
$(SILENT) rm -rf ./obj
windows-clean:
$(SILENT) if exist .\bin rmdir /s /q .\bin
$(SILENT) if exist .\build rmdir /s /q .\build
$(SILENT) if exist .\obj rmdir /s /q .\obj
mingw-clean: windows-clean
mingw: mingw-clean
if not exist build\bootstrap (mkdir build\bootstrap)
$(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -I"$(LUA_DIR)" -I"$(LUASHIM_DIR)" $(SRC) -lole32 -lversion
./build/bootstrap/premake_bootstrap embed
./build/bootstrap/premake_bootstrap --arch=$(PLATFORM) --os=windows --to=build/bootstrap --cc=mingw gmake2
$(MAKE) -C build/bootstrap config=$(CONFIG)_$(PLATFORM)
macosx: osx
macosx-clean: osx-clean
osx-clean: nix-clean
osx: osx-clean
mkdir -p build/bootstrap
$(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_MACOSX -I"$(LUA_DIR)" -I"$(LUASHIM_DIR)" -framework CoreServices -framework Foundation -framework Security -lreadline $(SRC)
./build/bootstrap/premake_bootstrap embed
./build/bootstrap/premake_bootstrap --arch=$(PLATFORM) --to=build/bootstrap gmake2
$(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` config=$(CONFIG)
linux-clean: nix-clean
linux: linux-clean
mkdir -p build/bootstrap
$(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -I"$(LUA_DIR)" -I"$(LUASHIM_DIR)" $(SRC) -lm -ldl -lrt
./build/bootstrap/premake_bootstrap embed
./build/bootstrap/premake_bootstrap --to=build/bootstrap gmake2
$(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` config=$(CONFIG)
bsd-clean: nix-clean
bsd: bsd-clean
mkdir -p build/bootstrap
$(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -I"$(LUA_DIR)" -I"$(LUASHIM_DIR)" $(SRC) -lm
./build/bootstrap/premake_bootstrap embed
./build/bootstrap/premake_bootstrap --to=build/bootstrap gmake2
$(MAKE) -C build/bootstrap -j`getconf NPROCESSORS_ONLN` config=$(CONFIG)
solaris-clean: nix-clean
solaris: solaris-clean
mkdir -p build/bootstrap
$(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -I"$(LUA_DIR)" -I"$(LUASHIM_DIR)" $(SRC) -lm
./build/bootstrap/premake_bootstrap embed
./build/bootstrap/premake_bootstrap --to=build/bootstrap gmake2
$(MAKE) -C build/bootstrap -j`getconf NPROCESSORS_ONLN` config=$(CONFIG)
haiku-clean: nix-clean
haiku: haiku-clean
mkdir -p build/bootstrap
$(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_BSD_SOURCE -I"$(LUA_DIR)" -I"$(LUASHIM_DIR)" $(SRC) -lbsd
./build/bootstrap/premake_bootstrap embed
./build/bootstrap/premake_bootstrap --to=build/bootstrap gmake2
$(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` config=$(CONFIG)
windows-base: windows-clean
if not exist build\bootstrap (mkdir build\bootstrap)
cl /Fo.\build\bootstrap\ /Fe.\build\bootstrap\premake_bootstrap.exe /DPREMAKE_NO_BUILTIN_SCRIPTS /I"$(LUA_DIR)" /I"$(LUASHIM_DIR)" user32.lib ole32.lib advapi32.lib $(SRC)
.\build\bootstrap\premake_bootstrap.exe embed
.\build\bootstrap\premake_bootstrap --arch=$(PLATFORM) --to=build/bootstrap $(MSDEV)
windows: windows-base
devenv .\build\bootstrap\Premake5.sln /Upgrade
devenv .\build\bootstrap\Premake5.sln /Build "$(CONFIG)|$(PLATFORM:x86=win32)"
windows-msbuild: windows-base
msbuild /p:Configuration=$(CONFIG) /p:Platform=$(PLATFORM:x86=win32) .\build\bootstrap\Premake5.sln

View file

@ -0,0 +1,656 @@
--------------------
5.0-beta1
--------------------
See https://github.com/premake/premake-core/wiki/What's-New-in-5.0
for the complete list of changes from the Premake 4.x series.
Since 5.0-alpha16:
* PR #1555 Added API to disable fast up to date checks (@nickclark2016)
* PR #1570 Initial C++20 module support for Visual Studio (@hannes-harnisch)
* PR #1619 Xcode embed libraries (@nickgravelyn)
* PR #1625 Remove "*ng" action deprecation (@noresources)
* PR #1629 Added support for Premake on macOS universal binary (@tempura-sukiyaki)
* PR #1635 Fix typo in Using Premake documentation (@abhiss)
* PR #1638 Fix broken links in docs (@KyrietS)
* PR #1642 Fix spelling mistake (@Troplo)
* PR #1644 Fix author name and update time on pages (@KyrietS)
* PR #1645 Add missing support for prebuildmessage/postbuildmessage for Codelite. (@Jarod42)
* PR #1649 Fix curl header search path (@depinxi)
* PR #1654 xcode4: Fix missing link of sibling project with custom targetextension (@depinxi)
* PR #1655 Compiler Version support for Visual Studion 2017+ (@nickclark2016)
* PR #1657 Renormalize line endings (@nickclark2016)
* PR #1661 Add frameworkdirs support to gmake and gmake2 with gcc/clang toolsets (@depinxi)
* PR #1663 compilebuildoutputs make some comments obsolete. (@Jarod42)
* PR #1668 Fix v6 bootstrapping from v5 (@starkos)
* PR #1673 Updated sidebar to include toolsversion link (@premake)
* PR #1680 Fix some build issues with mingw (@Biswa96)
* PR #1682 Add Community Update #9 (@starkos)
* PR #1687 Update deprecated entry for `newaction` (@Jarod42)
* PR #1704 VS2022 Exporter (@nickclark2016)
* PR #1710 Add support for SSE 4.2. (@ActuallyaDeviloper)
* PR #1712 Add OpenMP support for Visual Studio (@T-rvw)
* PR #1713 Upgrade docusaurus version to beta.6 (@KyrietS)
* PR #1715 Docs maintenance (@KyrietS)
* PR #1718 Deprecate `configuration()` (@starkos)
* PR #1720 Improve `justmycode` (@T-rvw)
* PR #1723 Add condition to `.csproj` references ItemGroup (@cicanci)
* PR #1726 Updated cdialect and cppdialect docs (@LORgames)
* PR #1727 Updated architecture docs (@LORgames)
* PR #1730 Added missing compileas values to docs (@LORgames)
* PR #1734 Add VS 2022 bootstrapping support (@afxw)
* PR #1736 Update showcase to include Orx (@sausagejohnson)
* PR #1662 Handle buildcommand for Codelite (@Jarod42)
* PR #1658 Fix D module compiler output for Visual Studio (@nickclark2016)
* PR #1728 Add action to check for and generate missing documentation (@ssurtees)
* PR #1721 Add custom rules for Gmake2 & Codelite (@Jarod42)
* PR #1739 Fix #1628 failing macOS os.findlib() test (@starkos)
Since 5.0-alpha15:
* PR #1430 Fixed adding LD_LIBRARY_PATH to the executable run command. (@Enhex)
* PR #1439 Disable XP deprecation warning for Visual Studio projects (@withmorten)
* PR #1446 Do not add <Link> for .NET resources or the resource will not be properly embedded. (@rhuvendiek)
* PR #1447 Added /Wall to possible warning levels for Visual Studio (@ethan-wallace)
* PR #1454 Bootstrap.mak clean target(s) (@noresources)
* PR #1460 Add C++20 cppdialect for C++ projects (@nickclark2016)
* PR #1462 Added clang as a valid option for projects generated with vs2019 (@nickclark2016)
* PR #1468 macOS deployment target support for gcc and clang (@noresources)
* PR #1473 macOS os.getversion() improvements (@noresources)
* PR #1477 Add support for .swift file for xcode (@socialpoint)
* PR #1481 Improved ability to override XCode generator (@LORgames)
* PR #1482 Disable redirect test until HTTP endpoint is fixed (@LORgames)
* PR #1483 Add file details to Windows builds including version number (@LORgames)
* PR #1484 Fixed issue with os.matchfiles and symlinks (@LORgames)
* PR #1485 Added Windows implementation to os.touchfile to avoid issues with truncating the file (@LORgames)
* PR #1499 GitHub Actions: Artifacts (@sphene)
* PR #1503 Update cxx standard; (@continue98)
* PR #1505 Fix sysincludedirs for codelite. (@Jarod42)
* PR #1506 Fix quote escaping in Codelite. (@Jarod42)
* PR #1515 ConformanceMode flag implemented for >= vs2017 (@cos-public)
* PR #1519 Add Metal shader files as source code (@nickgravelyn)
* PR #1522 Fixed external library linking for Clang in VS2019+ (@nickclark2016)
* PR #1523 Added C++1z and C++2a dialect options for XCode (@nickclark2016)
* PR #1525 [Codelite] Only active (i.e. unique) configuration should be selected. (@Jarod42)
* PR #1527 Removed old CI build files (@LORgames)
* PR #1528 Added COPYFILE and COPYDIR tokens (@LORgames)
* PR #1529 NMake projects can now specify buildoptions and cppdialect (@LORgames)
* PR #1530 Remove unused code in vs2010_vcxproj.lua (@LORgames)
* PR #1532 Disable network tests; add --test-all flag to enable (@starkos)
* PR #1534 Added Ability to Disable JMC in Visual Studio (@nickclark2016)
* PR #1540 Xcode improvements (@noresources)
* PR #1542 Improve the user contribution resources (@premake)
* PR #1551 Added NetCore to CLR API (@nickclark2016)
* PR #1552 Fix MSC LTO, runtime, subsystem (@JoelLinn)
* PR #1554 clang Use `llvm-ar` linker when LTO flag is set. (@JoelLinn)
* PR #1560 Added newer shader versions (@dpeter99)
* PR #1562 Remove moduledownloader to avoid RCE. (@xenia-project)
* PR #1564 Improved net version check to also support net5.0 and beyond (@ClxS)
* PR #1565 AllowUnsafeBlocks will now be a project level property in new format (@ClxS)
* PR #1566 Set execute bit on Bootstrap.bat (@ratzlaff)
* PR #1571 useFullPaths config property for Visual Studio projects (@cos-public)
* PR #1576 Mesh and amplification shader type for Visual Studio (@pkurth)
* PR #1587 Introduce new website with docs with docusaurus (@KyrietS)
* PR #1589 os.outputof: add a second argument to select which stream to output (@noresources)
* PR #1593 Update to mbedtls 2.25 (@susnux)
* PR #1594 Added reference pages to docs (@KyrietS)
* PR #1597 Port user guide pages from wiki (@starkos)
* PR #1600 Add GitHub Action workflow for website deployment (@KyrietS)
* PR #1602 Rework website home & download pages (@starkos)
* PR #1604 Break out community section on website (@starkos)
* PR #1606 add RemoveUnreferencedCodeData option to disable /Zc:inline (@withmorten)
* PR #1607 Add Algolia search (@KyrietS)
* PR #1608 Fix Premake logo in README (@KyrietS)
* PR #1609 Encourage contributors to align the docs (@KyrietS)
* PR #1610 Improve new user website navigation (@starkos)
* PR #1614 Set up blog; move community updates (@starkos)
Since 5.0-alpha14:
* PR #1086 Added support for Objective-C and Objective-C++ in xcode and gmake2nil (@LORgames)
* PR #1192 Update path.lua (@dsvi)
* PR #1229 Generated makefiles no longer error when a configuration can be missing (@LORgames)
* PR #1275 Fixed various issues with escaping in CodeLite generator (@LORgames)
* PR #1280 Bootstrap.bat: Default to latest Visual Studio available (@tdesveauxPKFX)
* PR #1281 Source package improvements (@tdesveauxPKFX)
* PR #1282 Fix VS2019 solution icons (@ifarbod)
* PR #1285 Use correct values for MinimumVisualStudioVersion in Android projects (@ifarbod)
* PR #1289 Haiku fixes (@mmuman)
* PR #1296 Fix source packaging (@tdesveauxPKFX)
* PR #1298 Update D module to VS2019 and latest D compiler options. (@TurkeyMan)
* PR #1305 Reconcile logic within os_matchisfile() (@cfs-pure)
* PR #1313 Activating Open Collective (@opencollective)
* PR #1316 Add FUNDING.yml for GitHub Sponsors (@starkos)
* PR #1318 Updated mismatched android config to the value in the allowed stl table (@LORgames)
* PR #1323 Update copyright year in support files (@starkos)
* PR #1324 Add a CONTRIBUTING.md (@starkos)
* PR #1325 Improve the README (@starkos)
* PR #1326 Update issue templates (@premake)
* PR #1327 Add a pull request template (@premake)
* PR #1332 Account for filename collisions on systems with case-insensitive file… (@ratzlaff)
* PR #1333 Cleanup related to #1332 (@ratzlaff)
* PR #1334 Implement 'compileas' for vc2008 (@ratzlaff)
* PR #1337 On OSX, convert systemversion to MACOSX_DEPLOYMENT_TARGET (@baconpaul)
* PR #1340 Upgrade Lua from 5.3.4 to 5.3.5 (@jp31415926)
* PR #1341 Add new issue template "Get help" (@premake)
* PR #1342 Improve bug reporting template (@premake)
* PR #1343 Improve feature request template (@premake)
* PR #1345 New 'listWindowsRegistry' OS API method for enumerating content of single registry subkey (@kaldap)
* PR #1351 Added support for vcxitems project generation for VS2013+ (@LORgames)
* PR #1352 Improved test runner usage (@LORgames)
* PR #1353 Fix premake4.lua bootstrap build script (@fountainment)
* PR #1355 Add shaderincludedirs to fxcompile configuration (@starkos)
* PR #1356 Allow wildcards in xcodebuildresources (@starkos)
* PR #1357 Replace debuggerflavor with debugger (take #2) (@starkos)
* PR #1358 Added support for Dx11.3 shader model (@zlnimda)
* PR #1359 Add assemblyDebug for vs2017 (@tbasnoopy)
* PR #1360 Fix the return value of some os functions (@sp-jordi-vilalta)
* PR #1361 Simplified unit test to resolve path issues (@LORgames)
* PR #1362 Fixed inconsistencies in Android VS project test (@LORgames)
* PR #1365 E2K: fixed build by MCST lcc compiler (@r-a-sattarov)
* PR #1385 Fix pull request template (@tempura-sukiyaki)
* PR #1386 Initial support for generating netcore and netstandard projects (@ClxS)
* PR #1395 Fixed edge case in path.normalize (@LORgames)
* PR #1396 Fixed bug with linkgroups only working on Premake projects (@LORgames)
* PR #1401 Remove commands optimization which breaks tokens (@starkos)
* PR #1402 Remove checkFunc from Resource files (@yuyoyuppe)
* PR #1403 Add build steps to Visual Studio (@redorav)
* PR #1404 Place all generated files in separate GENERATED list, so they all can… (@Mikhael-Danilov)
* PR #1406 Change deferred join delimiter to non-printable character (@starkos)
* PR #1415 Add .c++ extension support to a few spots it was missing (@englercj)
* PR #1419 Fix #1411: Remove "|" from Codelite config names (@starkos)
* PR #1420 Fix MinGW builds of Premake (@premake)
* PR #1421 Enable enablewarnings() for MSC (@starkos)
* PR #1422 Added GitHub Actions (@LORgames)
* PR #1424 Fix systemversion("latest") on VS2017 (@starkos)
* PR #1427 Fix up and improve the release docs and script (@premake)
Since 5.0-alpha13:
* PR #1067 Add 'Default', 'Dwarf' and 'SplitDwarf' arguments to 'debugformat' (@ratzlaff)
* PR #1160 use ';' as default separator for vs (@WorldofBay)
* PR #1177 Enable property categories in VS projects (@WorldofBay)
* PR #1178 Avoid impl dependent multi-char constants (@cengizIO)
* PR #1179 fix `xcodebuildsettings` using false (@tempura-sukiyaki)
* PR #1180 Add `os.ios` option in xcode4 (@tempura-sukiyaki)
* PR #1181 Release 5.0 alpha13 (@premake)
* PR #1189 Host path.normalize: Fix normalization for paths containing tokens (@tdesveauxPKFX)
* PR #1191 Fix objname collisions (@ratzlaff)
* PR #1193 Add tests for xcode id generator (@ratzlaff)
* PR #1194 Move rule property string expansion into modules (@WorldofBay)
* PR #1197 Added missing elements in Visual Studio Makefile projects (@LORgames)
* PR #1202 Support %{file.name} token in VS (@Blizzard)
* PR #1203 Add support for JavaCompile in vsandroid (@tempura-sukiyaki)
* PR #1206 Updated code lite to properly add LD_LIBRARY_PATH is set if libdirs is set (@pintodragon)
* PR #1218 Add support & tests for XCTest sharedlibtype (@Dingobloo)
* PR #1220 Implement the androidapilevel() API in Android packaging projects (@ifarbod)
* PR #1221 add nil check to fileconfig.hasFileSetting (gmake) (@WorldofBay)
* PR #1224 add missing local (@WorldofBay)
* PR #1228 Added Win64 as a recognized platform (@LORgames)
* PR #1230 Removed excessive escaping in CodeLite generator (@LORgames)
* PR #1231 Fixed issue with per-configuration build commands not returning errors correctly (@LORgames)
* PR #1236 Added support for Dx12 shader models (@CosmicRey)
* PR #1239 Implemented the startproject option for xcode (@macsforme)
* PR #1240 allow linking of mixed c++ assemblies (@WorldofBay)
* PR #1244 Fixed issue with detoken not handling deferred joins correctly (@LORgames)
* PR #1247 Added support for `csversion` API to dotnet toolset. (@tritao)
* PR #1248 Default to Roslyn-based `csc` compiler on all platforms. (@tritao)
* PR #1249 do not clear _isIncludingExternal in nested calls (@WorldofBay)
* PR #1253 Xcode newid determinism (@ratzlaff)
* PR #1258 Added support for Visual Studio 2019 solutions (@CosmicRey)
* PR #1264 Android changes, stage 1 (#1263) (@ifarbod)
* PR #1266 Implement the 'visibility' API for Android projects (@ifarbod)
* PR #1267 Provide access to json implementation (@ratzlaff)
* PR #1276 Added support for forceincludes in CodeLite (@LORgames)
* PR #1278 Packaging script improvement (@tdesveauxPKFX)
Since 5.0-alpha12:
* PR #880 Allow tokens to start with a ! to disable making paths relative. (@Blizzard)
* PR #882 Allow filtering on host. (@Blizzard)
* PR #883 Added basic iOS support to XCode4 (@LORgames)
* PR #889 Fix context.mergeFilters (@tdesveaux)
* PR #897 Fix c(pp)dialect generating uppercase C(++)xx for Xcode, replace gnu99 with compiler-default (@hsandt)
* PR #902 VS fix for projects with multiple manifest files (@Blizzard)
* PR #913 Fix subtle bug in table.translate (@Blizzard)
* PR #919 Add perfile flags test for gmake backend. (@Blizzard)
* PR #920 small fix in self-test module. (@Blizzard)
* PR #921 Compiler warnings (@Blizzard)
* PR #922 gmake2 bug fix. When generating gmake file with pch headers (@Blizzard)
* PR #923 Add Visual Studio ARM64 support. (@Blizzard)
* PR #926 Fixes translateCommandsAndPaths, and debugargs. (@Blizzard)
* PR #927 bug fix for recursive token expansion (@Blizzard)
* PR #928 sometimes due to ordering of test, we're in a rule scope. (@Blizzard)
* PR #931 Added synchronous and C-Throw to VS projects. (@CreativeAssembly)
* PR #932 Added extra information for Windows platform when copyfile fails. (@pjohalloran)
* PR #938 Added `staticruntime` API. (#163) (@premake)
* PR #939 Resolve the rule properties for gmake (#162) (@premake)
* PR #941 Fix makefile PCH tab problem (@premake)
* PR #944 C++0x dialect support (@premake)
* PR #945 Natvis files have an item group. (@premake)
* PR #948 Fixed a bug in gmake2 with clang and pch. (@Gereld)
* PR #949 Added DPI awareness support to VS2010+ projects (@LORgames)
* PR #950 Added defaultplatform support to gmake and gmake2 actions (@LORgames)
* PR #952 Add support for `targetextension` in xcode4 (@tempura-sukiyaki)
* PR #957 fix gmake2 utility (@Blizzard)
* PR #958 fix context.addFilter (@Blizzard)
* PR #959 Multiple gmake2 fixes (@Blizzard)
* PR #960 Improve determinism in sln output. (@Blizzard)
* PR #961 add 64-bit support on windows (@Blizzard)
* PR #962 fix table.insertkeyed (@Blizzard)
* PR #964 Add support for wildcards in mapconfig. (@Blizzard)
* PR #965 Move part of the workspace baking up (@premake)
* PR #966 utility projects also allow configuration of the executable path. (@Blizzard)
* PR #967 return generated fileconfig. (@Blizzard)
* PR #969 Fix buildoutput pathvars (@Blizzard)
* PR #970 Table fix indexof (@Blizzard)
* PR #979 Define _HAS_EXCEPTIONS=0 from vs2010 for exceptionhandling off (@tdesveauxPKFX)
* PR #980 src/base and modules: change links to industriousone.com to working HTTPS github links (@catb0t)
* PR #988 Fixed a bug with normalizing paths that contain dot folders (@LORgames)
* PR #990 Extended Instructions sets (@tdesveauxPKFX)
* PR #993 Fix /usr/lib64 being used as search dir before project's libdir (@alexandre-janniaux)
* PR #994 added a 'latest' systemversion for vs2017 (@dcourtois)
* PR #1005 Fix gmake dependencies (@premake)
* PR #1011 Fixes an issue with custom rules tracking files. (@Dandielo)
* PR #1018 Added release info badges to the readme (@LORgames)
* PR #1019 Remove git submodule commands (@Passw)
* PR #1020 Embed luasocket, add mobdebug and --debugger command line option (@redorav)
* PR #1021 Clear additional global state between unit test runs (@starkos)
* PR #1023 Include library directories in Codelite projects (@Gaztin)
* PR #1029 Replace last global state block in api.reset (@starkos)
* PR #1030 Fix vstudio symbolspath (@tdesveauxPKFX)
* PR #1031 Fix gmake2 Makefile projects callArray (@tdesveauxPKFX)
* PR #1033 vstudio staticlib symbolspath (@tdesveauxPKFX)
* PR #1034 Add 'modules/android/' from premake-android (@LORgames)
* PR #1037 HLSL Shader compilation in Visual Studio (@tdesveauxPKFX)
* PR #1040 Get 'compileas' working when using a 'filter "files: ..."' scope. (@ratzlaff)
* PR #1041 Fleshed out CI builds (@LORgames)
* PR #1042 Add UnsignedChar API (@tdesveauxPKFX)
* PR #1043 Add omitframepointer API (@tdesveauxPKFX)
* PR #1044 Add Visibility API for gcc/clang toolsets (@tdesveauxPKFX)
* PR #1045 Add debuggerflavor API (@tdesveauxPKFX)
* PR #1046 Add structmemberalign API (@tdesveauxPKFX)
* PR #1048 Add conditional behavior to global variables, add systemversion as first implementation (@redorav)
* PR #1049 Add InlinesVisibility API (@tdesveauxPKFX)
* PR #1053 Fixed issue with floatingpoint "Strict" causing errors in XCode (@LORgames)
* PR #1062 Allow system("android") per configuration (@redorav)
* PR #1064 Tiny gcc fix from PR #506. (@tvandijck)
* PR #1065 Fixes a few luasocket compile warnings. (@tvandijck)
* PR #1066 fix a few compiler warnings. (@tvandijck)
* PR #1068 Fix constructing executable path from argv[0] (@lanurmi)
* PR #1069 Support successfully bootstrapping on Solaris (OpenIndiana). (@lanurmi)
* PR #1070 Support successfully bootstrapping on OpenBSD. (@lanurmi)
* PR #1075 Fixed bug with alias tests that caused one to three extra tests to be run (@LORgames)
* PR #1077 Do not output colors e.g. into a pipe, unless forced. (@lanurmi)
* PR #1078 Added GoogleTest style output for unit tests (@LORgames)
* PR #1080 Fix curl compilation on Debian PowerPC. (@lanurmi)
* PR #1081 cache results of shouldUseColors() (@tvandijck)
* PR #1084 Fix httpbin useragent response format. (@SchmidtD)
* PR #1087 Fix missing DebugInformationFormat when symbols are set to full (@rorydriscoll)
* PR #1089 Import paths weren't translated properly (@TurkeyMan)
* PR #1092 CodeLite workspace folders (groups) (@Gaztin)
* PR #1093 Implemented 'debugenvs' for CodeLite (@Gaztin)
* PR #1096 gmake2: Fix dependency for pch (@tdesveauxPKFX)
* PR #1098 Prevent D module from adding D block in unrelated projects (@tdesveauxPKFX)
* PR #1100 gmake2: Remove pch from FORCE_INCLUDE to allow NoPCH per-file (@tdesveauxPKFX)
* PR #1103 gmake*: fix shell type identification (@tdesveauxPKFX)
* PR #1104 Xcode Fixes (@erincatto)
* PR #1105 gmake: Add rules and dependencies for directory creation (@tdesveauxPKFX)
* PR #1107 Only set WindowsSDKDesktopARMSupport for windows systems (#172) (@Blizzard)
* PR #1108 Fix gmake2 (@Blizzard)
* PR #1113 Support buildaction for C++ projects (@Blizzard)
* PR #1115 Remove Xbox 360 code from core to move and expand onto a standalone module (@redorav)
* PR #1117 Fix Xcode autocompletion with excluded files (@sp-jordi-vilalta)
* PR #1118 gmake2: fix cpp perfileflags (@tdesveauxPKFX)
* PR #1125 Swap order of applying project specific config (@Blizzard)
* PR #1126 vpath android.link fix (@Blizzard)
* PR #1132 Refactor path.normalize and handle path ending with . (@tdesveauxPKFX)
* PR #1136 Support server paths (@Gaztin)
* PR #1137 Fix gmake multiple-output rule issue. (@Blizzard)
* PR #1142 Support for CSDialect (@Blizzard)
* PR #1143 Fix `targetextension` in xcode4 (@tempura-sukiyaki)
* PR #1144 Add `sharedlibtype` in xcode4 (@tempura-sukiyaki)
* PR #1145 Add support `kind:Utility` in xcode4 (@tempura-sukiyaki)
* PR #1161 Add `xcodesystemcapabilities` in xcode4 (@tempura-sukiyaki)
* PR #1164 ! fixed pepper fish to work with lua 5.3.4 (@neo2buha)
* PR #1167 Add support for per-file custom build commands in xcode4 (@tempura-sukiyaki)
* PR #1176 path.normalize: Fix when call with path surrounded with quotes (@tdesveauxPKFX)
Since 5.0-alpha11:
* PR #617 fix switch/separator in rules_xml (@Blizzard)
* PR #639 Add MSBuild target to Bootstrap.mak (@nta)
* PR #644 Don't treat "dependson" libraries as "links" libraries in Xcode (@macsforme)
* PR #659 Add C11 flag support for GCC (@resetnow)
* PR #668 Fix sporadic failures when using make -j# (@UmbraSoftware)
* PR #672 Fix issue with msc.getlinks and vstudio.getLinks returning different results when 'explicit' is true. (@Blizzard)
* PR #673 Add additional tokens to fileconfig and vs2010+. (@Blizzard)
* PR #675 update semver.lua (@Blizzard)
* PR #678 Escape string literals passed to defines() for Xcode (@macsforme)
* PR #679 Better detect debug build (@TurkeyMan)
* PR #685 Detect native source files. (@TurkeyMan)
* PR #686 Refactor language flags to go through the language API. (@Blizzard)
* PR #687 Windows Registry (@tvandijck)
* PR #690 make buffered_io available for c code too. (@Blizzard)
* PR #707 Fix missing CA certs on Windows (@Jusonex)
* PR #718 Adding support for NotSet characterset in VS2010+ (#79) (@Blizzard)
* PR #721 Fix CodeLite linking issues (@Blizzard)
* PR #728 Add support of UTF-8 for Windows (@DrLynix)
* PR #732 Fix VS2013 and older always rebuilding when debug symbols explicitly … (@jstewart)
* PR #733 Generated project files are now correctly located beside script (@LORgames)
* PR #734 NuGet fixes (@aleksijuvani)
* PR #735 Fixed issue with Clang not actually supporting floatingpoint 'strict' (@LORgames)
* PR #736 Fixed issue where VS2010+ projects didn't support floatingpoint 'Default' (@LORgames)
* PR #737 Add string.escapepattern function (@aleksijuvani)
* PR #738 Update curl to 7.53.1 (@aleksijuvani)
* PR #739 Refactor _OS, os.get() & os.is() (@Blizzard)
* PR #740 Properly deprecate WinMain flag (@LORgames)
* PR #742 Added BSD support (@LORgames)
* PR #743 Clean up the deprecated APIs (@industriousone)
* PR #745 Fixed issue with using startproject API in CodeLite (@LORgames)
* PR #746 Fixed erroneous escape usages in VS2010+ (@LORgames)
* PR #747 Bootstrap makefile now cleans up previous builds before building (@LORgames)
* PR #748 os.translateCommands now supports multiple tokens (@LORgames)
* PR #749 Updated packaging script (@LORgames)
* PR #751 CompileAs element handles C++ now (@LORgames)
* PR #752 Fixed various issues with compiling with VS2012 (@LORgames)
* PR #753 Added proxy URL to http options (@LORgames)
* PR #754 Fixed issue with the OBJDIR value not being escaped (@LORgames)
* PR #755 Add 'supports_language' callback to action (@Blizzard)
* PR #756 Fix a call to deprecated os.get() (@Blizzard)
* PR #757 Increased consistency of p. usage (@LORgames)
* PR #758 Cleaned up inconsistencies in whitespace (@LORgames)
* PR #760 Adding ARM support for Visual Studio. (@Blizzard)
* PR #761 Removed echo off in VS rules prop generator (@LORgames)
* PR #763 [core] Print warnings in purple (@Blizzard)
* PR #764 [core] get file/line information on deprecated API's. (@Blizzard)
* PR #768 [core] Fix Visual Studio ExecutablePath settings. (@Blizzard)
* PR #769 [core] new cmd path decorations with %[] syntax (@Blizzard)
* PR #771 [core] Use 'compileAs' API (@Blizzard)
* PR #772 [core] Don't set default entrypoint, rely on visual studio default. (@Blizzard)
* PR #774 Assure a default toolset is always set. (@Blizzard)
* PR #776 [core] Use 'cdialect' and 'cppdialect' instead of 'language'. (@Blizzard)
* PR #778 Added support at the file level for the NoPCH flag in VS200x projects (@LORgames)
* PR #779 add os.findheader() (@noresources)
* PR #781 Allow filters to be written as tables: (@Blizzard)
* PR #785 Unicode file functions for Windows (@DrLynix)
* PR #786 Fix typo in embed.lua (@DrLynix)
* PR #787 os.comparefiles function (@DrLynix)
* PR #788 Provide a way to 'tag' systems, and filter on those tags. (@Blizzard)
* PR #789 Add 'tags' filter api. (@Blizzard)
* PR #790 [self-test] fix nil dereference crash in test.isequal (@Blizzard)
* PR #798 create object directory before generating precompiled header (@noresources)
* PR #801 Groups in XCode workspace working. (@ricka)
* PR #802 Suppress mkdir warning on Windows if the folder already exists (@aleksijuvani)
* PR #803 Gmake2 module (@Blizzard)
* PR #804 Update to Lua 5.3.4 (@Blizzard)
* PR #805 Add --insecure option for SSL curl requests. (@Blizzard)
* PR #806 Add premake.isSemVer function (@Blizzard)
* PR #807 Added visual studio support for dot net .tt files (@Blizzard)
* PR #808 Added per file rtti generation for Visual Studio (@Blizzard)
* PR #809 Added os touchfile and a workaround for vs2010 reloading (@Blizzard)
* PR #810 Added masm handling of seh exception handling for VS2010 and above (@Blizzard)
* PR #811 Add 'preferredtoolarchitecture' API (@Blizzard)
* PR #812 Add support for cppdialect in VS2015 & VS2017 actions. (@Blizzard)
* PR #813 Add json.encode_pretty wrapper. (@Blizzard)
* PR #814 Add premake.info message function. (@Blizzard)
* PR #815 Errors in red. (@Blizzard)
* PR #816 Fixed C++17 flag to work with current versions of Clang. (@Blizzard)
* PR #817 A few gmake2 fixes due to it moving into a module. (@premake)
* PR #818 Make module of 'gmake' action. (@Blizzard)
* PR #821 Attempt at colors on linux (@Blizzard)
* PR #822 Move VStudio action into a module. (@Blizzard)
* PR #824 Set default toolsets for vs2005 and vs2008. (@Blizzard)
* PR #825 Use workspace everywhere (@Blizzard)
* PR #826 Escape '&' -> '&amp;' (@Mikhael)
* PR #827 Added option to create bundle and frameworks on macOS. (@Blizzard)
* PR #828 Normalize path in 'getfileinfo' for local host. (@Blizzard)
* PR #829 Reduced vs2010+ file sizes by removing redundant config settings (@Blizzard)
* PR #830 Resource generator access (@Blizzard)
* PR #831 Fix in oven, for options that are not strings. (@Blizzard)
* PR #832 Fix a few compiler warnings (@Blizzard)
* PR #833 Fix empty rules. (@Blizzard)
* PR #834 Allow modules to register C code too. (@Blizzard)
* PR #836 Hook setTextColor in tests, so on linux/mac we don't get random color… (@Blizzard)
* PR #837 Removed "installer" kinds from vs2017. (@premake)
* PR #838 Fix bug in 'action.isConfigurable' not checking for onWorkspace. (@Blizzard)
* PR #839 Expand {...} macros in pre|post build commands for codelite (@Mikhael)
* PR #840 Proof of concept for binary modules. (@tvandijck)
* PR #842 Add bsd to the output of possible platforms (@ejb1123)
* PR #843 fix bug in testing framework leaving tests in random working folders. (@tvandijck)
* PR #844 fix unreferenced argument warning. (@tvandijck)
* PR #849 Write out build log element for VS utility projects (@mendsley)
* PR #851 Fix handling of unconventional NuGet .NET Framework folders (@aleksijuvani)
* PR #854 [core] Add High as a new warning level (@Blizzard)
* PR #855 Add filter for <Image> files (#135) (@Blizzard)
* PR #856 Fix path_getrelative for Windows (@Blizzard)
* PR #857 Fix action override targetos (@Blizzard)
* PR #858 Fix Nuget package handling to support Unix-style paths (@tritao)
* PR #859 Use NuGet package cache instead of the API if possible (@aleksijuvani)
* PR #860 fix for build failure on macOS in debug. (@Blizzard)
* PR #861 Allow embedding of binary resources. (@Blizzard)
* PR #862 small optimization in oven. (@Blizzard)
* PR #863 fix for duplicate 'allowed'. (@Blizzard)
* PR #864 move tags into globally accessible table, so we don't have to overload… (@Blizzard)
* PR #865 Remove "test.print" calls. (@Blizzard)
* PR #866 fix os.istarget and os.ishost to use the systemTags table as well. (@Blizzard)
* PR #867 Fix path translate (@Blizzard)
* PR #868 Filters always have to use \ regardless of target platform. (@Blizzard)
* PR #870 Fix prj.system bug in oven. (@Blizzard)
* PR #872 Rework binmodule example to silence unit test console output (@starkos)
* PR #874 Disable failing `os.findheader()` unit test on macOS (@starkos)
Since 5.0-alpha10:
* PR 523 New API symbols() replaces and extends "Symbols" flag
* PR 524 New API symbolspath() specifies location of symbol database
* PR 556 Add initialization hook for actions
* PR 553 Enable "list of paths" for rule properties
* PR 555 Allow multiple extensions for custom rules
* PR 561 Add IA32 to vectorextensions()
* PR 568 New API runpathdirs() adds rpath support
* PR 525 Add support for Visual Studio Debug Fast Link setting
* PR 401 Enable GCC link mode with ":static", ":shared"
* PR 543 Remove architecture specific include paths on macOS
* PR 554 Improve token expansion in rules
* PR 570 Normalize paths to os.execute()
* PR 546 Switch from openssl to mbedtls
* PR 545 compilebuildoutputs() adds generated files to build
* PR 575 New "raw" exporter
* PR 581 Fix path.normalize() handling of ".." sequences
* PR 587 Fix os.copyfile() handling of paths with spaces
* PR 597 Enable edit-and-continue for VS 2015 64-bit builds
* PR 583 Allow duplicate build commands
* PR 605 Fix for objdir() forced path operator "!"
* PR 603 Allow toolset-specific arguments to static linker
* PR 608 Allow Visual Studio StaticLib projects to link dependencies
* PR 610 Add defines and include paths to makefile projects
* PR 611 Prevent force includes from breaking precompiled headers
* PR 613 Fix os.match() detection of dot files
* PR 607 Remove support for deprecated MonoDevelop project formats
* PR 600 Fix VS support for symbolpath()
* PR 521 Make Clang default toolset for macOS
* PR 624 GCC support for C90 and C99
* PR 628 New API linkbuildoutputs() disables automatic linking of *.obj files
* PR 635 Improved parallelization of Makefile builds
* PR 619 Per-file configuration support for C# projects
* PR 649 Fix Visual Studio 2015 solution version identifier
* PR 645 Add initial Visual Studio 2017 support
Since 5.0-alpha9:
* New: `symbols()`, replaces and extends flags {"Symbols"}
* New: `symbolspath()` to specify location of symbol database
* New: `table.shallowcopy()`
* New: `vectorextensions` value "IA32"
* Fix: --start-group/--end-group now only enclose project libraries
Since 5.0-alpha8:
* New: `buildcustomizations()` imports custom .props files for VS
* New: `frameworksdir()` for Xcode and Make OS X projects
* New: `nuget()` to specify NuGet packages for VS projects
* New: `systemversion()` to specify VS target platform
* New: `io.readfile()` and `io.writefile()`
* New: Configurations may now be filtered by toolset
* New: HTTP calls now support authentication
* New: Support for XSD files in VS C# projects
* New: MASM file categorization for VS
* New: Integrated test framework for Premake module developers
* Fix: VS filter ordering is now deterministic
* Fix: VS projects and groups may now have the same name
* Fix: May now use '.' within shell variable tokens
* Fix: path.translate() now defaults to target system separator
* Fix: getextension() now handles multiple dots
* Fix: replaceextension() no longer adds leading dot
* Fix: Improved configuration baking performance
* Fix: Use -O0 for Clang debug optimization level
* Fix: CodeLite now uses portable path separators
* Fix: Improved ability to find precompiled headers in Makefiles
* Fix: Properly escape defines in Makefile projects
* Fix: Correct casing of UTF8 marker on Visual Studio rule files
Since 5.0-alpha7:
* New API: characterset()
* New API: editorintegration()
* New API: largeaddressaware()
* New: Visual Studio projects now default to Unicode
* New: Utility and Makefile project support for GMake exporter
* New: Updated Curl to 7.45.0
* Fix: Absolute path handling and error reporting in tokens
* Fix: Limit use of TargetMachine to static resource library projects
* Fix: Embed minified scripts by default, rather than bytecode
* Fix: os.isfile() now detects Windows symbolic links
* Fix: Correct handling of DOS environment variables in paths
* Fix: Buffer overflow in buffered writes of large strings
* Fix: Improved handling of absolute vs. relative path tokens
* Fix: --cc command line option works again (stream009)
* Fix: Use relative paths for PCH in Makefiles (stream009)
Since 5.0-alpha6:
* New API: additionalusingdirectories()
* New API: largeaddressaware()
* New: Embed bytecode to enable better debugging information
* New: Display elapsed time at completion
* New: Utility project support for Makefiles
* New: Enabled SSL support in HTTP functions
* Fix: Reduce memory usage during baking
* Fix: Improve performance of wildcard processing
* Fix: Preserve environment in recursive token expansion
* Fix: Added missing defines in bootstrap script
* Fix: Remove /usr/lib64 directories from Mac builds
* Fix: Added newline after UTF-8 marker in Visual Studio projects
* Fix: Duplicate escaping on include directories in Makefiles
* Fix: os.isdir() now works with Windows symbolic links
* Fix: Use correct path separators in C# response files
Since 5.0-alpha5:
* New API: ignoredefaultlibraries()
* New: Support LLVM platform toolset in Visual Studio
* New: Add framework folder path support
* Fix: Improved path.normalize() handling of DOS drive letters (StiX)
* Fix: os.match...() now supports more complex patterns
* Fix: Only generate project files if changed
* Fix: Improve handling of user platform names in Visual Studio
* Fix: Duplicate ".lib" extensions in Visual Studio
* Fix: Improve handling of mixed case command line options
* Fix: Remove `/E` option from Windows copy operations
* Fix: Multiple externalproject() calls to same project
* Fix: Improved determinism of generated project elements
* Fix: Set platform toolset for emtpty Visual Studio projects
* Fix: Better ".." handling for path.join()
Since 5.0-alpha4:
* New: Rename solution() to workspace()
* New API: customtoolnamespace() (tbasnoopy)
* New API: debuggertype() (tbasnoopy)
* New API: entrypoint() (Blizzard)
* New API: exceptionhandling() and rtti() (Blizzard)
* New API: http.get() and http.download() (Blizzard)
* New API: inlining() (Blizzard)
* New API: zip.extract() (Blizzard)
* New: `require()` now accepts optional version ranges
* New: Preloaded modules now return a "should load" test function
* New: Added support for IDL files in VC 2010+ (rhuvendiek)
* New: Added `file.directory` to token environment (Gabi Davar)
* New: Solution configurations are now fully baked (Blizzard)
* New: Enabled per-file configuration queries (Blizzard)
* New: Added more table functions (Blizzard)
* New: Added more values for floatingpoint()
* Fix: Enabled link-time optimization for Clang and GCC
* Fix: Module loader now reports script errors correctly (Tim Wharton)
* Fix: Wrap makefile targets in quotes (leeonix)
* Fix: Provide better default target directories (Blizzard)
* Fix: Escape backslashes in tokens (Damien Courtois)
* Fix: No longer generates containers marked as external
* Fix: Re-enable validation of supported action features (Blizzard)
* Fix: Match Visual C PDB output to target path (leeonix)
* Fix: Remove "." and ".." when joining paths (multiple contributors)
* Fix: Remove trailing newlines from os.outputof() (Tim Wharton)
* Fix: Improve token handling (multiple contributors)
Since 5.0-alpha2:
* New: CodeLite support
* New: D language support
* New: MonoDevelop support
* New API: buildlog()
* New API: callingconvention() (Tim Wharton)
* New API: os.writefile_ifnotequal()
* New API: sysincludedirs()
* New API: syslibdirs()
* New: toolset() can now specify a version number
* New: Default values and categories for command line options
* New: Add bootstrapping script for Git repository (Tim Wharton)
* Fix: Modules are now loaded correctly in all situations (Damien Courtois)
* Fix: Make Visual Studio debug commands absolute (amc522)
* Fix: Allow tokens in vpaths()
* Fix: Silence xcopy output from {COPY} command token (StiX)
* Fix: Remove ".." sequences in path.join()
* Fix: Allow CC and CXX overrides from command line (Tim Wharton)
* Fix: Enable solution level filtering on system values
* Fix: Make configuration flag mapping order deterministic
* Fix: Map "Win32" to x86 architecture for Visual Studio
* Fix: Correct formatting for Visual Studio rule paths
* Fix: Make project APIs consistently lowercase
* Fix: Disable SSE/SSE2 flags for Visual Studio 64-bit builds
* Fix: io.open() now creates directory append ("a") mode
Since 5.0-alpha1:
* Many new debugger APIs
* New API: endian()
* New API: fpu()
* New API: gccprefix()
* New API: pic()
* New API: runtime() (Tom van Dijck)
* New API: undefines()
* New API: disablewarnings(), enablewarnings(), fatalwarnings()
* Added Visual Studio 2015 support (Tom van Dijck)
* filter() now accepts field value aliases in the conditions
* Fixed _ACTION and _OPTIONS filter prefixes
* Main application logic can now be extended by modules
* Action arguments (_ARGS) are now keyed by both index and value
* Configuration baking and validation now skipped for execute only actions
* os.findlib() now accepts paths to search as argument
* Visual Studio .user files are now only generated if not empty
* Xcode4 exporter is now available
* Modules may now be loaded on demand where feasible
* os.outputof() now returns command exit code as second value
* Added AVX2 to vectorextensions()
* Checks to prevent self-linking (Mark Chandler)
* Added path.replaceextension() (M Skibbe)
* Made clean functions overridable
* Migrated x32/x64 to x86/x86_64
* Added new debugger selection APIs
* Fixed handling of ../ sequences in path.normalize() (Tom van Dijck)
* Added table.tostring() (Tom van Dijck)
* Added .editorconfig file
* Added string.sha1() (Tom van Dijck)
* Added verbosef() and --verbose flag (Tom van Dijck)

View file

@ -0,0 +1,100 @@
# Contributing to Premake
Thanks for your interest in contributing to Premake! :tada: We love getting [pull requests](https://www.quora.com/GitHub-What-is-a-pull-request) and rely heavily on the contributions of our community to keep Premake healthy and growing.
We want to keep it as easy as possible to contribute changes. These guidelines are intended to help smooth that process, and allow us to review and approve your changes quickly and easily. Improvements are always welcome! Feel free to [open an issue][issue-tracker] or [submit a new pull request][submit-pr]. And finally, these are just guidelines, not rules, so use your best judgement when necessary.
We do everything in [Git][git] hosted on [GitHub][github]. If you're new to this environment, you may want to begin with [Getting Started with GitHub](gh-start) and [Thinkful's GitHub Pull Request Tutorial](thinkful).
## Reporting Bugs
Bugs should be reported on our [GitHub Issue Tracker][issue-tracker].
Please consider if this is something [you can contribute](#contributing-a-fix-or-feature) yourself. Premake is a community project run by volunteers; the best way to get something fixed is to become a contributor!
Before opening an issue, use the search feature at the top of that page to see if it has already been reported.
If you've discovered a new bug, please follow the advice in [How do I ask a good question?][how-to-ask]. While the article is intended for people asking questions on [StackOverflow](https://stackoverflow.com/), it all applies to writing a good bug report too.
## Requesting New Features
Feature requests should be sent to our [GitHub Issue Tracker][issue-tracker].
Please consider if this is something [you can contribute](#contributing-a-fix-or-feature) yourself. Premake is a community project run by volunteers; the best way to get a feature built is to become a contributor!
Before opening a new request, use the search feature at the top of that page to see if it has already been requested.
- Explain the problem that you're having, and anything you've tried to solve it using the currently available features
- Explain how this new feature will help
- If possible, provide an example, like a code snippet, showing what your new feature might look like in use
Also, much of the advice in [How do I ask a good question?][how-to-ask] applies here too.
## Contributing a Fix or Feature
You've created a new fix or feature for Premake. Awesome!
1. If you haven't already, create a fork of the Premake repository
2. Create a topic branch, and make all of your changes on that branch
3. Submit a pull request; see [Writing a Good Pull Request](#writing-a-good-pull-request)
4. Give us a moment. Premake is maintained volunteers on their free time, so we might not be able to respond right away. We're working on improving our turnaround time with resources like this guide and [our OpenCollective][collective].
If you're not sure what any of that means, check out [Getting Started with GitHub](gh-start) and [Thinkful's GitHub Pull Request Tutorial](thinkful) for a complete walkthrough of the process. Gain a life skill!
Some tips...
- Don't hesitate to ask questions on the [issue tracker](issue-tracker) if you get stuck. We're always happy to help people who are trying to contribute. Help us help you help us!
- See [BUILD.txt](https://github.com/premake/premake-core/blob/master/BUILD.txt) for help getting your first build of Premake working. Be sure to run the unit tests!
- Understand exactly what needs to change in Premake's output to get the effect you want. Start by manually creating a working project script to use as a reference, either by adjusting Visual Studio project settings and inspecting the results, or by hand-editing Premake generated project files. Know exactly what you need Premake to do differently before diving in.
- Search the Premake code to find the element you want to change, or those nearby. This should turn up the right location to cut in your change, and also highlight the unit tests that cover that part of the code.
- Copy and paste one of the existing unit tests, and then modify it to match the output you're trying to achieve. If you run the tests again you should see your new test (and only your new test) fail.
- If you need to add new configuration switch(es) to support your feature, you can do that using `api.register()` in [_premake_init.lua](https://github.com/premake/premake-core/blob/master/src/_premake_init.lua).
- [Overrides and Call Arrays](https://github.com/premake/premake-core/wiki/Overrides-and-Call-Arrays) explains how and why we're organizing the code the way we are. Bonus points for converting older code (i.e. GMake and Xcode exporters) to this new and improved format.
- Once everything is working the way you like it, you're ready to submit a pull request for us to merge!
### Writing a Good Pull Request
- Stay focused on a single fix or feature. If you submit multiple changes in a single request, we may like some but spot issues with others. When that happens, we have to reject the whole thing. If you submit each change in its own request it is easier for us to review and approve.
- Limit your changes to only what is required to implement the fix or feature. In particular, avoid style or formatting tools that may modify the formatting of other areas of the code. If your code editor supports [EditorConfig](https://editorconfig.org), turn it on to use [the .editorconfig settings](https://github.com/premake/premake-core/blob/master/.editorconfig) supplied with the Premake sources.
- Write tests! You don't need to go crazy, but we will expect a unit test or two to show that your fix or feature does what it says, and doesn't break in the future. There are many test examples in Premake's source code, covering both the [modules](https://github.com/premake/premake-core/tree/master/modules) and the [core](https://github.com/premake/premake-core/tree/master/tests). Feel free to copy!
- Align [documentation](https://github.com/premake/premake-core/tree/master/website) to your changes. Keeping docs up to date is very important for all users of Premake.
- When you submit a change, try to limit the number of commits involved. A single commit is ideal.
- Follow our coding conventions, which we've intentionally kept quite minimal.
### Coding Conventions
- For symbols that will be visible to project script authors, follow the Lua all-lowercase standard for names: `dosomethingcool`. It's a terrible convention, but it helps us be consistent with Lua's core libraries. Everywhere else, use the much more readable camel case: `doSomethingCool`. (We know this is confusing, and may revisit it in a future major release.)
- Use tabs for indentation, not spaces
- Use Unix (LF) end-of-line sequence
- When in doubt, match the code that's already there
[collective]: https://opencollective.com/premake
[gh-start]: https://help.github.com/en/categories/getting-started-with-github
[git]: https://git-scm.com
[github]: https://github.com
[how-to-ask]: https://stackoverflow.com/help/how-to-ask
[issue-tracker]: https://github.com/premake/premake-core/issues
[submit-pr]: https://github.com/premake/premake-core/pulls
[thinkful]: https://www.thinkful.com/learn/github-pull-request-tutorial/

View file

@ -0,0 +1,75 @@
As the number of Premake contributors has grown, this list has become more
difficult to manage in a meaningful way. I'm leaving it here as part of the
historical records. If you find yourself in need of a list of contributors,
consider running:
git shortlog -sn
--------------------------------------------------------------------------
This file contains a list of people who've made non-trivial contributions
to Premake 5. People who commit code to the project are encouraged to
add their names here. And many thanks to those who contributed fixes and
improvements to earlier versions of Premake (feel free to add your name
in here too)!
Original design and implementation:
Jason Perkins <starkos@industriousone.com>
Main Contributors
Blizzard Entertainment (contact tvandijck@blizzard.com)
Manu Evans <https://github.com/TurkeyMan>
Sam Surtees <s.surtees@lorgames.com>
Builds and Infrastructure:
Mihai Sebea <http://twitter.com/mihai_sebea>
* Nightly binary packages
* Nightly Jenkins builds and error reports
Patch contributors:
Bastien Brunnenstein <bastien.brunnenstein@ubisoft.com>
* support wildcards in path tokens
Damien Courtois <https://github.com/dcourtois>
* module loading fixes
* bug fixes
David Ely <https://github.com/megaeels>
* symbols() API and flag deprecation
Gabi Davar <gabi.davar@discretix.com>
* added file.directory to token environment
João Matos (joao@tritao.eu)
* HTTP download support
* C# / C++/CLI language support improvements and bugfixes
* Visual Studio and Make improvements and bugfixes
* response files support for Make backend
* numerous bug fixes and smaller features
leeonix <real-like@yeah.net>
* bug fixes
Lusito <core@roughael.net>
* path.join() fixes
Mark Chandler <https://bitbucket.org/mchandler_blizzard>
* prevent self-linking
Matthew Endsley <https://github.com/mendsley>
* File matching improvements
Mark Sararu <mark.sararu@gmail.com>
* Makefile bug fixes
Mihai Sebea <http://twitter.com/mihai_sebea>
* Xcode exporter fixes and improvements
M Skibbe
* path.replaceextension()
Renaud Guillard <https://bitbucket.org/noresources>
* add library search paths argument to os.findlib()
* return command exit code from os.outputof()
* bug fixes and smaller improvements
rhuvendiek <rhuvendiek@schueco.com>
* Visual C 2010 IDL file support
Sami Kankaristo <sami@indiumgames.fi>
* Utility project support for Makefiles
tbasnoopy <tba-snoopy@gmx.de>
* customtoolnamespace()
* debuggertype()
Tim Wharton <https://github.com/moomalade>
* boostrapping scripts
* callingconvention()
* makefile environment overrides
* module loading improvements
* os.outputof() improvements

View file

@ -0,0 +1 @@
open_collective: premake

View file

@ -0,0 +1,27 @@
Copyright (c) 2003-2019 Jason Perkins and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of Premake nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,7 @@
Premake version 5.0-beta1
The following changes have been made:
* Modifications have been marked with --OpenMPT
* spectremitigations option added
* dataexecutionprevention option added
* C++20 mode for VS2022 has been added
* set sln version number to 17 for VS2022

View file

@ -0,0 +1,91 @@
<p align="center">
<a href="https://premake.github.io/" target="blank"><img src="https://premake.github.io/img/premake-logo.png" height="200" width="200" alt="Premake" /></a>
</p>
<p align="center">
<img src="https://img.shields.io/github/release/premake/premake-core/all.svg" alt="Latest release" />
<img src="https://img.shields.io/github/release-date-pre/premake/premake-core.svg" alt="Release date" />
<img src="https://img.shields.io/github/commits-since/premake/premake-core/v5.0.0-beta1.svg" alt="Commits" />
<a href="https://opensource.org/licenses/BSD-3-Clause" target="_blank">
<img src="https://img.shields.io/github/license/premake/premake-core" alt="BSD 3-Clause" />
</a>
<br/>
<a href="https://travis-ci.org/premake/premake-core" target="_blank">
<img src="https://img.shields.io/travis/premake/premake-core/master.svg?label=linux" alt="Linux" />
</a>
<a href="https://ci.appveyor.com/project/PremakeOrganization/premake-core" target="_blank">
<img src="https://img.shields.io/appveyor/ci/PremakeOrganization/premake-core?label=windows" alt="Windows" />
</a>
<a href="https://github.com/premake/premake-core/graphs/contributors" target="_blank">
<img src="https://img.shields.io/github/contributors/premake/premake-core?label=code+contributors" alt="Contributors" />
</a>
<a href="https://opencollective.com/premake" _target="blank">
<img src="https://opencollective.com/premake/all/badge.svg?label=financial+contributors" alt="Contributors" />
</a>
<a href="https://twitter.com/premakeapp" target="_blank">
<img src="https://img.shields.io/twitter/follow/premakeapp.svg?style=social&label=Follow">
</a>
</p>
# Welcome to Premake
Premake is a command line utility which reads a scripted definition of a software project, then uses it to perform build configuration tasks or generate project files for toolsets like Visual Studio, Xcode, and GNU Make. Premake's scripts are little [Lua](http://www.lua.org/) programs, so the sky's the limit!
```lua
workspace "MyWorkspace"
configurations { "Debug", "Release" }
project "MyProject"
kind "ConsoleApp"
language "C++"
files { "**.h", "**.cpp" }
filter { "configurations:Debug" }
defines { "DEBUG" }
symbols "On"
filter { "configurations:Release" }
defines { "NDEBUG" }
optimize "On"
```
## Getting Started
* [Documentation](https://github.com/premake/premake-core/wiki)
* [Contributing](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md)
* [Issue Tracker](https://github.com/premake/premake-core/issues)
## Sponsors
Premake is a BSD-licensed open source project. Our many thanks to these fine people who help us spend more time adding features and supporting the community. :tada:
Want to join them? [Learn more here](https://opencollective.com/premake). Use Premake at work? Ask your manager or marketing team about contributing too; your company logo will appear on our [website](https://premake.github.io/) and README, as well as all of our [release pages](https://github.com/premake/premake-core/releases).
### Organizations
<a href="https://opencollective.com/premake#sponsors" target="_blank"><img src="https://opencollective.com/premake/sponsors.svg?width=890&avatarHeight=92&button=false"/></a>
### Individuals
<a href="https://opencollective.com/premake#backers" target="_blank"><img src="https://opencollective.com/premake/backers.svg?width=890&button=false"/></a>
## Contributing
We love getting [pull requests](https://www.quora.com/GitHub-What-is-a-pull-request) and rely heavily on the contributions of our community to keep Premake healthy and growing. If you're new to the project, [our Contributing Guide is here](https://github.com/premake/premake-core/blob/master/CONTRIBUTING.md).
A great big thank you to all of you who have already contributed your time and know-how!
<a href="https://github.com/premake/premake-core/graphs/contributors"><img src="https://opencollective.com/premake/contributors.svg?width=890&avatarHeight=32&button=false" /></a>
## Stay in touch
* Website - https://premake.github.io
* Twitter - [@premakeapp](https://twitter.com/premakeapp)
## License
[BSD 3-Clause](https://opensource.org/licenses/BSD-3-Clause)
The Lua language and runtime library is &copy; TeCGraf, PUC-Rio.
See their website at http://www.lua.org/

View file

@ -0,0 +1,28 @@
#include "luashim.h"
static int example_test(lua_State* L)
{
lua_pushstring(L, "hello ");
lua_pushvalue(L, 1);
lua_concat(L, 2);
return 1;
}
static const luaL_Reg example_functions[] = {
{ "test", example_test },
{ NULL, NULL }
};
#ifdef _WIN32
__declspec(dllexport) int luaopen_example(lua_State *L)
#else
int luaopen_example(lua_State *L)
#endif
{
shimInitialize(L);
luaL_register(L, "example", example_functions);
return 0;
}

View file

@ -0,0 +1,28 @@
project "example"
language "C"
kind "SharedLib"
warnings "extra"
includedirs {
"../../contrib/lua/src",
"../../contrib/luashim"
}
links { 'luashim-lib' }
files
{
"*.c",
"*.lua"
}
filter "system:not windows"
targetprefix ""
targetextension ".so"
pic "on"
filter "configurations:Release"
targetdir "../../bin/release"
filter "configurations:Debug"
targetdir "../../bin/debug"

View file

@ -0,0 +1,16 @@
*.o
*.so
*.so.*
*.obj
*.lib
*.dll*
*.user
*.sdf
Lua.props
Debug
Release
*.manifest
*.swp
*.suo
x64

View file

@ -0,0 +1,54 @@
language: erlang
env:
global:
- LUAROCKS_BASE=luarocks-2.0.13
matrix:
- LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
- LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
- LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
branches:
only:
- master
before_install:
- if [ $LUA = "luajit" ]; then
sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
fi
- sudo apt-get install $LUA
- sudo apt-get install $LUA_DEV
- lua$LUA_SFX -v
# Install a recent luarocks release
- wget http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz
- tar zxvpf $LUAROCKS_BASE.tar.gz
- cd $LUAROCKS_BASE
- ./configure
--lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR"
- sudo make
- sudo make install
- cd $TRAVIS_BUILD_DIR
install:
- export DEBUG=DEBUG
- sudo -E luarocks make luasocket-scm-0.rockspec
script:
- cd test
- lua$LUA_SFX hello.lua
- lua$LUA_SFX testsrvr.lua > /dev/null &
- lua$LUA_SFX testclnt.lua
- lua$LUA_SFX stufftest.lua
- lua$LUA_SFX excepttest.lua
- lua$LUA_SFX test_bind.lua
- lua$LUA_SFX test_getaddrinfo.lua
- lua$LUA_SFX ltn12test.lua
- lua$LUA_SFX mimetest.lua
- lua$LUA_SFX urltest.lua
- lua$LUA_SFX test_socket_error.lua
notifications:
email:
on_success: change
on_failure: always

View file

@ -0,0 +1,28 @@
http was preserving old host header during redirects
fix smtp.send hang on source error
add create field to FTP and SMTP and fix HTTP ugliness
clean timeout argument to open functions in SMTP, HTTP and FTP
eliminate globals from namespaces created by module().
url.absolute was not working when base_url was already parsed
http.request was redirecting even when the location header was empty
tcp{client}:shutdown() was checking for group instead of class.
tcp{client}:send() now returns i+sent-1...
get rid of a = socket.try() in the manual, except for protected cases. replace it with assert.
get rid of "base." kludge in package.loaded
check all "require("http")" etc in the manual.
make sure sock_gethostname.* only return success if the hp is not null!
change 'l' prefix in C libraries to 'c' to avoid clash with LHF libraries
don't forget the declarations in luasocket.h and mime.h!!!
setpeername was using udp{unconnected}
fixed a bug in http.lua that caused some requests to fail (Florian Berger)
fixed a bug in select.c that prevented sockets with descriptor 0 from working (Renato Maia)
fixed a "bug" that caused dns.toip to crash under uLinux
fixed a "bug" that caused a crash in gethostbyname under VMS
DEBUG and VERSION became _DEBUG and _VERSION
send returns the right value if input is "". Alexander Marinov

View file

@ -0,0 +1,20 @@
LuaSocket 3.0 license
Copyright © 2004-2013 Diego Nehab
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.

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<LUABIN_PATH>..\build\vc12\bin\lua\5.1\</LUABIN_PATH>
<LUALIB_PATH>..\build\vc12\bin\lua\5.1\</LUALIB_PATH>
<LUAINC_PATH>..\build\vc12\include\lua\5.1\</LUAINC_PATH>
<LUALIB>lua51.lib</LUALIB>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua51</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUALIB_PATH">
<Value>$(LUALIB_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUABIN_PATH">
<Value>$(LUABIN_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC_PATH">
<Value>$(LUAINC_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
</ItemGroup>
</Project>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<LUABIN_PATH>..\build\vc12\bin\lua\5.2\</LUABIN_PATH>
<LUALIB_PATH>..\build\vc12\bin\lua\5.2\</LUALIB_PATH>
<LUAINC_PATH>..\build\vc12\include\lua\5.2\</LUAINC_PATH>
<LUALIB>lua52.lib</LUALIB>
</PropertyGroup>
<PropertyGroup>
<_PropertySheetDisplayName>Lua52</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="LUALIB_PATH">
<Value>$(LUALIB_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUABIN_PATH">
<Value>$(LUABIN_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUAINC_PATH">
<Value>$(LUAINC_PATH)</Value>
</BuildMacro>
<BuildMacro Include="LUALIB">
<Value>$(LUALIB)</Value>
</BuildMacro>
</ItemGroup>
</Project>

View file

@ -0,0 +1,44 @@
What's New
Main changes for LuaSocket 3.0-rc1 are IPv6 support and Lua 5.2 compatibility.
* Added: Compatible with Lua 5.2
- Note that unless you define LUA_COMPAT_MODULE, package
tables will not be exported as globals!
* Added: IPv6 support;
- Socket.connect and socket.bind support IPv6 addresses;
- Getpeername and getsockname support IPv6 addresses, and
return the socket family as a third value;
- URL module updated to support IPv6 host names;
- New socket.tcp6 and socket.udp6 functions;
- New socket.dns.getaddrinfo and socket.dns.getnameinfo functions;
* Added: getoption method;
* Fixed: url.unescape was returning additional values;
* Fixed: mime.qp, mime.unqp, mime.b64, and mime.unb64 could
mistaking their own stack slots for functions arguments;
* Fixed: Receiving zero-length datagram is now possible;
* Improved: Hidden all internal library symbols;
* Improved: Better error messages;
* Improved: Better documentation of socket options.
* Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
* Fixed: failure on bind() was destroying the socket (Sam Roberts);
* Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
* Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
* Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
* Fixed: manual links to home.html changed to index.html (Robert Hahn);
* Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
* Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
* Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
* Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
* Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
* Improved: Clarified tcp:receive() in the manual (MPB);
* Improved: Decent makefiles (LHF).
* Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).

View file

@ -0,0 +1,11 @@
This is the LuaSocket 3.0-rc1. It has been tested on Windows 7, Mac OS X,
and Linux.
Please use the project page at GitHub
https://github.com/diegonehab/luasocket
to file bug reports or propose changes.
Have fun,
Diego Nehab.

View file

@ -0,0 +1,81 @@
- bizarre default values for getnameinfo should throw error instead!
> It's just too bad it can't talk to gmail -
> reason 1: they absolutely want TLS
> reason 2: unlike all the other SMTP implementations, they
> don't
> tolerate missing < > around adresses
- document the new bind and connect behavior.
- shouldn't we instead make the code compatible to Lua 5.2
without any compat stuff, and use a compatibility layer to
make it work on 5.1?
- add what's new to manual
- should there be an equivalent to tohostname for IPv6?
- should we add service name resolution as well to getaddrinfo?
- Maybe the sockaddr to presentation conversion should be done with getnameinfo()?
- add http POST sample to manual
people keep asking stupid questions
- documentation of dirty/getfd/setfd is problematic because of portability
same for unix and serial.
what to do about this? add a stronger disclaimer?
- fix makefile with decent defaults?
Done:
- added IPv6 support to getsockname
- simplified getpeername implementation
- added family to return of getsockname and getpeername
and added modification to the manual to describe
- connect and bind try all adresses returned by getaddrinfo
- document headers.lua?
- update copyright date everywhere?
- remove RCSID from files?
- move version to 2.1 rather than 2.1.1?
- fixed url package to support ipv6 hosts
- changed domain to family
- implement getfamily methods.
- remove references to Lua 5.0 from documentation, add 5.2?
- update lua and luasocket version in samples in documentation
- document ipv5_v6only default option being set?
- document tcp6 and udp6
- document dns.getaddrinfo
- documented zero-sized datagram change?
no.
- document unix socket and serial socket? add raw support?
no.
- document getoption
- merge luaL_typeerror into auxiliar to avoid using luaL prefix?
replace \r\n with \0xD\0xA in everything
New mime support
ftp send should return server replies?
make sure there are no object files in the distribution tarball
http handling of 100-continue, see DB patch
DB ftp.lua bug.
test unix.c to return just a function and works with require"unix"
get rid of setmetatable(, nil) since packages don't need this anymore in 5.1
compat-5.1 novo
ajeitar pra lua-5.1
adicionar exemplos de expansão: pipe, local, named pipe
testar os options!
- Thread-unsafe functions to protect
gethostbyname(), gethostbyaddr(), gethostent(),
inet_ntoa(), strerror(),

View file

@ -0,0 +1,22 @@
... as an l-value to get all results of a function call?
at least ...[i] and #...
extend to full tuples?
__and __or __not metamethods
lua_tostring, lua_tonumber, lua_touseradta etc push values in stack
__tostring,__tonumber, __touserdata metamethods are checked
and expected to push an object of correct type on stack
lua_rawtostring, lua_rawtonumber, lua_rawtouserdata don't
push anything on stack, return data of appropriate type,
skip metamethods and throw error if object not of exact type
package.findfile exported
module not polluting the global namespace
coxpcall with a coroutine pool for efficiency (reusing coroutines)
exception mechanism formalized? just like the package system was.
a nice bitlib in the core

View file

@ -0,0 +1,183 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: DNS support">
<meta name="keywords" content="Lua, LuaSocket, DNS, Network, Library, Support">
<title>LuaSocket: DNS support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- dns ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=dns>DNS</h2>
<p>
IPv4 name resolution functions
<a href=#toip><tt>dns.toip</tt></a>
and
<a href=#tohostname><tt>dns.tohostname</tt></a>
return <em>all</em> information obtained from
the resolver in a table of the form:
</p>
<blockquote><tt>
resolved4 = {<br>
&nbsp;&nbsp;name = <i>canonic-name</i>,<br>
&nbsp;&nbsp;alias = <i>alias-list</i>,<br>
&nbsp;&nbsp;ip = <i>ip-address-list</i><br>
}
</tt> </blockquote>
<p>
Note that the <tt>alias</tt> list can be empty.
</p>
<p>
The more general name resolution function
<a href=#getaddrinfo><tt>dns.getaddrinfo</tt></a>, which
supports both IPv6 and IPv4,
returns <em>all</em> information obtained from
the resolver in a table of the form:
</p>
<blockquote><tt>
resolved6 = {<br>
&nbsp;&nbsp;[1] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;family = <i>family-name-1</i>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;addr = <i>address-1</i><br>
&nbsp;&nbsp;},<br>
&nbsp;&nbsp;...<br>
&nbsp;&nbsp;[n] = {<br>
&nbsp;&nbsp;&nbsp;&nbsp;family = <i>family-name-n</i>,<br>
&nbsp;&nbsp;&nbsp;&nbsp;addr = <i>address-n</i><br>
&nbsp;&nbsp;}<br>
}
</tt> </blockquote>
<p>
Here, <tt>family</tt> contains the string <tt>"inet"</tt> for IPv4
addresses, and <tt>"inet6"</tt> for IPv6 addresses.
</p>
<!-- getaddrinfo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=getaddrinfo>
socket.dns.<b>getaddrinfo(</b>address<b>)</b>
</p>
<p class=description>
Converts from host name to address.
</p>
<p class=parameters>
<tt>Address</tt> can be an IPv4 or IPv6 address or host name.
</p>
<p class=return>
The function returns a table with all information returned by
the resolver. In case of error, the function returns <b><tt>nil</tt></b>
followed by an error message.
</p>
<!-- gethostname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gethostname>
socket.dns.<b>gethostname()</b>
</p>
<p class=description>
Returns the standard host name for the machine as a string.
</p>
<!-- tohostname +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=tohostname>
socket.dns.<b>tohostname(</b>address<b>)</b>
</p>
<p class=description>
Converts from IPv4 address to host name.
</p>
<p class=parameters>
<tt>Address</tt> can be an IP address or host name.
</p>
<p class=return>
The function returns a string with the canonic host name of the given
<tt>address</tt>, followed by a table with all information returned by
the resolver. In case of error, the function returns <b><tt>nil</tt></b>
followed by an error message.
</p>
<!-- toip +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=toip>
socket.dns.<b>toip(</b>address<b>)</b>
</p>
<p class=description>
Converts from host name to IPv4 address.
</p>
<p class=parameters>
<tt>Address</tt> can be an IP address or host name.
</p>
<p class=return>
Returns a string with the first IP address found for <tt>address</tt>,
followed by a table with all information returned by the resolver.
In case of error, the function returns <b><tt>nil</tt></b> followed by an error
message.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:07 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,288 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: FTP support">
<meta name="keywords" content="Lua, LuaSocket, FTP, Network, Library, Support">
<title>LuaSocket: FTP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=ftp>FTP</h2>
<p>
FTP (File Transfer Protocol) is a protocol used to transfer files
between hosts. The <tt>ftp</tt> namespace offers thorough support
to FTP, under a simple interface. The implementation conforms to
<a href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</a>.
</p>
<p>
High level functions are provided supporting the most common operations.
These high level functions are implemented on top of a lower level
interface. Using the low-level interface, users can easily create their
own functions to access <em>any</em> operation supported by the FTP
protocol. For that, check the implementation.
</p>
<p>
To really benefit from this module, a good understanding of
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
LTN012, Filters sources and sinks</a> is necessary.
</p>
<p>
To obtain the <tt>ftp</tt> namespace, run:
</p>
<pre class=example>
-- loads the FTP module and any libraries it requires
local ftp = require("socket.ftp")
</pre>
<p>
URLs MUST conform to
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
</p>
<blockquote>
<tt>
[ftp://][&lt;user&gt;[:&lt;password&gt;]@]&lt;host&gt;[:&lt;port&gt;][/&lt;path&gt;][<i>type</i>=a|i]</tt>
</blockquote>
<p>
The following constants in the namespace can be set to control the default behavior of
the FTP module:
</p>
<ul>
<li> <tt>PASSWORD</tt>: default anonymous password.
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
<li> <tt>USER</tt>: default anonymous user;
</ul>
<!-- ftp.get ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=get>
ftp.<b>get(</b>url<b>)</b><br>
ftp.<b>get{</b><br>
&nbsp;&nbsp;host = <i>string</i>,<br>
&nbsp;&nbsp;sink = <i>LTN12 sink</i>,<br>
&nbsp;&nbsp;argument <i>or</i> path = <i>string</i>,<br>
&nbsp;&nbsp;[user = <i>string</i>,]<br>
&nbsp;&nbsp;[password = <i>string</i>]<br>
&nbsp;&nbsp;[command = <i>string</i>,]<br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[type = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
<p class=description>
The <tt>get</tt> function has two forms. The simple form has fixed
functionality: it downloads the contents of a URL and returns it as a
string. The generic form allows a <em>lot</em> more control, as explained
below.
</p>
<p class=parameters>
If the argument of the <tt>get</tt> function is a table, the function
expects at least the fields <tt>host</tt>, <tt>sink</tt>, and one of
<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
precedence). <tt>Host</tt> is the server to connect to. <tt>Sink</tt> is
the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink that will receive the downloaded data. <tt>Argument</tt> or
<tt>path</tt> give the target path to the resource in the server. The
optional arguments are the following:
</p>
<ul>
<li><tt>user</tt>, <tt>password</tt>: User name and password used for
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
<li><tt>command</tt>: The FTP command used to obtain data. Defaults to
"<tt>retr</tt>", but see example below;
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;
<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
"<tt>a</tt>". Defaults to whatever is the server default;
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
If successful, the simple version returns the URL contents as a
string, and the generic function returns 1. In case of error, both
functions return <b><tt>nil</tt></b> and an error message describing the
error.
</p>
<pre class=example>
-- load the ftp support
local ftp = require("socket.ftp")
-- Log as user "anonymous" on server "ftp.tecgraf.puc-rio.br",
-- and get file "lua.tar.gz" from directory "pub/lua" as binary.
f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
</pre>
<pre class=example>
-- load needed modules
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")
local url = require("socket.url")
-- a function that returns a directory listing
function nlst(u)
local t = {}
local p = url.parse(u)
p.command = "nlst"
p.sink = ltn12.sink.table(t)
local r, e = ftp.get(p)
return r and table.concat(t), e
end
</pre>
<!-- put ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=put>
ftp.<b>put(</b>url, content<b>)</b><br>
ftp.<b>put{</b><br>
&nbsp;&nbsp;host = <i>string</i>,<br>
&nbsp;&nbsp;source = <i>LTN12 sink</i>,<br>
&nbsp;&nbsp;argument <i>or</i> path = <i>string</i>,<br>
&nbsp;&nbsp;[user = <i>string</i>,]<br>
&nbsp;&nbsp;[password = <i>string</i>]<br>
&nbsp;&nbsp;[command = <i>string</i>,]<br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[type = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
<p class=description>
The <tt>put</tt> function has two forms. The simple form has fixed
functionality: it uploads a string of content into a URL. The generic form
allows a <em>lot</em> more control, as explained below.
</p>
<p class=parameters>
If the argument of the <tt>put</tt> function is a table, the function
expects at least the fields <tt>host</tt>, <tt>source</tt>, and one of
<tt>argument</tt> or <tt>path</tt> (<tt>argument</tt> takes
precedence). <tt>Host</tt> is the server to connect to. <tt>Source</tt> is
the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source that will provide the contents to be uploaded.
<tt>Argument</tt> or
<tt>path</tt> give the target path to the resource in the server. The
optional arguments are the following:
</p>
<ul>
<li><tt>user</tt>, <tt>password</tt>: User name and password used for
authentication. Defaults to "<tt>ftp:anonymous@anonymous.org</tt>";
<li><tt>command</tt>: The FTP command used to send data. Defaults to
"<tt>stor</tt>", but see example below;
<li><tt>port</tt>: The port to used for the control connection. Defaults to 21;
<li><tt>type</tt>: The transfer mode. Can take values "<tt>i</tt>" or
"<tt>a</tt>". Defaults to whatever is the server default;
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
server to the sink. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
Both functions return 1 if successful, or <b><tt>nil</tt></b> and an error
message describing the reason for failure.
</p>
<pre class=example>
-- load the ftp support
local ftp = require("socket.ftp")
-- Log as user "fulano" on server "ftp.example.com",
-- using password "silva", and store a file "README" with contents
-- "wrong password, of course"
f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README",
"wrong password, of course")
</pre>
<pre class=example>
-- load the ftp support
local ftp = require("socket.ftp")
local ltn12 = require("ltn12")
-- Log as user "fulano" on server "ftp.example.com",
-- using password "silva", and append to the remote file "LOG", sending the
-- contents of the local file "LOCAL-LOG"
f, e = ftp.put{
host = "ftp.example.com",
user = "fulano",
password = "silva",
command = "appe",
argument = "LOG",
source = ltn12.source.file(io.open("LOCAL-LOG", "r"))
}
</pre>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:18 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,335 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: HTTP support">
<meta name="keywords" content="Lua, HTTP, Library, WWW, Browser, Network, Support">
<title>LuaSocket: HTTP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="http">HTTP</h2>
<p>
HTTP (Hyper Text Transfer Protocol) is the protocol used to exchange
information between web-browsers and servers. The <tt>http</tt>
namespace offers full support for the client side of the HTTP
protocol (i.e.,
the facilities that would be used by a web-browser implementation). The
implementation conforms to the HTTP/1.1 standard,
<a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p>
<p>
The module exports functions that provide HTTP functionality in different
levels of abstraction. From the simple
string oriented requests, through generic
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> based, down to even lower-level if you bother to look through the source code.
</p>
<p>
To obtain the <tt>http</tt> namespace, run:
</p>
<pre class=example>
-- loads the HTTP module and any libraries it requires
local http = require("socket.http")
</pre>
<p>
URLs must conform to
<a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a>,
that is, an URL is a string in the form:
</p>
<blockquote>
<pre>
[http://][&lt;user&gt;[:&lt;password&gt;]@]&lt;host&gt;[:&lt;port&gt;][/&lt;path&gt;]
</pre>
</blockquote>
<p>
MIME headers are represented as a Lua table in the form:
</p>
<blockquote>
<table summary="MIME headers in Lua table">
<tr><td><tt>
headers = {<br>
&nbsp;&nbsp;field-1-name = <i>field-1-value</i>,<br>
&nbsp;&nbsp;field-2-name = <i>field-2-value</i>,<br>
&nbsp;&nbsp;field-3-name = <i>field-3-value</i>,<br>
&nbsp;&nbsp;...<br>
&nbsp;&nbsp;field-n-name = <i>field-n-value</i><br>
}
</tt></td></tr>
</table>
</blockquote>
<p>
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified.
</p>
<p class=note>
Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table.
</p>
<p>
The following constants can be set to control the default behavior of
the HTTP module:
</p>
<ul>
<li> <tt>PROXY</tt>: default proxy used for connections;
<li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
<li> <tt>USERAGENT</tt>: default user agent reported to server.
</ul>
<p class=note id="post">
Note: These constants are global. Changing them will also
change the behavior other code that might be using LuaSocket.
</p>
<!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="request">
http.<b>request(</b>url [, body]<b>)</b><br>
http.<b>request{</b><br>
&nbsp;&nbsp;url = <i>string</i>,<br>
&nbsp;&nbsp;[sink = <i>LTN12 sink</i>,]<br>
&nbsp;&nbsp;[method = <i>string</i>,]<br>
&nbsp;&nbsp;[headers = <i>header-table</i>,]<br>
&nbsp;&nbsp;[source = <i>LTN12 source</i>],<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[proxy = <i>string</i>,]<br>
&nbsp;&nbsp;[redirect = <i>boolean</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
<p class=description>
The request function has two forms. The simple form downloads
a URL using the <tt>GET</tt> or <tt>POST</tt> method and is based
on strings. The generic form performs any HTTP method and is
<a href=http://lua-users.org/wiki/FiltersSourcesAndSinks>LTN12</a> based.
</p>
<p class=parameters>
If the first argument of the <tt>request</tt> function is a string, it
should be an <tt>url</tt>. In that case, if a <tt>body</tt>
is provided as a string, the function will perform a <tt>POST</tt> method
in the <tt>url</tt>. Otherwise, it performs a <tt>GET</tt> in the
<tt>url</tt>
</p>
<p class=parameters>
If the first argument is instead a table, the most important fields are
the <tt>url</tt> and the <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>sink</tt> that will receive the downloaded content.
Any part of the <tt>url</tt> can be overridden by including
the appropriate field in the request table.
If authentication information is provided, the function
uses the Basic Authentication Scheme (see <a href="#authentication">note</a>)
to retrieve the document. If <tt>sink</tt> is <tt><b>nil</b></tt>, the
function discards the downloaded data. The optional parameters are the
following:
</p>
<ul>
<li><tt>method</tt>: The HTTP request method. Defaults to "GET";
<li><tt>headers</tt>: Any additional HTTP headers to send with the request;
<li><tt>source</tt>: <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source to provide the request body. If there
is a body, you need to provide an appropriate "<tt>content-length</tt>"
request header field, or the function will attempt to send the body as
"<tt>chunked</tt>" (something few servers support). Defaults to the empty source;
<li><tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to move data.
Defaults to the LTN12 <tt>pump.step</tt> function.
<li><tt>proxy</tt>: The URL of a proxy server to use. Defaults to no proxy;
<li><tt>redirect</tt>: Set to <tt><b>false</b></tt> to prevent the
function from automatically following 301 or 302 server redirect messages;
<li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
In case of failure, the function returns <tt><b>nil</b></tt> followed by an
error message. If successful, the simple form returns the response
body as a string, followed by the response status code, the response
headers and the response status line. The generic function returns the same
information, except the first return value is just the number 1 (the body
goes to the <tt>sink</tt>).
</p>
<p class=return>
Even when the server fails to provide the contents of the requested URL (URL not found, for example),
it usually returns a message body (a web page informing the
URL was not found or some other useless page). To make sure the
operation was successful, check the returned status <tt>code</tt>. For
a list of the possible values and their meanings, refer to <a
href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>.
</p>
<p class=description>
Here are a few examples with the simple interface:
</p>
<pre class=example>
-- load the http module
local io = require("io")
local http = require("socket.http")
local ltn12 = require("ltn12")
-- connect to server "www.cs.princeton.edu" and retrieves this manual
-- file from "~diego/professional/luasocket/http.html" and print it to stdout
http.request{
url = "http://www.cs.princeton.edu/~diego/professional/luasocket/http.html",
sink = ltn12.sink.file(io.stdout)
}
-- connect to server "www.example.com" and tries to retrieve
-- "/private/index.html". Fails because authentication is needed.
b, c, h = http.request("http://www.example.com/private/index.html")
-- b returns some useless page telling about the denied access,
-- h returns authentication information
-- and c returns with value 401 (Authentication Required)
-- tries to connect to server "wrong.host" to retrieve "/"
-- and fails because the host does not exist.
r, e = http.request("http://wrong.host/")
-- r is nil, and e returns with value "host not found"
</pre>
<p class=description>
And here is an example using the generic interface:
</p>
<pre class=example>
-- load the http module
http = require("socket.http")
-- Requests information about a document, without downloading it.
-- Useful, for example, if you want to display a download gauge and need
-- to know the size of the document in advance
r, c, h = http.request {
method = "HEAD",
url = "http://www.tecgraf.puc-rio.br/~diego"
}
-- r is 1, c is 200, and h would return the following headers:
-- h = {
-- date = "Tue, 18 Sep 2001 20:42:21 GMT",
-- server = "Apache/1.3.12 (Unix) (Red Hat/Linux)",
-- ["last-modified"] = "Wed, 05 Sep 2001 06:11:20 GMT",
-- ["content-length"] = 15652,
-- ["connection"] = "close",
-- ["content-Type"] = "text/html"
-- }
</pre>
<p class=note id="post">
Note: When sending a POST request, simple interface adds a
"<tt>Content-type: application/x-www-form-urlencoded</tt>"
header to the request. This is the type used by
HTML forms. If you need another type, use the generic
interface.
</p>
<p class=note id="authentication">
Note: Some URLs are protected by their
servers from anonymous download. For those URLs, the server must receive
some sort of authentication along with the request or it will deny
download and return status "401&nbsp;Authentication Required".
</p>
<p class=note>
The HTTP/1.1 standard defines two authentication methods: the Basic
Authentication Scheme and the Digest Authentication Scheme, both
explained in detail in
<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC 2068</a>.
</p>
<p class=note>The Basic Authentication Scheme sends
<tt>&lt;user&gt;</tt> and
<tt>&lt;password&gt;</tt> unencrypted to the server and is therefore
considered unsafe. Unfortunately, by the time of this implementation,
the wide majority of servers and browsers support the Basic Scheme only.
Therefore, this is the method used by the toolkit whenever
authentication is required.
</p>
<pre class=example>
-- load required modules
http = require("socket.http")
mime = require("mime")
-- Connect to server "www.example.com" and tries to retrieve
-- "/private/index.html", using the provided name and password to
-- authenticate the request
b, c, h = http.request("http://fulano:silva@www.example.com/private/index.html")
-- Alternatively, one could fill the appropriate header and authenticate
-- the request directly.
r, c = http.request {
url = "http://www.example.com/private/index.html",
headers = { authorization = "Basic " .. (mime.b64("fulano:silva")) }
}
</pre>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:26 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,215 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="The LuaSocket Homepage">
<meta name="keywords" content="Lua, LuaSocket, Network, Library, Support, Internet">
<title>LuaSocket: Network support for the Lua language </title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- whatis +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=whatis>What is LuaSocket?</h2>
<p>
LuaSocket is a <a href="http://www.lua.org">Lua</a> extension library
that is composed by two parts: a C core that provides support for the TCP
and UDP transport layers, and a set of Lua modules that add support for
functionality commonly needed by applications that deal with the Internet.
</p>
<p>
The core support has been implemented so that it is both efficient and
simple to use. It is available to any Lua application once it has been
properly initialized by the interpreter in use. The code has been tested
and runs well on several Windows and UNIX platforms. </p>
<p>
Among the support modules, the most commonly used implement the
<a href=smtp.html>SMTP</a>
(sending e-mails),
<a href=http.html>HTTP</a>
(WWW access) and
<a href=ftp.html>FTP</a>
(uploading and downloading files) client
protocols. These provide a very natural and generic interface to the
functionality defined by each protocol.
In addition, you will find that the
<a href=mime.html>MIME</a> (common encodings),
<a href=url.html>URL</a>
(anything you could possible want to do with one) and
<a href=ltn12.html>LTN12</a>
(filters, sinks, sources and pumps) modules can be very handy.
</p>
<p>
The library is available under the same
<a href="http://www.lua.org/copyright.html">
terms and conditions</a> as the Lua language, the MIT license. The idea is
that if you can use Lua in a project, you should also be able to use
LuaSocket.
</p>
<p>
Copyright &copy; 1999-2013 Diego Nehab. All rights reserved. <br>
Author: <A href="http://www.impa.br/~diego">Diego Nehab</a>
</p>
<!-- download +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=download>Download</h2>
<p>
LuaSocket version 3.0-rc1 is now available for download!
It is compatible with Lua&nbsp;5.1 and 5.2, and has
been tested on Windows&nbsp;XP, Linux, and Mac OS X. Chances
are it works well on most UNIX distributions and Windows flavors.
</p>
<p>
The current version of the library can be found at
the <a href="https://github.com/diegonehab/luasocket">LuaSocket
project page</a> on GitHub. Besides the full C and Lua source code
for the library, the distribution contains several examples,
this user's manual and basic test procedures.
</p>
<p> Take a look at the <a
href=installation.html>installation</a> section of the
manual to find out how to properly install the library.
</p>
<!-- thanks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=thanks>Special thanks</h2>
<p>
This marks the first release of LuaSocket that
wholeheartedly embraces the open-source development
philosophy. After a long hiatus, Matthew Wild finally
convinced me it was time for a release including IPv6 and
Lua 5.2 support. It was more work than we anticipated.
Special thanks to Sam Roberts, Florian Zeitz, and Paul
Aurich, Liam Devine, Alexey Melnichuk, and everybody else
that has helped bring this library back to life.
</p>
<!-- whatsnew +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=new>What's New</h2>
<p>
Main changes for LuaSocket&nbsp;3.0-rc1 are IPv6 support
and Lua&nbsp;5.2 compatibility.
</p>
<ul>
<li> Added: Compatible with Lua&nbsp;5.2
<ul>
<li> Note that unless you define <tt>LUA_COMPAT_MODULE</tt>,
package tables will <em>not</em> be exported as globals!
</ul>
<li> Added: IPv6 support;
<ul>
<li> <tt>Socket.connect</tt> and <tt>socket.bind</tt> support IPv6 addresses;
<li> <tt>Getpeername</tt> and <tt>getsockname</tt> support
IPv6 addresses, and return the socket family as a third value;
<li> URL module updated to support IPv6 host names;
<li> New <tt>socket.tcp6</tt> and <tt>socket.udp6</tt> functions;
<li> New <tt>socket.dns.getaddrinfo</tt> and
<tt>socket.dns.getnameinfo</tt> functions;
</ul>
<li> Added: <tt>getoption</tt> method;
<li> Fixed: <tt>url.unescape</tt> was returning additional values;
<li> Fixed: <tt>mime.qp</tt>, <tt>mime.unqp</tt>,
<tt>mime.b64</tt>, and <tt>mime.unb64</tt> could
mistaking their own stack slots for functions arguments;
<li> Fixed: Receiving zero-length datagram is now possible;
<li> Improved: Hidden all internal library symbols;
<li> Improved: Better error messages;
<li> Improved: Better documentation of socket options.
<li> Fixed: manual sample of HTTP authentication now uses correct
"authorization" header (Alexandre Ittner);
<li> Fixed: failure on bind() was destroying the socket (Sam Roberts);
<li> Fixed: receive() returns immediatelly if prefix can satisfy
bytes requested (M Joonas Pihlaja);
<li> Fixed: multicast didn't work on Windows, or anywhere
else for that matter (Herbert Leuwer, Adrian Sietsma);
<li> Fixed: select() now reports an error when called with more
sockets than FD_SETSIZE (Lorenzo Leonini);
<li> Fixed: manual links to home.html changed to index.html
(Robert Hahn);
<li> Fixed: mime.unb64() would return an empty string on results that started
with a null character (Robert Raschke);
<li> Fixed: HTTP now automatically redirects on 303 and 307 (Jonathan Gray);
<li> Fixed: calling sleep() with negative numbers could
block forever, wasting CPU. Now it returns immediately (MPB);
<li> Improved: FTP commands are now sent in upper case to
help buggy servers (Anders Eurenius);
<li> Improved: known headers now sent in canonic
capitalization to help buggy servers (Joseph Stewart);
<li> Improved: Clarified tcp:receive() in the manual (MPB);
<li> Improved: Decent makefiles (LHF).
<li> Fixed: RFC links in documentation now point to IETF (Cosmin Apreutesei).
</ul>
<!-- old ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=old>Old Versions</h2>
<p>
All previous versions of the LuaSocket library can be downloaded <a
href="http://www.impa.br/~diego/software/luasocket/old">
here</a>. Although these versions are no longer supported, they are
still available for those that have compatibility issues.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Tue Jun 11 18:50:23 HKT 2013
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,127 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: Introduction to the core">
<meta name="keywords" content="Lua, LuaSocket, TCP, UDP, Network, Support,
Installation">
<title>LuaSocket: Installation</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- installation ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2>Installation</h2>
<p> Here we describe the standard distribution. If the
standard doesn't meet your needs, we refer you to the Lua
discussion list, where any question about the package scheme
will likely already have been answered. </p>
<h3>Directory structure</h3>
<p> On Unix systems, the standard distribution uses two base
directories, one for system dependent files, and another for system
independent files. Let's call these directories <tt>&lt;CDIR&gt;</tt>
and <tt>&lt;LDIR&gt;</tt>, respectively.
For example, in my laptp, Lua&nbsp;5.1 is configured to
use '<tt>/usr/local/lib/lua/5.1</tt>' for
<tt>&lt;CDIR&gt;</tt> and '<tt>/usr/local/share/lua/5.1</tt>' for
<tt>&lt;LDIR&gt;</tt>. On Windows, <tt>&lt;CDIR&gt;</tt>
usually points to the directory where the Lua executable is
found, and <tt>&lt;LDIR&gt;</tt> points to a
<tt>lua/</tt> directory inside <tt>&lt;CDIR&gt;</tt>. (These
settings can be overridden by environment variables
<tt>LUA_PATH</tt> and <tt>LUA_CPATH</tt>. See the Lua
documentation for details.) Here is the standard LuaSocket
distribution directory structure:</p>
<pre class=example>
&lt;LDIR&gt;/ltn12.lua
&lt;LDIR&gt;/socket.lua
&lt;CDIR&gt;/socket/core.dll
&lt;LDIR&gt;/socket/http.lua
&lt;LDIR&gt;/socket/tp.lua
&lt;LDIR&gt;/socket/ftp.lua
&lt;LDIR&gt;/socket/smtp.lua
&lt;LDIR&gt;/socket/url.lua
&lt;LDIR&gt;/mime.lua
&lt;CDIR&gt;/mime/core.dll
</pre>
<p> Naturally, on Unix systems, <tt>core.dll</tt>
would be replaced by <tt>core.so</tt>.
</p>
<h3>Using LuaSocket</h3>
<p> With the above setup, and an interpreter with shared library support,
it should be easy to use LuaSocket. Just fire the interpreter and use the
<tt>require</tt> function to gain access to whatever module you need:</p>
<pre class=example>
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; socket = require("socket")
&gt; print(socket._VERSION)
--&gt; LuaSocket 3.0-rc1
</pre>
<p> Each module loads their dependencies automatically, so you only need to
load the modules you directly depend upon: </p>
<pre class=example>
Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
&gt; http = require("socket.http")
&gt; print(http.request("http://www.impa.br/~diego/software/luasocket"))
--&gt; homepage gets dumped to terminal
</pre>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Tue Jun 11 19:06:14 HKT 2013
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,333 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: Introduction to the core">
<meta name="keywords" content="Lua, LuaSocket, TCP, UDP, Network,
Library, Support">
<title>LuaSocket: Introduction to the core</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- introduction +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2>Introduction</h2>
<p>
LuaSocket is a <a href="http://www.lua.org">Lua</a> extension library
that is composed by two parts: a C core that provides support for the TCP
and UDP transport layers, and a set of Lua modules that add support for
the SMTP (sending e-mails), HTTP (WWW access) and FTP (uploading and
downloading files) protocols and other functionality commonly needed by
applications that deal with the Internet. This introduction is about the C
core.
</p>
<p>
Communication in LuaSocket is performed via I/O objects. These can
represent different network domains. Currently, support is provided for TCP
and UDP, but nothing prevents other developers from implementing SSL, Local
Domain, Pipes, File Descriptors etc. I/O objects provide a standard
interface to I/O across different domains and operating systems.
</p>
<p>
The API design had two goals in mind. First, users
experienced with the C API to sockets should feel comfortable using LuaSocket.
Second, the simplicity and the feel of the Lua language should be
preserved. To achieve these goals, the LuaSocket API keeps the function names and semantics the C API whenever possible, but their usage in Lua has been greatly simplified.
</p>
<p>
One of the simplifications is the receive pattern capability.
Applications can read data from stream domains (such as TCP)
line by line, block by block, or until the connection is closed.
All I/O reads are buffered and the performance differences between
different receive patterns are negligible.
</p>
<p>
Another advantage is the flexible timeout control
mechanism. As in C, all I/O operations are blocking by default. For
example, the <a href=tcp.html#send><tt>send</tt></a>,
<a href=tcp.html#receive><tt>receive</tt></a> and
<a href=tcp.html#accept><tt>accept</tt></a> methods
of the TCP domain will block the caller application until
the operation is completed (if ever!). However, with a call to the
<a href=tcp.html#settimeout><tt>settimeout</tt></a>
method, an application can specify upper limits on
the time it can be blocked by LuaSocket (the "<tt>total</tt>" timeout), on
the time LuaSocket can internally be blocked by any OS call (the
"<tt>block</tt>" timeout) or a combination of the two. Each LuaSocket
call might perform several OS calls, so that the two timeout values are
<em>not</em> equivalent.
</p>
<p>
Finally, the host name resolution is transparent, meaning that most
functions and methods accept both IP addresses and host names. In case a
host name is given, the library queries the system's resolver and
tries the main IP address returned. Note that direct use of IP addresses
is more efficient, of course. The
<a href=dns.html#toip><tt>toip</tt></a>
and <a href=dns.html#tohostname><tt>tohostname</tt></a>
functions from the DNS module are provided to convert between host names and IP addresses.
</p>
<p>
Together, these changes make network programming in LuaSocket much simpler
than it is in C, as the following sections will show.
</p>
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=tcp>TCP</h3>
<p>
TCP (Transfer Control Protocol) is reliable stream protocol. In other
words, applications communicating through TCP can send and receive data as
an error free stream of bytes. Data is split in one end and
reassembled transparently on the other end. There are no boundaries in
the data transfers. The library allows users to read data from the
sockets in several different granularities: patterns are available for
lines, arbitrary sized blocks or "read up to connection closed", all with
good performance.
</p>
<p>
The library distinguishes three types of TCP sockets: <em>master</em>,
<em>client</em> and <em>server</em> sockets.
</p>
<p>
Master sockets are newly created TCP sockets returned by the function
<a href=tcp.html#tcp><tt>socket.tcp</tt></a>. A master socket is
transformed into a server socket
after it is associated with a <em>local</em> address by a call to the
<a href=tcp.html#bind><tt>bind</tt></a> method followed by a call to the
<a href=tcp.html#listen><tt>listen</tt></a>. Conversely, a master socket
can be changed into a client socket with the method
<a href=tcp.html#connect><tt>connect</tt></a>,
which associates it with a <em>remote</em> address.
</p>
<p>
On server sockets, applications can use the
<a href=tcp.html#accept><tt>accept</tt></a> method
to wait for a client connection. Once a connection is established, a
client socket object is returned representing this connection. The
other methods available for server socket objects are
<a href=tcp.html#getsockname><tt>getsockname</tt></a>,
<a href=tcp.html#setoption><tt>setoption</tt></a>,
<a href=tcp.html#settimeout><tt>settimeout</tt></a>, and
<a href=tcp.html#close><tt>close</tt></a>.
</p>
<p>
Client sockets are used to exchange data between two applications over
the Internet. Applications can call the methods
<a href=tcp.html#send><tt>send</tt></a> and
<a href=tcp.html#receive><tt>receive</tt></a>
to send and receive data. The other methods
available for client socket objects are
<a href=tcp.html#getsockname><tt>getsockname</tt></a>,
<a href=tcp.html#getpeername><tt>getpeername</tt></a>,
<a href=tcp.html#setoption><tt>setoption</tt></a>,
<a href=tcp.html#settimeout><tt>settimeout</tt></a>,
<a href=tcp.html#shutdown><tt>shutdown</tt></a>, and
<a href=tcp.html#close><tt>close</tt></a>.
</p>
<p>
Example:
</p>
<blockquote>
<p>
A simple echo server, using LuaSocket. The program binds to an ephemeral
port (one that is chosen by the operating system) on the local host and
awaits client connections on that port. When a connection is established,
the program reads a line from the remote end and sends it back, closing
the connection immediately. You can test it using the telnet
program.
</p>
<pre class=example>
-- load namespace
local socket = require("socket")
-- create a TCP socket and bind it to the local host, at any port
local server = assert(socket.bind("*", 0))
-- find out which port the OS chose for us
local ip, port = server:getsockname()
-- print a message informing what's up
print("Please telnet to localhost on port " .. port)
print("After connecting, you have 10s to enter a line to be echoed")
-- loop forever waiting for clients
while 1 do
-- wait for a connection from any client
local client = server:accept()
-- make sure we don't block waiting for this client's line
client:settimeout(10)
-- receive the line
local line, err = client:receive()
-- if there was no error, send it back to the client
if not err then client:send(line .. "\n") end
-- done with client, close the object
client:close()
end
</pre>
</blockquote>
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=udp>UDP</h3>
<p>
UDP (User Datagram Protocol) is a non-reliable datagram protocol. In
other words, applications communicating through UDP send and receive
data as independent blocks, which are not guaranteed to reach the other
end. Even when they do reach the other end, they are not guaranteed to be
error free. Data transfers are atomic, one datagram at a time. Reading
only part of a datagram discards the rest, so that the following read
operation will act on the next datagram. The advantages are in
simplicity (no connection setup) and performance (no error checking or
error correction).
</p>
<p>
Note that although no guarantees are made, these days
networks are so good that, under normal circumstances, few errors
happen in practice.
</p>
<p>
An UDP socket object is created by the
<a href=udp.html#udp><tt>socket.udp</tt></a> function. UDP
sockets do not need to be connected before use. The method
<a href=udp.html#sendto><tt>sendto</tt></a>
can be used immediately after creation to
send a datagram to IP address and port. Host names are not allowed
because performing name resolution for each packet would be forbiddingly
slow. Methods
<a href=udp.html#receive><tt>receive</tt></a> and
<a href=udp.html#receivefrom><tt>receivefrom</tt></a>
can be used to retrieve datagrams, the latter returning the IP and port of
the sender as extra return values (thus being slightly less
efficient).
</p>
<p>
When communication is performed repeatedly with a single peer, an
application should call the
<a href=udp.html#setpeername><tt>setpeername</tt></a> method to specify a
permanent partner. Methods
<a href=udp.html#sendto><tt>sendto</tt></a> and
<a href=udp.html#receivefrom><tt>receivefrom</tt></a>
can no longer be used, but the method
<a href=udp.html#send><tt>send</tt></a> can be used to send data
directly to the peer, and the method
<a href=udp.html#receive><tt>receive</tt></a>
will only return datagrams originating
from that peer. There is about 30% performance gain due to this practice.
</p>
<p>
To associate an UDP socket with a local address, an application calls the
<a href=udp.html#setsockname><tt>setsockname</tt></a>
method <em>before</em> sending any datagrams. Otherwise, the socket is
automatically bound to an ephemeral address before the first data
transmission and once bound the local address cannot be changed.
The other methods available for UDP sockets are
<a href=udp.html#getpeername><tt>getpeername</tt></a>,
<a href=udp.html#getsockname><tt>getsockname</tt></a>,
<a href=udp.html#settimeout><tt>settimeout</tt></a>,
<a href=udp.html#setoption><tt>setoption</tt></a> and
<a href=udp.html#close><tt>close</tt></a>.
</p>
<p>
Example:
</p>
<blockquote>
<p>
A simple daytime client, using LuaSocket. The program connects to a remote
server and tries to retrieve the daytime, printing the answer it got or an
error message.
</p>
<pre class=example>
-- change here to the host an port you want to contact
local host, port = "localhost", 13
-- load namespace
local socket = require("socket")
-- convert host name to ip address
local ip = assert(socket.dns.toip(host))
-- create a new UDP object
local udp = assert(socket.udp())
-- contact daytime host
assert(udp:sendto("anything", ip, port))
-- retrieve the answer and print results
io.write(assert(udp:receive()))
</pre>
</blockquote>
<!-- More +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=more>Support modules</h3>
<p> Although not covered in the introduction, LuaSocket offers
much more than TCP and UDP functionality. As the library
evolved, support for <a href=http.html>HTTP</a>, <a href=ftp.html>FTP</a>,
and <a href=smtp.html>SMTP</a> were built on top of these. These modules
and many others are covered by the <a href=reference.html>reference manual</a>.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:36 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,430 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: LTN12 support">
<meta name="keywords" content="Lua, LuaSocket, Filters, Source, Sink,
Pump, Support, Library">
<title>LuaSocket: LTN12 module</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- ltn12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=ltn12>LTN12</h2>
<p> The <tt>ltn12</tt> namespace implements the ideas described in
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
LTN012, Filters sources and sinks</a>. This manual simply describes the
functions. Please refer to the LTN for a deeper explanation of the
functionality provided by this module.
</p>
<p>
To obtain the <tt>ltn12</tt> namespace, run:
</p>
<pre class=example>
-- loads the LTN21 module
local ltn12 = require("ltn12")
</pre>
<!-- filters ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id="filter">Filters</h3>
<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="filter.chain">
ltn12.filter.<b>chain(</b>filter<sub>1</sub>, filter<sub>2</sub>
[, ... filter<sub>N</sub>]<b>)</b>
</p>
<p class=description>
Returns a filter that passes all data it receives through each of a
series of given filters.
</p>
<p class=parameters>
<tt>Filter<sub>1</sub></tt> to <tt>filter<sub>N</sub></tt> are simple
filters.
</p>
<p class=return>
The function returns the chained filter.
</p>
<p class=note>
The nesting of filters can be arbitrary. For instance, the useless filter
below doesn't do anything but return the data that was passed to it,
unaltered.
</p>
<pre class=example>
-- load required modules
local ltn12 = require("ltn12")
local mime = require("mime")
-- create a silly identity filter
id = ltn12.filter.chain(
mime.encode("quoted-printable"),
mime.encode("base64"),
mime.decode("base64"),
mime.decode("quoted-printable")
)
</pre>
<!-- cycle ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="filter.cycle">
ltn12.filter.<b>cycle(</b>low [, ctx, extra]<b>)</b>
</p>
<p class=description>
Returns a high-level filter that cycles though a low-level filter by
passing it each chunk and updating a context between calls.
</p>
<p class=parameters>
<tt>Low</tt> is the low-level filter to be cycled,
<tt>ctx</tt> is the initial context and <tt>extra</tt> is any extra
argument the low-level filter might take.
</p>
<p class=return>
The function returns the high-level filter.
</p>
<pre class=example>
-- load the ltn12 module
local ltn12 = require("ltn12")
-- the base64 mime filter factory
encodet['base64'] = function()
return ltn12.filter.cycle(b64, "")
end
</pre>
<!-- pumps ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id="pump">Pumps</h3>
<!-- all ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="pump.all">
ltn12.pump.<b>all(</b>source, sink<b>)</b>
</p>
<p class=description>
Pumps <em>all</em> data from a <tt>source</tt> to a <tt>sink</tt>.
</p>
<p class=return>
If successful, the function returns a value that evaluates to
<b><tt>true</tt></b>. In case
of error, the function returns a <b><tt>false</tt></b> value, followed by an error message.
</p>
<!-- step +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="pump.step">
ltn12.pump.<b>step(</b>source, sink<b>)</b>
</p>
<p class=description>
Pumps <em>one</em> chunk of data from a <tt>source</tt> to a <tt>sink</tt>.
</p>
<p class=return>
If successful, the function returns a value that evaluates to
<b><tt>true</tt></b>. In case
of error, the function returns a <b><tt>false</tt></b> value, followed by an error message.
</p>
<!-- sinks ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id="sink">Sinks</h3>
<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.chain">
ltn12.sink.<b>chain(</b>filter, sink<b>)</b>
</p>
<p class=description>
Creates and returns a new sink that passes data through a <tt>filter</tt> before sending it to a given <tt>sink</tt>.
</p>
<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.error">
ltn12.sink.<b>error(</b>message<b>)</b>
</p>
<p class=description>
Creates and returns a sink that aborts transmission with the error
<tt>message</tt>.
</p>
<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.file">
ltn12.sink.<b>file(</b>handle, message<b>)</b>
</p>
<p class=description>
Creates a sink that sends data to a file.
</p>
<p class=parameters>
<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
<tt>message</tt> should give the reason for failure.
</p>
<p class=return>
The function returns a sink that sends all data to the given <tt>handle</tt>
and closes the file when done, or a sink that aborts the transmission with
the error <tt>message</tt>
</p>
<p class=note>
In the following example, notice how the prototype is designed to
fit nicely with the <tt>io.open</tt> function.
</p>
<pre class=example>
-- load the ltn12 module
local ltn12 = require("ltn12")
-- copy a file
ltn12.pump.all(
ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png", "wb"))
)
</pre>
<!-- null +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.null">
ltn12.sink.<b>null()</b>
</p>
<p class=description>
Returns a sink that ignores all data it receives.
</p>
<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.simplify">
ltn12.sink.<b>simplify(</b>sink<b>)</b>
</p>
<p class=description>
Creates and returns a simple sink given a fancy <tt>sink</tt>.
</p>
<!-- table ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="sink.table">
ltn12.sink.<b>table(</b>[table]<b>)</b>
</p>
<p class=description>
Creates a sink that stores all chunks in a table. The chunks can later be
efficiently concatenated into a single string.
</p>
<p class=parameters>
<tt>Table</tt> is used to hold the chunks. If
<tt><b>nil</b></tt>, the function creates its own table.
</p>
<p class=return>
The function returns the sink and the table used to store the chunks.
</p>
<pre class=example>
-- load needed modules
local http = require("socket.http")
local ltn12 = require("ltn12")
-- a simplified http.get function
function http.get(u)
local t = {}
local respt = request{
url = u,
sink = ltn12.sink.table(t)
}
return table.concat(t), respt.headers, respt.code
end
</pre>
<!-- sinks ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id="source">Sources</h3>
<!-- cat ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.cat">
ltn12.source.<b>cat(</b>source<sub>1</sub> [, source<sub>2</sub>, ...,
source<sub>N</sub>]<b>)</b>
</p>
<p class=description>
Creates a new source that produces the concatenation of the data produced
by a number of sources.
</p>
<p class=parameters>
<tt>Source<sub>1</sub></tt> to <tt>source<sub>N</sub></tt> are the original
sources.
</p>
<p class=return>
The function returns the new source.
</p>
<!-- chain ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.chain">
ltn12.source.<b>chain(</b>source, filter<b>)</b>
</p>
<p class=description>
Creates a new <tt>source</tt> that passes data through a <tt>filter</tt>
before returning it.
</p>
<p class=return>
The function returns the new source.
</p>
<!-- empty ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.empty">
ltn12.source.<b>empty()</b>
</p>
<p class=description>
Creates and returns an empty source.
</p>
<!-- error ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.error">
ltn12.source.<b>error(</b>message<b>)</b>
</p>
<p class=description>
Creates and returns a source that aborts transmission with the error
<tt>message</tt>.
</p>
<!-- file +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.file">
ltn12.source.<b>file(</b>handle, message<b>)</b>
</p>
<p class=description>
Creates a source that produces the contents of a file.
</p>
<p class=parameters>
<tt>Handle</tt> is a file handle. If <tt>handle</tt> is <tt><b>nil</b></tt>,
<tt>message</tt> should give the reason for failure.
</p>
<p class=return>
The function returns a source that reads chunks of data from
given <tt>handle</tt> and returns it to the user,
closing the file when done, or a source that aborts the transmission with
the error <tt>message</tt>
</p>
<p class=note>
In the following example, notice how the prototype is designed to
fit nicely with the <tt>io.open</tt> function.
</p>
<pre class=example>
-- load the ltn12 module
local ltn12 = require("ltn12")
-- copy a file
ltn12.pump.all(
ltn12.source.file(io.open("original.png", "rb")),
ltn12.sink.file(io.open("copy.png", "wb"))
)
</pre>
<!-- simplify +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.simplify">
ltn12.source.<b>simplify(</b>source<b>)</b>
</p>
<p class=description>
Creates and returns a simple source given a fancy <tt>source</tt>.
</p>
<!-- string +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="source.string">
ltn12.source.<b>string(</b>string<b>)</b>
</p>
<p class=description>
Creates and returns a source that produces the contents of a
<tt>string</tt>, chunk by chunk.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:41 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,477 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: MIME support">
<meta name="keywords" content="Lua, LuaSocket, MIME, Library, Support">
<title>LuaSocket: MIME module</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=mime>MIME</h2>
<p>
The <tt>mime</tt> namespace offers filters that apply and remove common
content transfer encodings, such as Base64 and Quoted-Printable.
It also provides functions to break text into lines and change
the end-of-line convention.
MIME is described mainly in
<a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
<a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>,
<a href="http://www.ietf.org/rfc/rfc2047.txt">2047</a>,
<a href="http://www.ietf.org/rfc/rfc2047.txt">2048</a>, and
<a href="http://www.ietf.org/rfc/rfc2048.txt">2049</a>.
</p>
<p>
All functionality provided by the MIME module
follows the ideas presented in
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">
LTN012, Filters sources and sinks</a>.
</p>
<p>
To obtain the <tt>mime</tt> namespace, run:
</p>
<pre class=example>
-- loads the MIME module and everything it requires
local mime = require("mime")
</pre>
<!-- High-level +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=high>High-level filters</h3>
<!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="decode">
mime.<b>decode(</b>"base64"<b>)</b><br>
mime.<b>decode(</b>"quoted-printable"<b>)</b>
</p>
<p class=description>
Returns a filter that decodes data from a given transfer content
encoding.
</p>
<!-- encode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="encode">
mime.<b>encode(</b>"base64"<b>)</b><br>
mime.<b>encode(</b>"quoted-printable" [, mode]<b>)</b>
</p>
<p class=description>
Returns a filter that encodes data according to a given transfer content
encoding.
</p>
<p class=parameters>
In the Quoted-Printable case, the user can specify whether the data is
textual or binary, by passing the <tt>mode</tt> strings "<tt>text</tt>" or
"<tt>binary</tt>". <tt>Mode</tt> defaults to "<tt>text</tt>".
</p>
<p class=note>
Although both transfer content encodings specify a limit for the line
length, the encoding filters do <em>not</em> break text into lines (for
added flexibility).
Below is a filter that converts binary data to the Base64 transfer content
encoding and breaks it into lines of the correct size.
</p>
<pre class=example>
base64 = ltn12.filter.chain(
mime.encode("base64"),
mime.wrap("base64")
)
</pre>
<p class=note>
Note: Text data <em>has</em> to be converted to canonic form
<em>before</em> being encoded.
</p>
<pre class=example>
base64 = ltn12.filter.chain(
mime.normalize(),
mime.encode("base64"),
mime.wrap("base64")
)
</pre>
<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="normalize">
mime.<b>normalize(</b>[marker]<b>)</b>
</p>
<p class=description>
Converts most common end-of-line markers to a specific given marker.
</p>
<p class=parameters>
<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic
end-of-line marker defined by the MIME standard.
</p>
<p class=return>
The function returns a filter that performs the conversion.
</p>
<p class=note>
Note: There is no perfect solution to this problem. Different end-of-line
markers are an evil that will probably plague developers forever.
This function, however, will work perfectly for text created with any of
the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF),
or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
markers, the function will still work well, although it doesn't
guarantee that the number of empty lines will be correct.
</p>
<!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="stuff">
mime.<b>stuff()</b><br>
</p>
<p class=description>
Creates and returns a filter that performs stuffing of SMTP messages.
</p>
<p class=note>
Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to chain it with your
source, or apply it to your message body.
</p>
<!-- wrap +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="wrap">
mime.<b>wrap(</b>"text" [, length]<b>)</b><br>
mime.<b>wrap(</b>"base64"<b>)</b><br>
mime.<b>wrap(</b>"quoted-printable"<b>)</b>
</p>
<p class=description>
Returns a filter that breaks data into lines.
</p>
<p class=parameters>
The "<tt>text</tt>" line-wrap filter simply breaks text into lines by
inserting CRLF end-of-line markers at appropriate positions.
<tt>Length</tt> defaults 76.
The "<tt>base64</tt>" line-wrap filter works just like the default
"<tt>text</tt>" line-wrap filter with default length.
The function can also wrap "<tt>quoted-printable</tt>" lines, taking care
not to break lines in the middle of an escaped character. In that case, the
line length is fixed at 76.
</p>
<p class=note>
For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following:
</p>
<pre class=example>
qp = ltn12.filter.chain(
mime.normalize(),
mime.encode("quoted-printable"),
mime.wrap("quoted-printable")
)
</pre>
<p class=note>
Note: To break into lines with a different end-of-line convention, apply
a normalization filter after the line break filter.
</p>
<!-- Low-level ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h3 id=low>Low-level filters</h3>
<!-- b64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="b64">
A, B = mime.<b>b64(</b>C [, D]<b>)</b>
</p>
<p class=description>
Low-level filter to perform Base64 encoding.
</p>
<p class=description>
<tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> encoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>.
</p>
<p class=note>
Note: The simplest use of this function is to encode a string into it's
Base64 transfer content encoding. Notice the extra parenthesis around the
call to <tt>mime.b64</tt>, to discard the second return value.
</p>
<pre class=example>
print((mime.b64("diego:password")))
--&gt; ZGllZ286cGFzc3dvcmQ=
</pre>
<!-- dot +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dot">
A, n = mime.<b>dot(</b>m [, B]<b>)</b>
</p>
<p class=description>
Low-level filter to perform SMTP stuffing and enable transmission of
messages containing the sequence "CRLF.CRLF".
</p>
<p class=parameters>
<tt>A</tt> is the stuffed version of <tt>B</tt>. '<tt>n</tt>' gives the
number of characters from the sequence CRLF seen in the end of <tt>B</tt>.
'<tt>m</tt>' should tell the same, but for the previous chunk.
</p>
<p class=note>Note: The message body is defined to begin with
an implicit CRLF. Therefore, to stuff a message correctly, the
first <tt>m</tt> should have the value 2.
</p>
<pre class=example>
print((string.gsub(mime.dot(2, ".\r\nStuffing the message.\r\n.\r\n."), "\r\n", "\\n")))
--&gt; ..\nStuffing the message.\n..\n..
</pre>
<p class=note>
Note: The <a href=smtp.html#send><tt>smtp.send</tt></a> function
uses this filter automatically. You don't need to
apply it again.
</p>
<!-- eol ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="eol">
A, B = mime.<b>eol(</b>C [, D, marker]<b>)</b>
</p>
<p class=description>
Low-level filter to perform end-of-line marker translation.
For each chunk, the function needs to know if the last character of the
previous chunk could be part of an end-of-line marker or not. This is the
context the function receives besides the chunk. An updated version of
the context is returned after each new chunk.
</p>
<p class=parameters>
<tt>A</tt> is the translated version of <tt>D</tt>. <tt>C</tt> is the
ASCII value of the last character of the previous chunk, if it was a
candidate for line break, or 0 otherwise.
<tt>B</tt> is the same as <tt>C</tt>, but for the current
chunk. <tt>Marker</tt> gives the new end-of-line marker and defaults to CRLF.
</p>
<pre class=example>
-- translates the end-of-line marker to UNIX
unix = mime.eol(0, dos, "\n")
</pre>
<!-- qp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="qp">
A, B = mime.<b>qp(</b>C [, D, marker]<b>)</b>
</p>
<p class=description>
Low-level filter to perform Quoted-Printable encoding.
</p>
<p class=parameters>
<tt>A</tt> is the encoded version of the largest prefix of
<tt>C..D</tt>
that can be encoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> encoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is padded with
the encoding of the remaining bytes of <tt>C</tt>.
Throughout encoding, occurrences of CRLF are replaced by the
<tt>marker</tt>, which itself defaults to CRLF.
</p>
<p class=note>
Note: The simplest use of this function is to encode a string into it's
Quoted-Printable transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.qp</tt>, to discard the second return value.
</p>
<pre class=example>
print((mime.qp("maçã")))
--&gt; ma=E7=E3=
</pre>
<!-- qpwrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="qpwrp">
A, m = mime.<b>qpwrp(</b>n [, B, length]<b>)</b>
</p>
<p class=description>
Low-level filter to break Quoted-Printable text into lines.
</p>
<p class=parameters>
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first
line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>.
</p>
<p class=note>
Note: Besides breaking text into lines, this function makes sure the line
breaks don't fall in the middle of an escaped character combination. Also,
this function only breaks lines that are bigger than <tt>length</tt> bytes.
</p>
<!-- unb64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unb64">
A, B = mime.<b>unb64(</b>C [, D]<b>)</b>
</p>
<p class=description>
Low-level filter to perform Base64 decoding.
</p>
<p class=parameters>
<tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> decoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is the empty string
and <tt>B</tt> returns whatever couldn't be decoded.
</p>
<p class=note>
Note: The simplest use of this function is to decode a string from it's
Base64 transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
</p>
<pre class=example>
print((mime.unb64("ZGllZ286cGFzc3dvcmQ=")))
--&gt; diego:password
</pre>
<!-- unqp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unqp">
A, B = mime.<b>unqp(</b>C [, D]<b>)</b>
</p>
<p class=description>
Low-level filter to remove the Quoted-Printable transfer content encoding
from data.
</p>
<p class=parameters>
<tt>A</tt> is the decoded version of the largest prefix of
<tt>C..D</tt>
that can be decoded unambiguously. <tt>B</tt> has the remaining bytes of
<tt>C..D</tt>, <em>before</em> decoding.
If <tt>D</tt> is <tt><b>nil</b></tt>, <tt>A</tt> is augmented with
the encoding of the remaining bytes of <tt>C</tt>.
</p>
<p class=note>
Note: The simplest use of this function is to decode a string from it's
Quoted-Printable transfer content encoding.
Notice the extra parenthesis around the call to <tt>mime.unqp</tt>, to discard the second return value.
</p>
<pre class=example>
print((mime.qp("ma=E7=E3=")))
--&gt; maçã
</pre>
<!-- wrp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="wrp">
A, m = mime.<b>wrp(</b>n [, B, length]<b>)</b>
</p>
<p class=description>
Low-level filter to break text into lines with CRLF marker.
Text is assumed to be in the <a href=#normalize><tt>normalize</tt></a> form.
</p>
<p class=parameters>
<tt>A</tt> is a copy of <tt>B</tt>, broken into lines of at most
<tt>length</tt> bytes (defaults to 76).
'<tt>n</tt>' should tell how many bytes are left for the first
line of <tt>B</tt> and '<tt>m</tt>' returns the number of bytes
left in the last line of <tt>A</tt>.
</p>
<p class=note>
Note: This function only breaks lines that are bigger than
<tt>length</tt> bytes. The resulting line length does not include the CRLF
marker.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Fri Mar 4 15:19:17 BRT 2016
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,55 @@
body {
margin-left: 1em;
margin-right: 1em;
font-family: "Verdana", sans-serif;
background: #ffffff;
}
tt {
font-family: "Andale Mono", monospace;
}
h1, h2, h3, h4 { margin-left: 0em; }
h3 { padding-top: 1em; }
p { margin-left: 1em; }
p.name {
font-family: "Andale Mono", monospace;
padding-top: 1em;
margin-left: 0em;
}
a[href] { color: #00007f; }
blockquote { margin-left: 3em; }
pre.example {
background: #ccc;
padding: 1em;
margin-left: 1em;
font-family: "Andale Mono", monospace;
font-size: small;
}
hr {
margin-left: 0em;
background: #00007f;
border: 0px;
height: 1px;
}
ul { list-style-type: disc; }
table.index { border: 1px #00007f; }
table.index td { text-align: left; vertical-align: top; }
table.index ul { padding-top: 0em; margin-top: 0em; }
h1:first-letter,
h2:first-letter,
h2:first-letter,
h3:first-letter { color: #00007f; }
div.header, div.footer { margin-left: 0em; }

View file

@ -0,0 +1,260 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: Index to reference manual">
<meta name="keywords" content="Lua, LuaSocket, Index, Manual, Network, Library,
Support, Manual">
<title>LuaSocket: Index to reference manual</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- reference +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2>Reference</h2>
<blockquote>
<a href="dns.html">DNS (in socket)</a>
<blockquote>
<a href="dns.html#getaddrinfo">getaddrinfo</a>,
<a href="dns.html#gethostname">gethostname</a>,
<a href="dns.html#tohostname">tohostname</a>,
<a href="dns.html#toip">toip</a>.
</blockquote>
</blockquote>
<!-- ftp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="ftp.html">FTP</a>
<blockquote>
<a href="ftp.html#get">get</a>,
<a href="ftp.html#put">put</a>.
</blockquote>
</blockquote>
<!-- http +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="http.html">HTTP</a>
<blockquote>
<a href="http.html#request">request</a>.
</blockquote>
</blockquote>
<!-- ltn12 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="ltn12.html">LTN12</a>
<blockquote>
<a href="ltn12.html#filter">filter</a>:
<a href="ltn12.html#filter.chain">chain</a>,
<a href="ltn12.html#filter.cycle">cycle</a>.
</blockquote>
<blockquote>
<a href="ltn12.html#pump">pump</a>:
<a href="ltn12.html#pump.all">all</a>,
<a href="ltn12.html#pump.step">step</a>.
</blockquote>
<blockquote>
<a href="ltn12.html#sink">sink</a>:
<a href="ltn12.html#sink.chain">chain</a>,
<a href="ltn12.html#sink.error">error</a>,
<a href="ltn12.html#sink.file">file</a>,
<a href="ltn12.html#sink.null">null</a>,
<a href="ltn12.html#sink.simplify">simplify</a>,
<a href="ltn12.html#sink.table">table</a>.
</blockquote>
<blockquote>
<a href="ltn12.html#source">source</a>:
<a href="ltn12.html#source.cat">cat</a>,
<a href="ltn12.html#source.chain">chain</a>,
<a href="ltn12.html#source.empty">empty</a>,
<a href="ltn12.html#source.error">error</a>,
<a href="ltn12.html#source.file">file</a>,
<a href="ltn12.html#source.simplify">simplify</a>,
<a href="ltn12.html#source.string">string</a>.
</blockquote>
</blockquote>
<!-- mime +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="mime.html">MIME</a>
<blockquote>
<a href="mime.html#high">high-level</a>:
<a href="mime.html#decode">decode</a>,
<a href="mime.html#encode">encode</a>,
<a href="mime.html#normalize">normalize</a>,
<a href="mime.html#stuff">stuff</a>,
<a href="mime.html#wrap">wrap</a>.
</blockquote>
<blockquote>
<a href="mime.html#low">low-level</a>:
<a href="mime.html#b64">b64</a>,
<a href="mime.html#dot">dot</a>,
<a href="mime.html#eol">eol</a>,
<a href="mime.html#qp">qp</a>,
<a href="mime.html#qpwrp">qpwrp</a>,
<a href="mime.html#unb64">unb64</a>,
<a href="mime.html#unqp">unqp</a>,
<a href="mime.html#wrp">wrp</a>.
</blockquote>
</blockquote>
<!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="smtp.html">SMTP</a>
<blockquote>
<a href="smtp.html#message">message</a>,
<a href="smtp.html#send">send</a>.
</blockquote>
</blockquote>
<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="socket.html">Socket</a>
<blockquote>
<a href="socket.html#bind">bind</a>,
<a href="socket.html#connect">connect</a>,
<a href="socket.html#connect">connect4</a>,
<a href="socket.html#connect">connect6</a>,
<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
<a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>,
<a href="socket.html#headers.canonic">headers.canonic</a>,
<a href="socket.html#newtry">newtry</a>,
<a href="socket.html#protect">protect</a>,
<a href="socket.html#select">select</a>,
<a href="socket.html#sink">sink</a>,
<a href="socket.html#skip">skip</a>,
<a href="socket.html#sleep">sleep</a>,
<a href="socket.html#setsize">_SETSIZE</a>,
<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
<a href="socket.html#source">source</a>,
<a href="tcp.html#socket.tcp">tcp</a>,
<a href="tcp.html#socket.tcp4">tcp4</a>,
<a href="tcp.html#socket.tcp6">tcp6</a>,
<a href="socket.html#try">try</a>,
<a href="udp.html#socket.udp">udp</a>,
<a href="udp.html#socket.udp4">udp4</a>,
<a href="udp.html#socket.udp6">udp6</a>,
<a href="socket.html#version">_VERSION</a>.
</blockquote>
</blockquote>
<!-- tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="tcp.html">TCP (in socket)</a>
<blockquote>
<a href="tcp.html#accept">accept</a>,
<a href="tcp.html#bind">bind</a>,
<a href="tcp.html#close">close</a>,
<a href="tcp.html#connect">connect</a>,
<a href="tcp.html#dirty">dirty</a>,
<a href="tcp.html#getfd">getfd</a>,
<a href="tcp.html#getoption">getoption</a>,
<a href="tcp.html#getpeername">getpeername</a>,
<a href="tcp.html#getsockname">getsockname</a>,
<a href="tcp.html#getstats">getstats</a>,
<a href="tcp.html#gettimeout">gettimeout</a>,
<a href="tcp.html#listen">listen</a>,
<a href="tcp.html#receive">receive</a>,
<a href="tcp.html#send">send</a>,
<a href="tcp.html#setfd">setfd</a>,
<a href="tcp.html#setoption">setoption</a>,
<a href="tcp.html#setstats">setstats</a>,
<a href="tcp.html#settimeout">settimeout</a>,
<a href="tcp.html#shutdown">shutdown</a>.
</blockquote>
</blockquote>
<!-- udp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="udp.html">UDP (in socket)</a>
<blockquote>
<a href="udp.html#close">close</a>,
<a href="udp.html#getoption">getoption</a>,
<a href="udp.html#getpeername">getpeername</a>,
<a href="udp.html#getsockname">getsockname</a>,
<a href="udp.html#gettimeout">gettimeout</a>,
<a href="udp.html#receive">receive</a>,
<a href="udp.html#receivefrom">receivefrom</a>,
<a href="udp.html#send">send</a>,
<a href="udp.html#sendto">sendto</a>,
<a href="udp.html#setpeername">setpeername</a>,
<a href="udp.html#setsockname">setsockname</a>,
<a href="udp.html#setoption">setoption</a>,
<a href="udp.html#settimeout">settimeout</a>.
</blockquote>
</blockquote>
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<blockquote>
<a href="url.html">URL</a>
<blockquote>
<a href="url.html#absolute">absolute</a>,
<a href="url.html#build">build</a>,
<a href="url.html#build_path">build_path</a>,
<a href="url.html#escape">escape</a>,
<a href="url.html#parse">parse</a>,
<a href="url.html#parse_path">parse_path</a>,
<a href="url.html#unescape">unescape</a>.
</blockquote>
</blockquote>
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:47 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,418 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: SMTP support">
<meta name="keywords" content="Lua, LuaSocket, SMTP, E-Mail, MIME, Multipart,
Library, Support">
<title>LuaSocket: SMTP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- smtp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=smtp>SMTP</h2>
<p> The <tt>smtp</tt> namespace provides functionality to send e-mail
messages. The high-level API consists of two functions: one to
define an e-mail message, and another to actually send the message.
Although almost all users will find that these functions provide more than
enough functionality, the underlying implementation allows for even more
control (if you bother to read the code).
</p>
<p>The implementation conforms to the Simple Mail Transfer Protocol,
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>.
Another RFC of interest is <a
href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>,
which governs the Internet Message Format.
Multipart messages (those that contain attachments) are part
of the MIME standard, but described mainly
in <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a>
<p> In the description below, good understanding of <a
href="http://lua-users.org/wiki/FiltersSourcesAndSinks"> LTN012, Filters
sources and sinks</a> and the <a href=mime.html>MIME</a> module is
assumed. In fact, the SMTP module was the main reason for their
creation. </p>
<p>
To obtain the <tt>smtp</tt> namespace, run:
</p>
<pre class=example>
-- loads the SMTP module and everything it requires
local smtp = require("socket.smtp")
</pre>
<p>
MIME headers are represented as a Lua table in the form:
</p>
<blockquote>
<table summary="MIME headers in Lua table">
<tr><td><tt>
headers = {<br>
&nbsp;&nbsp;field-1-name = <i>field-1-value</i>,<br>
&nbsp;&nbsp;field-2-name = <i>field-2-value</i>,<br>
&nbsp;&nbsp;field-3-name = <i>field-3-value</i>,<br>
&nbsp;&nbsp;...<br>
&nbsp;&nbsp;field-n-name = <i>field-n-value</i><br>
}
</tt></td></tr>
</table>
</blockquote>
<p>
Field names are case insensitive (as specified by the standard) and all
functions work with lowercase field names (but see
<a href=socket.html#headers.canonic><tt>socket.headers.canonic</tt></a>).
Field values are left unmodified.
</p>
<p class=note>
Note: MIME headers are independent of order. Therefore, there is no problem
in representing them in a Lua table.
</p>
<p>
The following constants can be set to control the default behavior of
the SMTP module:
</p>
<ul>
<li> <tt>DOMAIN</tt>: domain used to greet the server;
<li> <tt>PORT</tt>: default port used for the connection;
<li> <tt>SERVER</tt>: default server used for the connection;
<li> <tt>TIMEOUT</tt>: default timeout for all I/O operations;
<li> <tt>ZONE</tt>: default time zone.
</ul>
<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=message>
smtp.<b>message(</b>mesgt<b>)</b>
</p>
<p class=description>
Returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep).
</p>
<p class=parameters>
The only parameter of the function is a table describing the message.
<tt>Mesgt</tt> has the following form (notice the recursive structure):
</p>
<blockquote>
<table summary="Mesgt table structure">
<tr><td><tt>
mesgt = {<br>
&nbsp;&nbsp;headers = <i>header-table</i>,<br>
&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or
<i>multipart-mesgt</i><br>
}<br>
&nbsp;<br>
multipart-mesgt = {<br>
&nbsp;&nbsp;[preamble = <i>string</i>,]<br>
&nbsp;&nbsp;[1] = <i>mesgt</i>,<br>
&nbsp;&nbsp;[2] = <i>mesgt</i>,<br>
&nbsp;&nbsp;...<br>
&nbsp;&nbsp;[<i>n</i>] = <i>mesgt</i>,<br>
&nbsp;&nbsp;[epilogue = <i>string</i>,]<br>
}<br>
</tt></td></tr>
</table>
</blockquote>
<p class=parameters>
For a simple message, all that is needed is a set of <tt>headers</tt>
and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
or as a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source. For multipart messages, the body is a table that
recursively defines each part as an independent message, plus an optional
<tt>preamble</tt> and <tt>epilogue</tt>.
</p>
<p class=return>
The function returns a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source that produces the
message contents as defined by <tt>mesgt</tt>, chunk by chunk.
Hopefully, the following
example will make things clear. When in doubt, refer to the appropriate RFC
as listed in the introduction. </p>
<pre class=example>
-- load the smtp support and its friends
local smtp = require("socket.smtp")
local mime = require("mime")
local ltn12 = require("ltn12")
-- creates a source to send a message with two parts. The first part is
-- plain text, the second part is a PNG image, encoded as base64.
source = smtp.message{
headers = {
-- Remember that headers are *ignored* by smtp.send.
from = "Sicrano de Oliveira &lt;sicrano@example.com&gt;",
to = "Fulano da Silva &lt;fulano@example.com&gt;",
subject = "Here is a message with attachments"
},
body = {
preamble = "If your client doesn't understand attachments, \r\n" ..
"it will still display the preamble and the epilogue.\r\n" ..
"Preamble will probably appear even in a MIME enabled client.",
-- first part: no headers means plain text, us-ascii.
-- The mime.eol low-level filter normalizes end-of-line markers.
[1] = {
body = mime.eol(0, [[
Lines in a message body should always end with CRLF.
The smtp module will *NOT* perform translation. However, the
send function *DOES* perform SMTP stuffing, whereas the message
function does *NOT*.
]])
},
-- second part: headers describe content to be a png image,
-- sent under the base64 transfer content encoding.
-- notice that nothing happens until the message is actually sent.
-- small chunks are loaded into memory right before transmission and
-- translation happens on the fly.
[2] = {
headers = {
["content-type"] = 'image/png; name="image.png"',
["content-disposition"] = 'attachment; filename="image.png"',
["content-description"] = 'a beautiful image',
["content-transfer-encoding"] = "BASE64"
},
body = ltn12.source.chain(
ltn12.source.file(io.open("image.png", "rb")),
ltn12.filter.chain(
mime.encode("base64"),
mime.wrap()
)
)
},
epilogue = "This might also show up, but after the attachments"
}
}
-- finally send it
r, e = smtp.send{
from = "&lt;sicrano@example.com&gt;",
rcpt = "&lt;fulano@example.com&gt;",
source = source,
}
</pre>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=send>
smtp.<b>send{</b><br>
&nbsp;&nbsp;from = <i>string</i>,<br>
&nbsp;&nbsp;rcpt = <i>string</i> or <i>string-table</i>,<br>
&nbsp;&nbsp;source = <i>LTN12 source</i>,<br>
&nbsp;&nbsp;[user = <i>string</i>,]<br>
&nbsp;&nbsp;[password = <i>string</i>,]<br>
&nbsp;&nbsp;[server = <i>string</i>,]<br>
&nbsp;&nbsp;[port = <i>number</i>,]<br>
&nbsp;&nbsp;[domain = <i>string</i>,]<br>
&nbsp;&nbsp;[step = <i>LTN12 pump step</i>,]<br>
&nbsp;&nbsp;[create = <i>function</i>]<br>
<b>}</b>
</p>
<p class=description>
Sends a message to a recipient list. Since sending messages is not as
simple as downloading an URL from a FTP or HTTP server, this function
doesn't have a simple interface. However, see the
<a href=#message><tt>message</tt></a> source factory for
a very powerful way to define the message contents.
</p>
<p class=parameters>
The sender is given by the e-mail address in the <tt>from</tt> field.
<tt>Rcpt</tt> is a Lua table with one entry for each recipient e-mail
address, or a string
in case there is just one recipient.
The contents of the message are given by a <em>simple</em>
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>source</tt>. Several arguments are optional:
</p>
<ul>
<li> <tt>user</tt>, <tt>password</tt>: User and password for
authentication. The function will attempt LOGIN and PLAIN authentication
methods if supported by the server (both are unsafe);
<li> <tt>server</tt>: Server to connect to. Defaults to "localhost";
<li> <tt>port</tt>: Port to connect to. Defaults to 25;
<li> <tt>domain</tt>: Domain name used to greet the server; Defaults to the
local machine host name;
<li> <tt>step</tt>:
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
pump step function used to pass data from the
source to the server. Defaults to the LTN12 <tt>pump.step</tt> function;
<li><tt>create</tt>: An optional function to be used instead of
<a href=tcp.html#socket.tcp><tt>socket.tcp</tt></a> when the communications socket is created.
</ul>
<p class=return>
If successful, the function returns 1. Otherwise, the function returns
<b><tt>nil</tt></b> followed by an error message.
</p>
<p class=note>
Note: SMTP servers can be very picky with the format of e-mail
addresses. To be safe, use only addresses of the form
"<tt>&lt;fulano@example.com&gt;</tt>" in the <tt>from</tt> and
<tt>rcpt</tt> arguments to the <tt>send</tt> function. In headers, e-mail
addresses can take whatever form you like. </p>
<p class=note>
Big note: There is a good deal of misconception with the use of the
destination address field headers, i.e., the '<tt>To</tt>', '<tt>Cc</tt>',
and, more importantly, the '<tt>Bcc</tt>' headers. Do <em>not</em> add a
'<tt>Bcc</tt>' header to your messages because it will probably do the
exact opposite of what you expect.
</p>
<p class=note>
Only recipients specified in the <tt>rcpt</tt> list will receive a copy of the
message. Each recipient of an SMTP mail message receives a copy of the
message body along with the headers, and nothing more. The headers
<em>are</em> part of the message and should be produced by the
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
<tt>source</tt> function. The <tt>rcpt</tt> list is <em>not</em>
part of the message and will not be sent to anyone.
</p>
<p class=note>
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>
has two <em>important and short</em> sections, "3.6.3. Destination address
fields" and "5. Security considerations", explaining the proper
use of these headers. Here is a summary of what it says:
</p>
<ul>
<li> <tt>To</tt>: contains the address(es) of the primary recipient(s)
of the message;
<li> <tt>Cc</tt>: (where the "Cc" means "Carbon Copy" in the sense of
making a copy on a typewriter using carbon paper) contains the
addresses of others who are to receive the message, though the
content of the message may not be directed at them;
<li> <tt>Bcc</tt>: (where the "Bcc" means "Blind Carbon
Copy") contains addresses of recipients of the message whose addresses are not to be revealed to other recipients of the message.
</ul>
<p class=note>
The LuaSocket <tt>send</tt> function does not care or interpret the
headers you send, but it gives you full control over what is sent and
to whom it is sent:
</p>
<ul>
<li> If someone is to receive the message, the e-mail address <em>has</em>
to be in the recipient list. This is the only parameter that controls who
gets a copy of the message;
<li> If there are multiple recipients, none of them will automatically
know that someone else got that message. That is, the default behavior is
similar to the <tt>Bcc</tt> field of popular e-mail clients;
<li> It is up to you to add the <tt>To</tt> header with the list of primary
recipients so that other recipients can see it;
<li> It is also up to you to add the <tt>Cc</tt> header with the
list of additional recipients so that everyone else sees it;
<li> Adding a header <tt>Bcc</tt> is nonsense, unless it is
empty. Otherwise, everyone receiving the message will see it and that is
exactly what you <em>don't</em> want to happen!
</ul>
<p class=note>
I hope this clarifies the issue. Otherwise, please refer to
<a href="http://www.ietf.org/rfc/rfc2821.txt">RFC 2821</a>
and
<a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>.
</p>
<pre class=example>
-- load the smtp support
local smtp = require("socket.smtp")
-- Connects to server "localhost" and sends a message to users
-- "fulano@example.com", "beltrano@example.com",
-- and "sicrano@example.com".
-- Note that "fulano" is the primary recipient, "beltrano" receives a
-- carbon copy and neither of them knows that "sicrano" received a blind
-- carbon copy of the message.
from = "&lt;luasocket@example.com&gt;"
rcpt = {
"&lt;fulano@example.com&gt;",
"&lt;beltrano@example.com&gt;",
"&lt;sicrano@example.com&gt;"
}
mesgt = {
headers = {
to = "Fulano da Silva &lt;fulano@example.com&gt;",
cc = '"Beltrano F. Nunes" &lt;beltrano@example.com&gt;',
subject = "My first message"
},
body = "I hope this works. If it does, I can send you another 1000 copies."
}
r, e = smtp.send{
from = from,
rcpt = rcpt,
source = smtp.message(mesgt)
}
</pre>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:51 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,479 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The core namespace">
<meta name="keywords" content="Lua, LuaSocket, Socket, Network, Library, Support">
<title>LuaSocket: The socket namespace</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- socket +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id=socket>The socket namespace</h2>
<p>
The <tt>socket</tt> namespace contains the core functionality of LuaSocket.
</p>
<p>
To obtain the <tt>socket</tt> namespace, run:
</p>
<pre class=example>
-- loads the socket module
local socket = require("socket")
</pre>
<!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="headers.canonic">
socket.headers.<b>canonic</b></p>
<p> The <tt>socket.headers.canonic</tt> table
is used by the HTTP and SMTP modules to translate from
lowercase field names back into their canonic
capitalization. When a lowercase field name exists as a key
in this table, the associated value is substituted in
whenever the field name is sent out.
</p>
<p>
You can obtain the <tt>headers</tt> namespace if case run-time
modifications are required by running:
</p>
<pre class=example>
-- loads the headers module
local headers = require("headers")
</pre>
<!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=bind>
socket.<b>bind(</b>address, port [, backlog]<b>)</b>
</p>
<p class=description>
This function is a shortcut that creates and returns a TCP server object
bound to a local <tt>address</tt> and <tt>port</tt>, ready to
accept client connections. Optionally,
user can also specify the <tt>backlog</tt> argument to the
<a href=tcp.html#listen><tt>listen</tt></a> method (defaults to 32).
</p>
<p class=note>
Note: The server object returned will have the option "<tt>reuseaddr</tt>"
set to <tt><b>true</b></tt>.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=connect>
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
</p>
<p class=description>
This function is a shortcut that creates and returns a TCP client object
connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
the user can also specify the local address and port to bind
(<tt>locaddr</tt> and <tt>locport</tt>), or restrict the socket family
to "<tt>inet</tt>" or "<tt>inet6</tt>".
Without specifying <tt>family</tt> to <tt>connect</tt>, whether a tcp or tcp6
connection is created depends on your system configuration. Two variations
of connect are defined as simple helper functions that restrict the
<tt>family</tt>, <tt>socket.connect4</tt> and <tt>socket.connect6</tt>.
</p>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug>
socket.<b>_DEBUG</b>
</p>
<p class=description>
This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support.
</p>
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug>
socket.<b>_DATAGRAMSIZE</b>
</p>
<p class=description>
Default datagram size used by calls to
<a href="udp.html#receive"<tt>receive</tt></a> and
<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
(Unless changed in compile time, the value is 8192.)
</p>
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime>
socket.<b>gettime()</b>
</p>
<p class=description>
Returns the UNIX time in seconds. You should subtract the values returned by this function
to get meaningful values.
</p>
<pre class=example>
t = socket.gettime()
-- do stuff
print(socket.gettime() - t .. " seconds elapsed")
</pre>
<!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=newtry>
socket.<b>newtry(</b>finalizer<b>)</b>
</p>
<p class=description>
Creates and returns a <em>clean</em>
<a href="#try"><tt>try</tt></a>
function that allows for cleanup before the exception
is raised.
</p>
<p class=parameters>
<tt>Finalizer</tt> is a function that will be called before
<tt>try</tt> throws the exception.
</p>
<p class=return>
The function returns your customized <tt>try</tt> function.
</p>
<p class=note>
Note: This idea saved a <em>lot</em> of work with the
implementation of protocols in LuaSocket:
</p>
<pre class=example>
foo = socket.protect(function()
-- connect somewhere
local c = socket.try(socket.connect("somewhere", 42))
-- create a try function that closes 'c' on error
local try = socket.newtry(function() c:close() end)
-- do everything reassured c will be closed
try(c:send("hello there?\r\n"))
local answer = try(c:receive())
...
try(c:send("good bye\r\n"))
c:close()
end)
</pre>
<!-- protect +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=protect>
socket.<b>protect(</b>func<b>)</b>
</p>
<p class=description>
Converts a function that throws exceptions into a safe function. This
function only catches exceptions thrown by the <a href=#try><tt>try</tt></a>
and <a href=#newtry><tt>newtry</tt></a> functions. It does not catch normal
Lua errors.
</p>
<p class=parameters>
<tt>Func</tt> is a function that calls
<a href=#try><tt>try</tt></a> (or <tt>assert</tt>, or <tt>error</tt>)
to throw exceptions.
</p>
<p class=return>
Returns an equivalent function that instead of throwing exceptions in case of
a failed <a href=#try><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
followed by an error message.
</p>
<!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=select>
socket.<b>select(</b>recvt, sendt [, timeout]<b>)</b>
</p>
<p class=description>
Waits for a number of sockets to change status.
</p>
<p class=parameters>
<tt>Recvt</tt> is an array with the sockets to test for characters
available for reading. Sockets in the <tt>sendt</tt> array are watched to
see if it is OK to immediately write on them. <tt>Timeout</tt> is the
maximum amount of time (in seconds) to wait for a change in status. A
<tt><b>nil</b></tt>, negative or omitted <tt>timeout</tt> value allows the
function to block indefinitely. <tt>Recvt</tt> and <tt>sendt</tt> can also
be empty tables or <tt><b>nil</b></tt>. Non-socket values (or values with
non-numeric indices) in the arrays will be silently ignored.
</p>
<p class=return> The function returns a list with the sockets ready for
reading, a list with the sockets ready for writing and an error message.
The error message is "<tt>timeout</tt>" if a timeout
condition was met, "<tt>select failed</tt>" if the call
to <tt>select</tt> failed, and
<tt><b>nil</b></tt> otherwise. The returned tables are
doubly keyed both by integers and also by the sockets
themselves, to simplify the test if a specific socket has
changed status.
</p>
<p class=note>
<b>Note:</b> <tt>select</tt> can monitor a limited number
of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This
number may be as high as 1024 or as low as 64 by default,
depending on the system. It is usually possible to change this
at compile time. Invoking <tt>select</tt> with a larger
number of sockets will raise an error.
</p>
<p class=note>
<b>Important note</b>: a known bug in WinSock causes <tt>select</tt> to fail
on non-blocking TCP sockets. The function may return a socket as
writable even though the socket is <em>not</em> ready for sending.
</p>
<p class=note>
<b>Another important note</b>: calling select with a server socket in the receive parameter before a call to accept does <em>not</em> guarantee
<a href=tcp.html#accept><tt>accept</tt></a> will return immediately.
Use the <a href=tcp.html#settimeout><tt>settimeout</tt></a>
method or <tt>accept</tt> might block forever.
</p>
<p class=note>
<b>Yet another note</b>: If you close a socket and pass
it to <tt>select</tt>, it will be ignored.
</p>
<p class=note>
<b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
</p>
<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=setsize>
socket.<b>_SETSIZE</b>
</p>
<p class=description>
The maximum number of sockets that the <a
href=#select><tt>select</tt></a> function can handle.
</p>
<!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sink>
socket.<b>sink(</b>mode, socket<b>)</b>
</p>
<p class=description>
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
sink from a stream socket object.
</p>
<p class=parameters>
<tt>Mode</tt> defines the behavior of the sink. The following
options are available:
</p>
<ul>
<li> <tt>"http-chunked"</tt>: sends data through socket after applying the
<em>chunked transfer coding</em>, closing the socket when done;
<li> <tt>"close-when-done"</tt>: sends all received data through the
socket, closing the socket when done;
<li> <tt>"keep-open"</tt>: sends all received data through the
socket, leaving it open when done.
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to send the data.
</p>
<p class=return>
The function returns a sink with the appropriate behavior.
</p>
<!-- skip ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=skip>
socket.<b>skip(</b>d [, ret<sub>1</sub>, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p>
<p class=description>
Drops a number of arguments and returns the remaining.
</p>
<p class=parameters>
<tt>D</tt> is the number of arguments to drop. <tt>Ret<sub>1</sub></tt> to
<tt>ret<sub>N</sub></tt> are the arguments.
</p>
<p class=return>
The function returns <tt>ret<sub>d+1</sub></tt> to <tt>ret<sub>N</sub></tt>.
</p>
<p class=note>
Note: This function is useful to avoid creation of dummy variables:
</p>
<pre class=example>
-- get the status code and separator from SMTP server reply
local code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
</pre>
<!-- sleep ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=sleep>
socket.<b>sleep(</b>time<b>)</b>
</p>
<p class=description>
Freezes the program execution during a given amount of time.
</p>
<p class=parameters>
<tt>Time</tt> is the number of seconds to sleep for. If
<tt>time</tt> is negative, the function returns immediately.
</p>
<!-- source +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=source>
socket.<b>source(</b>mode, socket [, length]<b>)</b>
</p>
<p class=description>
Creates an
<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a>
source from a stream socket object.
</p>
<p class=parameters>
<tt>Mode</tt> defines the behavior of the source. The following
options are available:
</p>
<ul>
<li> <tt>"http-chunked"</tt>: receives data from socket and removes the
<em>chunked transfer coding</em> before returning the data;
<li> <tt>"by-length"</tt>: receives a fixed number of bytes from the
socket. This mode requires the extra argument <tt>length</tt>;
<li> <tt>"until-closed"</tt>: receives data from a socket until the other
side closes the connection.
</ul>
<p>
<tt>Socket</tt> is the stream socket object used to receive the data.
</p>
<p class=return>
The function returns a source with the appropriate behavior.
</p>
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=socketinvalid>
socket.<b>_SOCKETINVALID</b>
</p>
<p class=description>
The OS value for an invalid socket.
</p>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try>
socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b>
</p>
<p class=description>
Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
<tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught
by a <a href=#protect><tt>protect</tt></a>ed function only.
</p>
<p class=parameters>
<tt>Ret<sub>1</sub></tt> to <tt>ret<sub>N</sub></tt> can be arbitrary
arguments, but are usually the return values of a function call
nested with <tt>try</tt>.
</p>
<p class=return>
The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
in a table with metatable used by <a href=#protect><tt>protect</tt></a> to
distinguish exceptions from runtime errors.
</p>
<pre class=example>
-- connects or throws an exception with the appropriate error message
c = socket.try(socket.connect("localhost", 80))
</pre>
<!-- version ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=version>
socket.<b>_VERSION</b>
</p>
<p class=description>
This constant has a string describing the current LuaSocket version.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:54 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,721 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The TCP/IP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
<title>LuaSocket: TCP/IP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="tcp">TCP</h2>
<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="accept">
server:<b>accept()</b>
</p>
<p class=description>
Waits for a remote connection on the server
object and returns a client object representing that connection.
</p>
<p class=return>
If a connection is successfully initiated, a client object is returned.
If a timeout condition is met, the method returns <b><tt>nil</tt></b>
followed by the error string '<tt>timeout</tt>'. Other errors are
reported by <b><tt>nil</tt></b> followed by a message describing the error.
</p>
<p class=note>
Note: calling <a href=socket.html#select><tt>socket.select</tt></a>
with a server object in
the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
might block until <em>another</em> client shows up.
</p>
<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="bind">
master:<b>bind(</b>address, port<b>)</b>
</p>
<p class=description>
Binds a master object to <tt>address</tt> and <tt>port</tt> on the
local host.
<p class=parameters>
<tt>Address</tt> can be an IP address or a host name.
<tt>Port</tt> must be an integer number in the range [0..64K).
If <tt>address</tt>
is '<tt>*</tt>', the system binds to all local interfaces
using the <tt>INADDR_ANY</tt> constant or
<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
If <tt>port</tt> is 0, the system automatically
chooses an ephemeral port.
</p>
<p class=return>
In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<p class=note>
Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
is available and is a shortcut for the creation of server sockets.
</p>
<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="close">
master:<b>close()</b><br>
client:<b>close()</b><br>
server:<b>close()</b>
</p>
<p class=description>
Closes a TCP object. The internal socket used by the object is closed
and the local address to which the object was
bound is made available to other applications. No further operations
(except for further calls to the <tt>close</tt> method) are allowed on
a closed socket.
</p>
<p class=note>
Note: It is important to close all used sockets once they are not
needed, since, in many systems, each socket uses a file descriptor,
which are limited system resources. Garbage-collected objects are
automatically closed before destruction, though.
</p>
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="connect">
master:<b>connect(</b>address, port<b>)</b>
</p>
<p class=description>
Attempts to connect a master object to a remote host, transforming it into a
client object.
Client objects support methods
<a href=#send><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>,
<a href=#getpeername><tt>getpeername</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a>.
</p>
<p class=parameters>
<tt>Address</tt> can be an IP address or a host name.
<tt>Port</tt> must be an integer number in the range [1..64K).
</p>
<p class=return>
In case of error, the method returns <b><tt>nil</tt></b> followed by a string
describing the error. In case of success, the method returns 1.
</p>
<p class=note>
Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
is available and is a shortcut for the creation of client sockets.
</p>
<p class=note>
Note: Starting with LuaSocket 2.0,
the <a href=#settimeout><tt>settimeout</tt></a>
method affects the behavior of <tt>connect</tt>, causing it to return
with an error in case of a timeout. If that happens, you can still call <a
href=socket.html#select><tt>socket.select</tt></a> with the socket in the
<tt>sendt</tt> table. The socket will be writable when the connection is
established.
</p>
<p class=note>
Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by
<a href=#socket.tcp><tt>socket.tcp</tt></a>,
<a href=#socket.tcp4><tt>socket.tcp4</tt></a> or
<a href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
the appropriate family (or both) are tried in the order
returned by the resolver until the
first success or until the last failure. If the timeout was
set to zero, only the first address is tried.
</p>
<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="dirty">
master:<b>dirty()</b><br>
client:<b>dirty()</b><br>
server:<b>dirty()</b>
</p>
<p class=description>
Check the read buffer status.
</p>
<p class=return>
Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
</p>
<p class=note>
Note: <b>This is an internal method, use at your own risk.</b>
</p>
<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getfd">
master:<b>getfd()</b><br>
client:<b>getfd()</b><br>
server:<b>getfd()</b>
</p>
<p class=description>
Returns the underling socket descriptor or handle associated to the object.
</p>
<p class=return>
The descriptor or handle. In case the object has been closed, the return will be -1.
</p>
<p class=note>
Note: <b>This is an internal method. Unlikely to be
portable. Use at your own risk. </b>
</p>
<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getoption">
client:<b>getoption(</b>option)</b><br>
server:<b>getoption(</b>option)</b>
</p>
<p class=description>
Gets options for the TCP object.
See <a href=#setoption><tt>setoption</tt></a> for description of the
option names and values.
</p>
<p class=parameters>
<tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>keepalive</tt>'
<li> '<tt>linger</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>tcp-nodelay</tt>'
</ul>
<p class=return>
The method returns the option <tt>value</tt> in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getpeername">
client:<b>getpeername()</b>
</p>
<p class=description>
Returns information about the remote side of a connected client object.
</p>
<p class=return>
Returns a string with the IP address of the peer, the
port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<p class=note>
Note: It makes no sense to call this method on server objects.
</p>
<!-- getsockname ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getsockname">
master:<b>getsockname()</b><br>
client:<b>getsockname()</b><br>
server:<b>getsockname()</b>
</p>
<p class=description>
Returns the local address information associated to the object.
</p>
<p class=return>
The method returns a string with local IP address, a number with
the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<!-- getstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="getstats">
master:<b>getstats()</b><br>
client:<b>getstats()</b><br>
server:<b>getstats()</b><br>
</p>
<p class=description>
Returns accounting information on the socket, useful for throttling
of bandwidth.
</p>
<p class=return>
The method returns the number of bytes received, the number of bytes sent,
and the age of the socket object in seconds.
</p>
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="gettimeout">
master:<b>gettimeout()</b><br>
client:<b>gettimeout()</b><br>
server:<b>gettimeout()</b>
</p>
<p class=description>
Returns the current block timeout followed by the curent
total timeout.
</p>
<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="listen">
master:<b>listen(</b>backlog<b>)</b>
</p>
<p class=description>
Specifies the socket is willing to receive connections, transforming the
object into a server object. Server objects support the
<a href=#accept><tt>accept</tt></a>,
<a href=#getsockname><tt>getsockname</tt></a>,
<a href=#setoption><tt>setoption</tt></a>,
<a href=#settimeout><tt>settimeout</tt></a>,
and <a href=#close><tt>close</tt></a> methods.
</p>
<p class=parameters>
The parameter <tt>backlog</tt> specifies the number of client
connections that can
be queued waiting for service. If the queue is full and another client
attempts connection, the connection is refused.
</p>
<p class=return>
In case of success, the method returns 1. In case of error, the
method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<!-- receive ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="receive">
client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
</p>
<p class=description>
Reads data from a client object, according to the specified <em>read
pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
</p>
<p class=parameters>
<tt>Pattern</tt> can be any of the following:
</p>
<ul>
<li> '<tt>*a</tt>': reads from the socket until the connection is
closed. No end-of-line translation is performed;
<li> '<tt>*l</tt>': reads a line of text from the socket. The line is
terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
CR character (ASCII&nbsp;13). The CR and LF characters are not included in
the returned line. In fact, <em>all</em> CR characters are
ignored by the pattern. This is the default pattern;
<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
of bytes from the socket.
</ul>
<p class=parameters>
<tt>Prefix</tt> is an optional string to be concatenated to the beginning
of any received data before return.
</p>
<p class=return>
If successful, the method returns the received pattern. In case of error,
the method returns <tt><b>nil</b></tt> followed by an error
message, followed by a (possibly empty) string containing
the partial that was received. The error message can be
the string '<tt>closed</tt>' in case the connection was
closed before the transmission was completed or the string
'<tt>timeout</tt>' in case there was a timeout during the operation.
</p>
<p class=note>
<b>Important note</b>: This function was changed <em>severely</em>. It used
to support multiple patterns (but I have never seen this feature used) and
now it doesn't anymore. Partial results used to be returned in the same
way as successful results. This last feature violated the idea that all
functions should return <tt><b>nil</b></tt> on error. Thus it was changed
too.
</p>
<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="send">
client:<b>send(</b>data [, i [, j]]<b>)</b>
</p>
<p class=description>
Sends <tt>data</tt> through client object.
</p>
<p class=parameters>
<tt>Data</tt> is the string to be sent. The optional arguments
<tt>i</tt> and <tt>j</tt> work exactly like the standard
<tt>string.sub</tt> Lua function to allow the selection of a
substring to be sent.
</p>
<p class=return>
If successful, the method returns the index of the last byte
within <tt>[i, j]</tt> that has been sent. Notice that, if
<tt>i</tt> is 1 or absent, this is effectively the total
number of bytes sent. In case of error, the method returns
<b><tt>nil</tt></b>, followed by an error message, followed
by the index of the last byte within <tt>[i, j]</tt> that
has been sent. You might want to try again from the byte
following that. The error message can be '<tt>closed</tt>'
in case the connection was closed before the transmission
was completed or the string '<tt>timeout</tt>' in case
there was a timeout during the operation.
</p>
<p class=note>
Note: Output is <em>not</em> buffered. For small strings,
it is always better to concatenate them in Lua
(with the '<tt>..</tt>' operator) and send the result in one call
instead of calling the method several times.
</p>
<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setoption">
client:<b>setoption(</b>option [, value]<b>)</b><br>
server:<b>setoption(</b>option [, value]<b>)</b>
</p>
<p class=description>
Sets options for the TCP object. Options are only needed by low-level or
time-critical applications. You should only modify an option if you
are sure you need it.
</p>
<p class=parameters>
<tt>Option</tt> is a string with the option name, and <tt>value</tt>
depends on the option being set:
<ul>
<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
the periodic transmission of messages on a connected socket. Should the
connected party fail to respond to these messages, the connection is
considered broken and processes using the socket are notified;
<li> '<tt>linger</tt>': Controls the action taken when unsent data are
queued on a socket and a close is performed. The value is a table with a
boolean entry '<tt>on</tt>' and a numeric entry for the time interval
'<tt>timeout</tt>' in seconds. If the '<tt>on</tt>' field is set to
<tt>true</tt>, the system will block the process on the close attempt until
it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
process the close in a manner that allows the process to continue as
quickly as possible. I do not advise you to set this to anything other than
zero;
<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
used in validating addresses supplied in a call to
<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
disables the Nagle's algorithm for the connection;
<li> '<tt>ipv6-v6only</tt>':
Setting this option to <tt>true</tt> restricts an <tt>inet6</tt> socket to
sending and receiving only IPv6 packets.
</ul>
<p class=return>
The method returns 1 in case of success, or <b><tt>nil</tt></b>
followed by an error message otherwise.
</p>
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setstats">
master:<b>setstats(</b>received, sent, age<b>)</b><br>
client:<b>setstats(</b>received, sent, age<b>)</b><br>
server:<b>setstats(</b>received, sent, age<b>)</b><br>
</p>
<p class=description>
Resets accounting information on the socket, useful for throttling
of bandwidth.
</p>
<p class=parameters>
<tt>Received</tt> is a number with the new number of bytes received.
<tt>Sent</tt> is a number with the new number of bytes sent.
<tt>Age</tt> is the new age in seconds.
</p>
<p class=return>
The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="settimeout">
master:<b>settimeout(</b>value [, mode]<b>)</b><br>
client:<b>settimeout(</b>value [, mode]<b>)</b><br>
server:<b>settimeout(</b>value [, mode]<b>)</b>
</p>
<p class=description>
Changes the timeout values for the object. By default,
all I/O operations are blocking. That is, any call to the methods
<a href=#send><tt>send</tt></a>,
<a href=#receive><tt>receive</tt></a>, and
<a href=#accept><tt>accept</tt></a>
will block indefinitely, until the operation completes. The
<tt>settimeout</tt> method defines a limit on the amount of time the
I/O methods can block. When a timeout is set and the specified amount of
time has elapsed, the affected methods give up and fail with an error code.
</p>
<p class=parameters>
The amount of time to wait is specified as the
<tt>value</tt> parameter, in seconds. There are two timeout modes and
both can be used together for fine tuning:
</p>
<ul>
<li> '<tt>b</tt>': <em>block</em> timeout. Specifies the upper limit on
the amount of time LuaSocket can be blocked by the operating system
while waiting for completion of any single I/O operation. This is the
default mode;</li>
<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on
the amount of time LuaSocket can block a Lua script before returning from
a call.</li>
</ul>
<p class=parameters>
The <b><tt>nil</tt></b> timeout <tt>value</tt> allows operations to block
indefinitely. Negative timeout values have the same effect.
</p>
<p class=note>
Note: although timeout values have millisecond precision in LuaSocket,
large blocks can cause I/O functions not to respect timeout values due
to the time the library takes to transfer blocks to and from the OS
and to and from the Lua interpreter. Also, function that accept host names
and perform automatic name resolution might be blocked by the resolver for
longer than the specified timeout value.
</p>
<p class=note>
Note: The old <tt>timeout</tt> method is deprecated. The name has been
changed for sake of uniformity, since all other method names already
contained verbs making their imperative nature obvious.
</p>
<!-- shutdown +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="shutdown">
client:<b>shutdown(</b>mode<b>)</b><br>
</p>
<p class=description>
Shuts down part of a full-duplex connection.
</p>
<p class=parameters>
Mode tells which way of the connection should be shut down and can
take the value:
<ul>
<li>"<tt>both</tt>": disallow further sends and receives on the object.
This is the default mode;
<li>"<tt>send</tt>": disallow further sends on the object;
<li>"<tt>receive</tt>": disallow further receives on the object.
</ul>
<p class=return>
This function returns 1.
</p>
<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="setfd">
master:<b>setfd(</b>fd<b>)</b><br>
client:<b>setfd(</b>fd<b>)</b><br>
server:<b>setfd(</b>fd<b>)</b>
</p>
<p class=description>
Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
</p>
<p class=return>
No return value.
</p>
<p class=note>
Note: <b>This is an internal method. Unlikely to be
portable. Use at your own risk. </b>
</p>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp">
socket.<b>tcp()</b>
</p>
<p class=description>
Creates and returns an TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<p class=note>
Note: The choice between IPv4 and IPv6 happens during a call to
<a href=#bind><tt>bind</tt></a> or <a
href=#bind><tt>connect</tt></a>, depending on the address
family obtained from the resolver.
</p>
<p class=note>
Note: Before the choice between IPv4 and IPv6 happens,
the internal socket object is invalid and therefore <a
href=#setoption><tt>setoption</tt></a> will fail.
</p>
<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp4">
socket.<b>tcp4()</b>
</p>
<p class=description>
Creates and returns an IPv4 TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="socket.tcp6">
socket.<b>tcp6()</b>
</p>
<p class=description>
Creates and returns an IPv6 TCP master object. A master object can
be transformed into a server object with the method
<a href=#listen><tt>listen</tt></a> (after a call to <a
href=#bind><tt>bind</tt></a>) or into a client object with
the method <a href=#connect><tt>connect</tt></a>. The only other
method supported by a master object is the
<a href=#close><tt>close</tt></a> method.</p>
<p class=return>
In case of success, a new master object is returned. In case of error,
<b><tt>nil</tt></b> is returned, followed by an error message.
</p>
<p class=note>
Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:25:57 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,596 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: The UDP support">
<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
<title>LuaSocket: UDP support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="udp">UDP</h2>
<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="close">
connected:<b>close()</b><br>
unconnected:<b>close()</b>
</p>
<p class="description">
Closes a UDP object. The internal socket
used by the object is closed and the local address to which the
object was bound is made available to other applications. No
further operations (except for further calls to the <tt>close</tt>
method) are allowed on a closed socket.
</p>
<p class="note">
Note: It is important to close all used sockets
once they are not needed, since, in many systems, each socket uses
a file descriptor, which are limited system resources.
Garbage-collected objects are automatically closed before
destruction, though.
</p>
<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getoption">
connected:<b>getoption()</b><br>
unconnected:<b>getoption()</b>
</p>
<p class="description">
Gets an option value from the UDP object.
See <a href=#setoption><tt>setoption</tt></a> for
description of the option names and values.
</p>
<p class="parameters"><tt>Option</tt> is a string with the option name.
<ul>
<li> '<tt>dontroute</tt>'
<li> '<tt>broadcast</tt>'
<li> '<tt>reuseaddr</tt>'
<li> '<tt>reuseport</tt>'
<li> '<tt>ip-multicast-loop</tt>'
<li> '<tt>ipv6-v6only</tt>'
<li> '<tt>ip-multicast-if</tt>'
<li> '<tt>ip-multicast-ttl</tt>'
<li> '<tt>ip-add-membership</tt>'
<li> '<tt>ip-drop-membership</tt>'
</ul>
</p>
<p class=return>
The method returns the option <tt>value</tt> in case of
success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getpeername">
connected:<b>getpeername()</b>
</p>
<p class="description">
Retrieves information about the peer
associated with a connected UDP object.
</p>
<p class=return>
Returns a string with the IP address of the peer, the
port number that peer is using for the connection,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<p class="note">
Note: It makes no sense to call this method on unconnected objects.
</p>
<!-- getsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="getsockname">
connected:<b>getsockname()</b><br>
unconnected:<b>getsockname()</b>
</p>
<p class="description">
Returns the local address information associated to the object.
</p>
<p class=return>
The method returns a string with local IP address, a number with
the local port,
and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
In case of error, the method returns <b><tt>nil</tt></b>.
</p>
<p class="note">
Note: UDP sockets are not bound to any address
until the <a href="#setsockname"><tt>setsockname</tt></a> or the
<a href="#sendto"><tt>sendto</tt></a> method is called for the
first time (in which case it is bound to an ephemeral port and the
wild-card address).
</p>
<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="gettimeout">
connected:<b>settimeout(</b>value<b>)</b><br>
unconnected:<b>settimeout(</b>value<b>)</b>
</p>
<p class=description>
Returns the current timeout value.
</p>
<!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="receive">
connected:<b>receive(</b>[size]<b>)</b><br>
unconnected:<b>receive(</b>[size]<b>)</b>
</p>
<p class="description">
Receives a datagram from the UDP object. If
the UDP object is connected, only datagrams coming from the peer
are accepted. Otherwise, the returned datagram can come from any
host.
</p>
<p class="parameters">
The optional <tt>size</tt> parameter
specifies the maximum size of the datagram to be retrieved. If
there are more than <tt>size</tt> bytes available in the datagram,
the excess bytes are discarded. If there are less then
<tt>size</tt> bytes available in the current datagram, the
available bytes are returned.
If <tt>size</tt> is omitted, the
compile-time constant <a
href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used
(it defaults to 8192 bytes). Larger sizes will cause a
temporary buffer to be allocated for the operation.
</p>
<p class="return">
In case of success, the method returns the
received datagram. In case of timeout, the method returns
<b><tt>nil</tt></b> followed by the string '<tt>timeout</tt>'.
</p>
<!-- receivefrom +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="receivefrom">
unconnected:<b>receivefrom(</b>[size]<b>)</b>
</p>
<p class="description">
Works exactly as the <a href="#receive"><tt>receive</tt></a>
method, except it returns the IP
address and port as extra return values (and is therefore slightly less
efficient).
</p>
<!-- send ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="send">
connected:<b>send(</b>datagram<b>)</b>
</p>
<p class="description">
Sends a datagram to the UDP peer of a connected object.
</p>
<p class="parameters">
<tt>Datagram</tt> is a string with the datagram contents.
The maximum datagram size for UDP is 64K minus IP layer overhead.
However datagrams larger than the link layer packet size will be
fragmented, which may deteriorate performance and/or reliability.
</p>
<p class="return">
If successful, the method returns 1. In case of
error, the method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<p class="note">
Note: In UDP, the <tt>send</tt> method never blocks
and the only way it can fail is if the underlying transport layer
refuses to send a message to the specified address (i.e. no
interface accepts the address).
</p>
<!-- sendto ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="sendto">
unconnected:<b>sendto(</b>datagram, ip, port<b>)</b>
</p>
<p class="description">
Sends a datagram to the specified IP address and port number.
</p>
<p class="parameters">
<tt>Datagram</tt> is a string with the
datagram contents.
The maximum datagram size for UDP is 64K minus IP layer overhead.
However datagrams larger than the link layer packet size will be
fragmented, which may deteriorate performance and/or reliability.
<tt>Ip</tt> is the IP address of the recipient.
Host names are <em>not</em> allowed for performance reasons.
<tt>Port</tt> is the port number at the recipient.
</p>
<p class="return">
If successful, the method returns 1. In case of
error, the method returns <b><tt>nil</tt></b> followed by an error message.
</p>
<p class="note">
Note: In UDP, the <tt>send</tt> method never blocks
and the only way it can fail is if the underlying transport layer
refuses to send a message to the specified address (i.e. no
interface accepts the address).
</p>
<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setoption">
connected:<b>setoption(</b>option [, value]<b>)</b><br>
unconnected:<b>setoption(</b>option [, value]<b>)</b>
</p>
<p class="description">
Sets options for the UDP object. Options are
only needed by low-level or time-critical applications. You should
only modify an option if you are sure you need it.</p>
<p class="parameters"><tt>Option</tt> is a string with the option
name, and <tt>value</tt> depends on the option being set:
</p>
<ul>
<li> '<tt>dontroute</tt>': Indicates that outgoing
messages should bypass the standard routing facilities.
Receives a boolean value;
<li> '<tt>broadcast</tt>': Requests permission to send
broadcast datagrams on the socket.
Receives a boolean value;
<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
validating addresses supplied in a <tt>bind()</tt> call
should allow reuse of local addresses.
Receives a boolean value;
<li> '<tt>reuseport</tt>': Allows completely duplicate
bindings by multiple processes if they all set
'<tt>reuseport</tt>' before binding the port.
Receives a boolean value;
<li> '<tt>ip-multicast-loop</tt>':
Specifies whether or not a copy of an outgoing multicast
datagram is delivered to the sending host as long as it is a
member of the multicast group.
Receives a boolean value;
<li> '<tt>ipv6-v6only</tt>':
Specifies whether to restrict <tt>inet6</tt> sockets to
sending and receiving only IPv6 packets.
Receive a boolean value;
<li> '<tt>ip-multicast-if</tt>':
Sets the interface over which outgoing multicast datagrams
are sent.
Receives an IP address;
<li> '<tt>ip-multicast-ttl</tt>':
Sets the Time To Live in the IP header for outgoing
multicast datagrams.
Receives a number;
<li> '<tt>ip-add-membership</tt>':
Joins the multicast group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address;
<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
group specified.
Receives a table with fields
<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
IP address.
</ul>
<p class="return">
The method returns 1 in case of success, or
<b><tt>nil</tt></b> followed by an error message otherwise.
</p>
<p class=note>
Note: The descriptions above come from the man pages.
</p>
<!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setpeername">
connected:<b>setpeername(</b>'*'<b>)</b><br>
unconnected:<b>setpeername(</b>address, port<b>)</b>
</p>
<p class="description">
Changes the peer of a UDP object. This
method turns an unconnected UDP object into a connected UDP
object or vice versa.
</p>
<p class="description">
For connected objects, outgoing datagrams
will be sent to the specified peer, and datagrams received from
other peers will be discarded by the OS. Connected UDP objects must
use the <a href="#send"><tt>send</tt></a> and
<a href="#receive"><tt>receive</tt></a> methods instead of
<a href="#sendto"><tt>sendto</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a>.
</p>
<p class="parameters">
<tt>Address</tt> can be an IP address or a
host name. <tt>Port</tt> is the port number. If <tt>address</tt> is
'<tt>*</tt>' and the object is connected, the peer association is
removed and the object becomes an unconnected object again. In that
case, the <tt>port</tt> argument is ignored.
</p>
<p class="return">
In case of error the method returns
<b><tt>nil</tt></b> followed by an error message. In case of success, the
method returns 1.
</p>
<p class="note">
Note: Since the address of the peer does not have
to be passed to and from the OS, the use of connected UDP objects
is recommended when the same peer is used for several transmissions
and can result in up to 30% performance gains.
</p>
<p class=note>
Note: Starting with LuaSocket 3.0, the host name resolution
depends on whether the socket was created by <a
href=#socket.udp><tt>socket.udp</tt></a> or <a
href=#socket.udp6><tt>socket.udp6</tt></a>. Addresses from
the appropriate family are tried in succession until the
first success or until the last failure.
</p>
<!-- setsockname +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="setsockname">
unconnected:<b>setsockname(</b>address, port<b>)</b>
</p>
<p class="description">
Binds the UDP object to a local address.
</p>
<p class="parameters">
<tt>Address</tt> can be an IP address or a
host name. If <tt>address</tt> is '<tt>*</tt>' the system binds to
all local interfaces using the constant <tt>INADDR_ANY</tt>. If
<tt>port</tt> is 0, the system chooses an ephemeral port.
</p>
<p class="return">
If successful, the method returns 1. In case of
error, the method returns <b><tt>nil</tt></b> followed by an error
message.
</p>
<p class="note">
Note: This method can only be called before any
datagram is sent through the UDP object, and only once. Otherwise,
the system automatically binds the object to all local interfaces
and chooses an ephemeral port as soon as the first datagram is
sent. After the local address is set, either automatically by the
system or explicitly by <tt>setsockname</tt>, it cannot be
changed.
</p>
<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="settimeout">
connected:<b>settimeout(</b>value<b>)</b><br>
unconnected:<b>settimeout(</b>value<b>)</b>
</p>
<p class="description">
Changes the timeout values for the object. By default, the
<a href="#receive"><tt>receive</tt></a> and
<a href="#receivefrom"><tt>receivefrom</tt></a>
operations are blocking. That is, any call to the methods will block
indefinitely, until data arrives. The <tt>settimeout</tt> function defines
a limit on the amount of time the functions can block. When a timeout is
set and the specified amount of time has elapsed, the affected methods
give up and fail with an error code.
</p>
<p class="parameters">
The amount of time to wait is specified as
the <tt>value</tt> parameter, in seconds. The <b><tt>nil</tt></b> timeout
<tt>value</tt> allows operations to block indefinitely. Negative
timeout values have the same effect.
</p>
<p class="note">
Note: In UDP, the <a href="#send"><tt>send</tt></a>
and <a href="#sentdo"><tt>sendto</tt></a> methods never block (the
datagram is just passed to the OS and the call returns
immediately). Therefore, the <tt>settimeout</tt> method has no
effect on them.
</p>
<p class="note">
Note: The old <tt>timeout</tt> method is
deprecated. The name has been changed for sake of uniformity, since
all other method names already contained verbs making their
imperative nature obvious.
</p>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp()</b>
</p>
<p class="description">
Creates and returns an unconnected UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<p class=note>
Note: The choice between IPv4 and IPv6 happens during a call to
<a href=#sendto><tt>sendto</tt></a>, <a
href=#setpeername><tt>setpeername</tt></a>, or <a
href=#setsockname><tt>sockname</tt></a>, depending on the address
family obtained from the resolver.
</p>
<p class=note>
Note: Before the choice between IPv4 and IPv6 happens,
the internal socket object is invalid and therefore <a
href=#setoption><tt>setoption</tt></a> will fail.
</p>
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp4()</b>
</p>
<p class="description">
Creates and returns an unconnected IPv4 UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp6">
socket.<b>udp6()</b>
</p>
<p class="description">
Creates and returns an unconnected IPv6 UDP object.
Unconnected objects support the
<a href="#sendto"><tt>sendto</tt></a>,
<a href="#receive"><tt>receive</tt></a>,
<a href="#receivefrom"><tt>receivefrom</tt></a>,
<a href="#getoption"><tt>getoption</tt></a>,
<a href="#getsockname"><tt>getsockname</tt></a>,
<a href="#setoption"><tt>setoption</tt></a>,
<a href="#settimeout"><tt>settimeout</tt></a>,
<a href="#setpeername"><tt>setpeername</tt></a>,
<a href="#setsockname"><tt>setsockname</tt></a>, and
<a href="#close"><tt>close</tt></a>.
The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
an error message.
</p>
<p class=note>
Note: The TCP object returned will have the option
"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
</p>
<!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:26:01 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,328 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="description" content="LuaSocket: URL manipulation">
<meta name="keywords" content="Lua, LuaSocket, URL, Library, Link, Network, Support">
<title>LuaSocket: URL support</title>
<link rel="stylesheet" href="reference.css" type="text/css">
</head>
<body>
<!-- header +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=header>
<hr>
<center>
<table summary="LuaSocket logo">
<tr><td align=center><a href="http://www.lua.org">
<img width=128 height=128 border=0 alt="LuaSocket" src="luasocket.png">
</a></td></tr>
<tr><td align=center valign=top>Network support for the Lua language
</td></tr>
</table>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#download">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
</center>
<hr>
</div>
<!-- url ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<h2 id="url">URL</h2>
<p>
The <tt>url</tt> namespace provides functions to parse, protect,
and build URLs, as well as functions to compose absolute URLs
from base and relative URLs, according to
<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
</p>
<p>
To obtain the <tt>url</tt> namespace, run:
</p>
<pre class=example>
-- loads the URL module
local url = require("socket.url")
</pre>
<p>
An URL is defined by the following grammar:
</p>
<blockquote>
<tt>
&lt;url&gt; ::= [&lt;scheme&gt;:][//&lt;authority&gt;][/&lt;path&gt;][;&lt;params&gt;][?&lt;query&gt;][#&lt;fragment&gt;]<br>
&lt;authority&gt; ::= [&lt;userinfo&gt;@]&lt;host&gt;[:&lt;port&gt;]<br>
&lt;userinfo&gt; ::= &lt;user&gt;[:&lt;password&gt;]<br>
&lt;path&gt; ::= {&lt;segment&gt;/}&lt;segment&gt;<br>
</tt>
</blockquote>
<!-- absolute +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="absolute">
url.<b>absolute(</b>base, relative<b>)</b>
</p>
<p class=description>
Builds an absolute URL from a base URL and a relative URL.
</p>
<p class=parameters>
<tt>Base</tt> is a string with the base URL or
a parsed URL table. <tt>Relative</tt> is a
string with the relative URL.
</p>
<p class=return>
The function returns a string with the absolute URL.
</p>
<p class=note>
Note: The rules that
govern the composition are fairly complex, and are described in detail in
<a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>.
The example bellow should give an idea of what the rules are.
</p>
<pre class=example>
http://a/b/c/d;p?q
+
g:h = g:h
g = http://a/b/c/g
./g = http://a/b/c/g
g/ = http://a/b/c/g/
/g = http://a/g
//g = http://g
?y = http://a/b/c/?y
g?y = http://a/b/c/g?y
#s = http://a/b/c/d;p?q#s
g#s = http://a/b/c/g#s
g?y#s = http://a/b/c/g?y#s
;x = http://a/b/c/;x
g;x = http://a/b/c/g;x
g;x?y#s = http://a/b/c/g;x?y#s
. = http://a/b/c/
./ = http://a/b/c/
.. = http://a/b/
../ = http://a/b/
../g = http://a/b/g
../.. = http://a/
../../ = http://a/
../../g = http://a/g
</pre>
<!-- build ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="build">
url.<b>build(</b>parsed_url<b>)</b>
</p>
<p class=description>
Rebuilds an URL from its parts.
</p>
<p class=parameters>
<tt>Parsed_url</tt> is a table with same components returned by
<a href="#parse"><tt>parse</tt></a>.
Lower level components, if specified,
take precedence over high level components of the URL grammar.
</p>
<p class=return>
The function returns a string with the built URL.
</p>
<!-- build_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="build_path">
url.<b>build_path(</b>segments, unsafe<b>)</b>
</p>
<p class=description>
Builds a <tt>&lt;path&gt;</tt> component from a list of
<tt>&lt;segment&gt;</tt> parts.
Before composition, any reserved characters found in a segment are escaped into
their protected form, so that the resulting path is a valid URL path
component.
</p>
<p class=parameters>
<tt>Segments</tt> is a list of strings with the <tt>&lt;segment&gt;</tt>
parts. If <tt>unsafe</tt> is anything but <b><tt>nil</tt></b>, reserved
characters are left untouched.
</p>
<p class=return>
The function returns a string with the
built <tt>&lt;path&gt;</tt> component.
</p>
<!-- escape +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="escape">
url.<b>escape(</b>content<b>)</b>
</p>
<p class=description>
Applies the URL escaping content coding to a string
Each byte is encoded as a percent character followed
by the two byte hexadecimal representation of its integer
value.
</p>
<p class=parameters>
<tt>Content</tt> is the string to be encoded.
</p>
<p class=result>
The function returns the encoded string.
</p>
<pre class=example>
-- load url module
url = require("socket.url")
code = url.escape("/#?;")
-- code = "%2f%23%3f%3b"
</pre>
<!-- parse ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="parse">
url.<b>parse(</b>url, default<b>)</b>
</p>
<p class=description>
Parses an URL given as a string into a Lua table with its components.
</p>
<p class=parameters>
<tt>Url</tt> is the URL to be parsed. If the <tt>default</tt> table is
present, it is used to store the parsed fields. Only fields present in the
URL are overwritten. Therefore, this table can be used to pass default
values for each field.
</p>
<p class=return>
The function returns a table with all the URL components:
</p>
<blockquote><tt>
parsed_url = {<br>
&nbsp;&nbsp;url = <i>string</i>,<br>
&nbsp;&nbsp;scheme = <i>string</i>,<br>
&nbsp;&nbsp;authority = <i>string</i>,<br>
&nbsp;&nbsp;path = <i>string</i>,<br>
&nbsp;&nbsp;params = <i>string</i>,<br>
&nbsp;&nbsp;query = <i>string</i>,<br>
&nbsp;&nbsp;fragment = <i>string</i>,<br>
&nbsp;&nbsp;userinfo = <i>string</i>,<br>
&nbsp;&nbsp;host = <i>string</i>,<br>
&nbsp;&nbsp;port = <i>string</i>,<br>
&nbsp;&nbsp;user = <i>string</i>,<br>
&nbsp;&nbsp;password = <i>string</i><br>
}
</tt></blockquote>
<pre class=example>
-- load url module
url = require("socket.url")
parsed_url = url.parse("http://www.example.com/cgilua/index.lua?a=2#there")
-- parsed_url = {
-- scheme = "http",
-- authority = "www.example.com",
-- path = "/cgilua/index.lua"
-- query = "a=2",
-- fragment = "there",
-- host = "www.puc-rio.br",
-- }
parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
-- parsed_url = {
-- scheme = "ftp",
-- authority = "root:passwd@unsafe.org",
-- path = "/pub/virus.exe",
-- params = "type=i",
-- userinfo = "root:passwd",
-- host = "unsafe.org",
-- user = "root",
-- password = "passwd",
-- }
</pre>
<!-- parse_path +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="parse_path">
url.<b>parse_path(</b>path<b>)</b>
</p>
<p class=description>
Breaks a <tt>&lt;path&gt;</tt> URL component into all its
<tt>&lt;segment&gt;</tt> parts.
</p>
<p class=description>
<tt>Path</tt> is a string with the path to be parsed.
</p>
<p class=return>
Since some characters are reserved in URLs, they must be escaped
whenever present in a <tt>&lt;path&gt;</tt> component. Therefore, before
returning a list with all the parsed segments, the function removes
escaping from all of them.
</p>
<!-- unescape +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id="unescape">
url.<b>unescape(</b>content<b>)</b>
</p>
<p class=description>
Removes the URL escaping content coding from a string.
</p>
<p class=parameters>
<tt>Content</tt> is the string to be decoded.
</p>
<p class=return>
The function returns the decoded string.
</p>
<!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<div class=footer>
<hr>
<center>
<p class=bar>
<a href="index.html">home</a> &middot;
<a href="index.html#down">download</a> &middot;
<a href="installation.html">installation</a> &middot;
<a href="introduction.html">introduction</a> &middot;
<a href="reference.html">reference</a>
</p>
<p>
<small>
Last modified by Diego Nehab on <br>
Thu Apr 20 00:26:05 EDT 2006
</small>
</p>
</center>
</div>
</body>
</html>

View file

@ -0,0 +1,89 @@
This directory contains code that is more useful than the
samples. This code *is* supported.
tftp.lua -- Trivial FTP client
This module implements file retrieval by the TFTP protocol.
Its main use was to test the UDP code, but since someone
found it usefull, I turned it into a module that is almost
official (no uploads, yet).
dict.lua -- Dict client
The dict.lua module started with a cool simple client
for the DICT protocol, written by Luiz Henrique Figueiredo.
This new version has been converted into a library, similar
to the HTTP and FTP libraries, that can be used from within
any luasocket application. Take a look on the source code
and you will be able to figure out how to use it.
lp.lua -- LPD client library
The lp.lua module implements the client part of the Line
Printer Daemon protocol, used to print files on Unix
machines. It is courtesy of David Burgess! See the source
code and the lpr.lua in the examples directory.
b64.lua
qp.lua
eol.lua
These are tiny programs that perform Base64,
Quoted-Printable and end-of-line marker conversions.
get.lua -- file retriever
This little program is a client that uses the FTP and
HTTP code to implement a command line file graber. Just
run
lua get.lua <remote-file> [<local-file>]
to download a remote file (either ftp:// or http://) to
the specified local file. The program also prints the
download throughput, elapsed time, bytes already downloaded
etc during download.
check-memory.lua -- checks memory consumption
This is just to see how much memory each module uses.
dispatch.lua -- coroutine based dispatcher
This is a first try at a coroutine based non-blocking
dispatcher for LuaSocket. Take a look at 'check-links.lua'
and at 'forward.lua' to see how to use it.
check-links.lua -- HTML link checker program
This little program scans a HTML file and checks for broken
links. It is similar to check-links.pl by Jamie Zawinski,
but uses all facilities of the LuaSocket library and the Lua
language. It has not been thoroughly tested, but it should
work. Just run
lua check-links.lua [-n] {<url>} > output
and open the result to see a list of broken links. Make sure
you check the '-n' switch. It runs in non-blocking mode,
using coroutines, and is MUCH faster!
forward.lua -- coroutine based forward server
This is a forward server that can accept several connections
and transfers simultaneously using non-blocking I/O and the
coroutine-based dispatcher. You can run, for example
lua forward.lua 8080:proxy.com:3128
to redirect all local conections to port 8080 to the host
'proxy.com' at port 3128.
unix.c and unix.h
This is an implementation of Unix local domain sockets and
demonstrates how to extend LuaSocket with a new type of
transport. It has been tested on Linux and on Mac OS X.
Good luck,
Diego.

View file

@ -0,0 +1,19 @@
-----------------------------------------------------------------------------
-- Little program to convert to and from Base64
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local ltn12 = require("ltn12")
local mime = require("mime")
local source = ltn12.source.file(io.stdin)
local sink = ltn12.sink.file(io.stdout)
local convert
if arg and arg[1] == '-d' then
convert = mime.decode("base64")
else
local base64 = mime.encode("base64")
local wrap = mime.wrap()
convert = ltn12.filter.chain(base64, wrap)
end
sink = ltn12.sink.chain(convert, sink)
ltn12.pump.all(source, sink)

View file

@ -0,0 +1,111 @@
-----------------------------------------------------------------------------
-- Little program that checks links in HTML files, using coroutines and
-- non-blocking I/O via the dispatcher module.
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local url = require("socket.url")
local dispatch = require("dispatch")
local http = require("socket.http")
dispatch.TIMEOUT = 10
-- make sure the user knows how to invoke us
arg = arg or {}
if #arg < 1 then
print("Usage:\n luasocket check-links.lua [-n] {<url>}")
exit()
end
-- '-n' means we are running in non-blocking mode
if arg[1] == "-n" then
-- if non-blocking I/O was requested, use real dispatcher interface
table.remove(arg, 1)
handler = dispatch.newhandler("coroutine")
else
-- if using blocking I/O, use fake dispatcher interface
handler = dispatch.newhandler("sequential")
end
local nthreads = 0
-- get the status of a URL using the dispatcher
function getstatus(link)
local parsed = url.parse(link, {scheme = "file"})
if parsed.scheme == "http" then
nthreads = nthreads + 1
handler:start(function()
local r, c, h, s = http.request{
method = "HEAD",
url = link,
create = handler.tcp
}
if r and c == 200 then io.write('\t', link, '\n')
else io.write('\t', link, ': ', tostring(c), '\n') end
nthreads = nthreads - 1
end)
end
end
function readfile(path)
path = url.unescape(path)
local file, error = io.open(path, "r")
if file then
local body = file:read("*a")
file:close()
return body
else return nil, error end
end
function load(u)
local parsed = url.parse(u, { scheme = "file" })
local body, headers, code, error
local base = u
if parsed.scheme == "http" then
body, code, headers = http.request(u)
if code == 200 then
-- if there was a redirect, update base to reflect it
base = headers.location or base
end
if not body then
error = code
end
elseif parsed.scheme == "file" then
body, error = readfile(parsed.path)
else error = string.format("unhandled scheme '%s'", parsed.scheme) end
return base, body, error
end
function getlinks(body, base)
-- get rid of comments
body = string.gsub(body, "%<%!%-%-.-%-%-%>", "")
local links = {}
-- extract links
body = string.gsub(body, '[Hh][Rr][Ee][Ff]%s*=%s*"([^"]*)"', function(href)
table.insert(links, url.absolute(base, href))
end)
body = string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*'([^']*)'", function(href)
table.insert(links, url.absolute(base, href))
end)
string.gsub(body, "[Hh][Rr][Ee][Ff]%s*=%s*(.-)>", function(href)
table.insert(links, url.absolute(base, href))
end)
return links
end
function checklinks(address)
local base, body, error = load(address)
if not body then print(error) return end
print("Checking ", base)
local links = getlinks(body, base)
for _, link in ipairs(links) do
getstatus(link)
end
end
for _, address in ipairs(arg) do
checklinks(url.absolute("file:", address))
end
while nthreads > 0 do
handler:step()
end

View file

@ -0,0 +1,17 @@
function load(s)
collectgarbage()
local a = gcinfo()
_G[s] = require(s)
collectgarbage()
local b = gcinfo()
print(s .. ":\t " .. (b-a) .. "k")
end
load("socket.url")
load("ltn12")
load("socket")
load("mime")
load("socket.tp")
load("socket.smtp")
load("socket.http")
load("socket.ftp")

View file

@ -0,0 +1,88 @@
local socket = require"socket"
local http = require"socket.http"
local url = require"socket.url"
local ltn12 = require"ltn12"
local token_class = '[^%c%s%(%)%<%>%@%,%;%:%\\%"%/%[%]%?%=%{%}]'
local function unquote(t, quoted)
local n = string.match(t, "%$(%d+)$")
if n then n = tonumber(n) end
if quoted[n] then return quoted[n]
else return t end
end
local function parse_set_cookie(c, quoted, cookie_table)
c = c .. ";$last=last;"
local _, __, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=%s*(.-)%s*;%s*()")
local cookie = {
name = n,
value = unquote(v, quoted),
attributes = {}
}
while 1 do
_, __, n, v, i = string.find(c, "(" .. token_class ..
"+)%s*=?%s*(.-)%s*;%s*()", i)
if not n or n == "$last" then break end
cookie.attributes[#cookie.attributes+1] = {
name = n,
value = unquote(v, quoted)
}
end
cookie_table[#cookie_table+1] = cookie
end
local function split_set_cookie(s, cookie_table)
cookie_table = cookie_table or {}
-- remove quoted strings from cookie list
local quoted = {}
s = string.gsub(s, '"(.-)"', function(q)
quoted[#quoted+1] = q
return "$" .. #quoted
end)
-- add sentinel
s = s .. ",$last="
-- split into individual cookies
i = 1
while 1 do
local _, __, cookie, next_token
_, __, cookie, i, next_token = string.find(s, "(.-)%s*%,%s*()(" ..
token_class .. "+)%s*=", i)
if not next_token then break end
parse_set_cookie(cookie, quoted, cookie_table)
if next_token == "$last" then break end
end
return cookie_table
end
local function quote(s)
if string.find(s, "[ %,%;]") then return '"' .. s .. '"'
else return s end
end
local _empty = {}
local function build_cookies(cookies)
s = ""
for i,v in ipairs(cookies or _empty) do
if v.name then
s = s .. v.name
if v.value and v.value ~= "" then
s = s .. '=' .. quote(v.value)
end
end
if v.name and #(v.attributes or _empty) > 0 then s = s .. "; " end
for j,u in ipairs(v.attributes or _empty) do
if u.name then
s = s .. u.name
if u.value and u.value ~= "" then
s = s .. '=' .. quote(u.value)
end
end
if j < #v.attributes then s = s .. "; " end
end
if i < #cookies then s = s .. ", " end
end
return s
end

View file

@ -0,0 +1,151 @@
-----------------------------------------------------------------------------
-- Little program to download DICT word definitions
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Load required modules
-----------------------------------------------------------------------------
local base = _G
local string = require("string")
local table = require("table")
local socket = require("socket")
local url = require("socket.url")
local tp = require("socket.tp")
module("socket.dict")
-----------------------------------------------------------------------------
-- Globals
-----------------------------------------------------------------------------
HOST = "dict.org"
PORT = 2628
TIMEOUT = 10
-----------------------------------------------------------------------------
-- Low-level dict API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function open(host, port)
local tp = socket.try(tp.connect(host or HOST, port or PORT, TIMEOUT))
return base.setmetatable({tp = tp}, metat)
end
function metat.__index:greet()
return socket.try(self.tp:check(220))
end
function metat.__index:check(ok)
local code, status = socket.try(self.tp:check(ok))
return code,
base.tonumber(socket.skip(2, string.find(status, "^%d%d%d (%d*)")))
end
function metat.__index:getdef()
local line = socket.try(self.tp:receive())
local def = {}
while line ~= "." do
table.insert(def, line)
line = socket.try(self.tp:receive())
end
return table.concat(def, "\n")
end
function metat.__index:define(database, word)
database = database or "!"
socket.try(self.tp:command("DEFINE", database .. " " .. word))
local code, count = self:check(150)
local defs = {}
for i = 1, count do
self:check(151)
table.insert(defs, self:getdef())
end
self:check(250)
return defs
end
function metat.__index:match(database, strat, word)
database = database or "!"
strat = strat or "."
socket.try(self.tp:command("MATCH", database .." ".. strat .." ".. word))
self:check(152)
local mat = {}
local line = socket.try(self.tp:receive())
while line ~= '.' do
database, word = socket.skip(2, string.find(line, "(%S+) (.*)"))
if not mat[database] then mat[database] = {} end
table.insert(mat[database], word)
line = socket.try(self.tp:receive())
end
self:check(250)
return mat
end
function metat.__index:quit()
self.tp:command("QUIT")
return self:check(221)
end
function metat.__index:close()
return self.tp:close()
end
-----------------------------------------------------------------------------
-- High-level dict API
-----------------------------------------------------------------------------
local default = {
scheme = "dict",
host = "dict.org"
}
local function there(f)
if f == "" then return nil
else return f end
end
local function parse(u)
local t = socket.try(url.parse(u, default))
socket.try(t.scheme == "dict", "invalid scheme '" .. t.scheme .. "'")
socket.try(t.path, "invalid path in url")
local cmd, arg = socket.skip(2, string.find(t.path, "^/(.)(.*)$"))
socket.try(cmd == "d" or cmd == "m", "<command> should be 'm' or 'd'")
socket.try(arg and arg ~= "", "need at least <word> in URL")
t.command, t.argument = cmd, arg
arg = string.gsub(arg, "^:([^:]+)", function(f) t.word = f end)
socket.try(t.word, "need at least <word> in URL")
arg = string.gsub(arg, "^:([^:]*)", function(f) t.database = there(f) end)
if cmd == "m" then
arg = string.gsub(arg, "^:([^:]*)", function(f) t.strat = there(f) end)
end
string.gsub(arg, ":([^:]*)$", function(f) t.n = base.tonumber(f) end)
return t
end
local function tget(gett)
local con = open(gett.host, gett.port)
con:greet()
if gett.command == "d" then
local def = con:define(gett.database, gett.word)
con:quit()
con:close()
if gett.n then return def[gett.n]
else return def end
elseif gett.command == "m" then
local mat = con:match(gett.database, gett.strat, gett.word)
con:quit()
con:close()
return mat
else return nil, "invalid command" end
end
local function sget(u)
local gett = parse(u)
return tget(gett)
end
get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett)
else return tget(gett) end
end)

View file

@ -0,0 +1,307 @@
-----------------------------------------------------------------------------
-- A hacked dispatcher module
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
local string = require("string")
local socket = require("socket")
local coroutine = require("coroutine")
module("dispatch")
-- if too much time goes by without any activity in one of our sockets, we
-- just kill it
TIMEOUT = 60
-----------------------------------------------------------------------------
-- We implement 3 types of dispatchers:
-- sequential
-- coroutine
-- threaded
-- The user can choose whatever one is needed
-----------------------------------------------------------------------------
local handlert = {}
-- default handler is coroutine
function newhandler(mode)
mode = mode or "coroutine"
return handlert[mode]()
end
local function seqstart(self, func)
return func()
end
-- sequential handler simply calls the functions and doesn't wrap I/O
function handlert.sequential()
return {
tcp = socket.tcp,
start = seqstart
}
end
-----------------------------------------------------------------------------
-- Mega hack. Don't try to do this at home.
-----------------------------------------------------------------------------
-- we can't yield across calls to protect on Lua 5.1, so we rewrite it with
-- coroutines
-- make sure you don't require any module that uses socket.protect before
-- loading our hack
if string.sub(base._VERSION, -3) == "5.1" then
local function _protect(co, status, ...)
if not status then
local msg = ...
if base.type(msg) == 'table' then
return nil, msg[1]
else
base.error(msg, 0)
end
end
if coroutine.status(co) == "suspended" then
return _protect(co, coroutine.resume(co, coroutine.yield(...)))
else
return ...
end
end
function socket.protect(f)
return function(...)
local co = coroutine.create(f)
return _protect(co, coroutine.resume(co, ...))
end
end
end
-----------------------------------------------------------------------------
-- Simple set data structure. O(1) everything.
-----------------------------------------------------------------------------
local function newset()
local reverse = {}
local set = {}
return base.setmetatable(set, {__index = {
insert = function(set, value)
if not reverse[value] then
table.insert(set, value)
reverse[value] = #set
end
end,
remove = function(set, value)
local index = reverse[value]
if index then
reverse[value] = nil
local top = table.remove(set)
if top ~= value then
reverse[top] = index
set[index] = top
end
end
end
}})
end
-----------------------------------------------------------------------------
-- socket.tcp() wrapper for the coroutine dispatcher
-----------------------------------------------------------------------------
local function cowrap(dispatcher, tcp, error)
if not tcp then return nil, error end
-- put it in non-blocking mode right away
tcp:settimeout(0)
-- metatable for wrap produces new methods on demand for those that we
-- don't override explicitly.
local metat = { __index = function(table, key)
table[key] = function(...)
return tcp[key](tcp,select(2,...))
end
return table[key]
end}
-- does our user want to do his own non-blocking I/O?
local zero = false
-- create a wrap object that will behave just like a real socket object
local wrap = { }
-- we ignore settimeout to preserve our 0 timeout, but record whether
-- the user wants to do his own non-blocking I/O
function wrap:settimeout(value, mode)
if value == 0 then zero = true
else zero = false end
return 1
end
-- send in non-blocking mode and yield on timeout
function wrap:send(data, first, last)
first = (first or 1) - 1
local result, error
while true do
-- return control to dispatcher and tell it we want to send
-- if upon return the dispatcher tells us we timed out,
-- return an error to whoever called us
if coroutine.yield(dispatcher.sending, tcp) == "timeout" then
return nil, "timeout"
end
-- try sending
result, error, first = tcp:send(data, first+1, last)
-- if we are done, or there was an unexpected error,
-- break away from loop
if error ~= "timeout" then return result, error, first end
end
end
-- receive in non-blocking mode and yield on timeout
-- or simply return partial read, if user requested timeout = 0
function wrap:receive(pattern, partial)
local error = "timeout"
local value
while true do
-- return control to dispatcher and tell it we want to receive
-- if upon return the dispatcher tells us we timed out,
-- return an error to whoever called us
if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then
return nil, "timeout"
end
-- try receiving
value, error, partial = tcp:receive(pattern, partial)
-- if we are done, or there was an unexpected error,
-- break away from loop. also, if the user requested
-- zero timeout, return all we got
if (error ~= "timeout") or zero then
return value, error, partial
end
end
end
-- connect in non-blocking mode and yield on timeout
function wrap:connect(host, port)
local result, error = tcp:connect(host, port)
if error == "timeout" then
-- return control to dispatcher. we will be writable when
-- connection succeeds.
-- if upon return the dispatcher tells us we have a
-- timeout, just abort
if coroutine.yield(dispatcher.sending, tcp) == "timeout" then
return nil, "timeout"
end
-- when we come back, check if connection was successful
result, error = tcp:connect(host, port)
if result or error == "already connected" then return 1
else return nil, "non-blocking connect failed" end
else return result, error end
end
-- accept in non-blocking mode and yield on timeout
function wrap:accept()
while 1 do
-- return control to dispatcher. we will be readable when a
-- connection arrives.
-- if upon return the dispatcher tells us we have a
-- timeout, just abort
if coroutine.yield(dispatcher.receiving, tcp) == "timeout" then
return nil, "timeout"
end
local client, error = tcp:accept()
if error ~= "timeout" then
return cowrap(dispatcher, client, error)
end
end
end
-- remove cortn from context
function wrap:close()
dispatcher.stamp[tcp] = nil
dispatcher.sending.set:remove(tcp)
dispatcher.sending.cortn[tcp] = nil
dispatcher.receiving.set:remove(tcp)
dispatcher.receiving.cortn[tcp] = nil
return tcp:close()
end
return base.setmetatable(wrap, metat)
end
-----------------------------------------------------------------------------
-- Our coroutine dispatcher
-----------------------------------------------------------------------------
local cometat = { __index = {} }
function schedule(cortn, status, operation, tcp)
if status then
if cortn and operation then
operation.set:insert(tcp)
operation.cortn[tcp] = cortn
operation.stamp[tcp] = socket.gettime()
end
else base.error(operation) end
end
function kick(operation, tcp)
operation.cortn[tcp] = nil
operation.set:remove(tcp)
end
function wakeup(operation, tcp)
local cortn = operation.cortn[tcp]
-- if cortn is still valid, wake it up
if cortn then
kick(operation, tcp)
return cortn, coroutine.resume(cortn)
-- othrewise, just get scheduler not to do anything
else
return nil, true
end
end
function abort(operation, tcp)
local cortn = operation.cortn[tcp]
if cortn then
kick(operation, tcp)
coroutine.resume(cortn, "timeout")
end
end
-- step through all active cortns
function cometat.__index:step()
-- check which sockets are interesting and act on them
local readable, writable = socket.select(self.receiving.set,
self.sending.set, 1)
-- for all readable connections, resume their cortns and reschedule
-- when they yield back to us
for _, tcp in base.ipairs(readable) do
schedule(wakeup(self.receiving, tcp))
end
-- for all writable connections, do the same
for _, tcp in base.ipairs(writable) do
schedule(wakeup(self.sending, tcp))
end
-- politely ask replacement I/O functions in idle cortns to
-- return reporting a timeout
local now = socket.gettime()
for tcp, stamp in base.pairs(self.stamp) do
if tcp.class == "tcp{client}" and now - stamp > TIMEOUT then
abort(self.sending, tcp)
abort(self.receiving, tcp)
end
end
end
function cometat.__index:start(func)
local cortn = coroutine.create(func)
schedule(cortn, coroutine.resume(cortn))
end
function handlert.coroutine()
local stamp = {}
local dispatcher = {
stamp = stamp,
sending = {
name = "sending",
set = newset(),
cortn = {},
stamp = stamp
},
receiving = {
name = "receiving",
set = newset(),
cortn = {},
stamp = stamp
},
}
function dispatcher.tcp()
return cowrap(dispatcher, socket.tcp())
end
return base.setmetatable(dispatcher, cometat)
end

View file

@ -0,0 +1,13 @@
-----------------------------------------------------------------------------
-- Little program to adjust end of line markers.
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local mime = require("mime")
local ltn12 = require("ltn12")
local marker = '\n'
if arg and arg[1] == '-d' then marker = '\r\n' end
local filter = mime.normalize(marker)
local source = ltn12.source.chain(ltn12.source.file(io.stdin), filter)
local sink = ltn12.sink.file(io.stdout)
ltn12.pump.all(source, sink)

View file

@ -0,0 +1,65 @@
-- load our favourite library
local dispatch = require("dispatch")
local handler = dispatch.newhandler()
-- make sure the user knows how to invoke us
if #arg < 1 then
print("Usage")
print(" lua forward.lua <iport:ohost:oport> ...")
os.exit(1)
end
-- function to move data from one socket to the other
local function move(foo, bar)
local live
while 1 do
local data, error, partial = foo:receive(2048)
live = data or error == "timeout"
data = data or partial
local result, error = bar:send(data)
if not live or not result then
foo:close()
bar:close()
break
end
end
end
-- for each tunnel, start a new server
for i, v in ipairs(arg) do
-- capture forwarding parameters
local _, _, iport, ohost, oport = string.find(v, "([^:]+):([^:]+):([^:]+)")
assert(iport, "invalid arguments")
-- create our server socket
local server = assert(handler.tcp())
assert(server:setoption("reuseaddr", true))
assert(server:bind("*", iport))
assert(server:listen(32))
-- handler for the server object loops accepting new connections
handler:start(function()
while 1 do
local client = assert(server:accept())
assert(client:settimeout(0))
-- for each new connection, start a new client handler
handler:start(function()
-- handler tries to connect to peer
local peer = assert(handler.tcp())
assert(peer:settimeout(0))
assert(peer:connect(ohost, oport))
-- if sucessful, starts a new handler to send data from
-- client to peer
handler:start(function()
move(client, peer)
end)
-- afte starting new handler, enter in loop sending data from
-- peer to client
move(peer, client)
end)
end
end)
end
-- simply loop stepping the server
while 1 do
handler:step()
end

View file

@ -0,0 +1,141 @@
-----------------------------------------------------------------------------
-- Little program to download files from URLs
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local socket = require("socket")
local http = require("socket.http")
local ftp = require("socket.ftp")
local url = require("socket.url")
local ltn12 = require("ltn12")
-- formats a number of seconds into human readable form
function nicetime(s)
local l = "s"
if s > 60 then
s = s / 60
l = "m"
if s > 60 then
s = s / 60
l = "h"
if s > 24 then
s = s / 24
l = "d" -- hmmm
end
end
end
if l == "s" then return string.format("%5.0f%s", s, l)
else return string.format("%5.2f%s", s, l) end
end
-- formats a number of bytes into human readable form
function nicesize(b)
local l = "B"
if b > 1024 then
b = b / 1024
l = "KB"
if b > 1024 then
b = b / 1024
l = "MB"
if b > 1024 then
b = b / 1024
l = "GB" -- hmmm
end
end
end
return string.format("%7.2f%2s", b, l)
end
-- returns a string with the current state of the download
local remaining_s = "%s received, %s/s throughput, %2.0f%% done, %s remaining"
local elapsed_s = "%s received, %s/s throughput, %s elapsed "
function gauge(got, delta, size)
local rate = got / delta
if size and size >= 1 then
return string.format(remaining_s, nicesize(got), nicesize(rate),
100*got/size, nicetime((size-got)/rate))
else
return string.format(elapsed_s, nicesize(got),
nicesize(rate), nicetime(delta))
end
end
-- creates a new instance of a receive_cb that saves to disk
-- kind of copied from luasocket's manual callback examples
function stats(size)
local start = socket.gettime()
local last = start
local got = 0
return function(chunk)
-- elapsed time since start
local current = socket.gettime()
if chunk then
-- total bytes received
got = got + string.len(chunk)
-- not enough time for estimate
if current - last > 1 then
io.stderr:write("\r", gauge(got, current - start, size))
io.stderr:flush()
last = current
end
else
-- close up
io.stderr:write("\r", gauge(got, current - start), "\n")
end
return chunk
end
end
-- determines the size of a http file
function gethttpsize(u)
local r, c, h = http.request {method = "HEAD", url = u}
if c == 200 then
return tonumber(h["content-length"])
end
end
-- downloads a file using the http protocol
function getbyhttp(u, file)
local save = ltn12.sink.file(file or io.stdout)
-- only print feedback if output is not stdout
if file then save = ltn12.sink.chain(stats(gethttpsize(u)), save) end
local r, c, h, s = http.request {url = u, sink = save }
if c ~= 200 then io.stderr:write(s or c, "\n") end
end
-- downloads a file using the ftp protocol
function getbyftp(u, file)
local save = ltn12.sink.file(file or io.stdout)
-- only print feedback if output is not stdout
-- and we don't know how big the file is
if file then save = ltn12.sink.chain(stats(), save) end
local gett = url.parse(u)
gett.sink = save
gett.type = "i"
local ret, err = ftp.get(gett)
if err then print(err) end
end
-- determines the scheme
function getscheme(u)
-- this is an heuristic to solve a common invalid url poblem
if not string.find(u, "//") then u = "//" .. u end
local parsed = url.parse(u, {scheme = "http"})
return parsed.scheme
end
-- gets a file either by http or ftp, saving as <name>
function get(u, name)
local fout = name and io.open(name, "wb")
local scheme = getscheme(u)
if scheme == "ftp" then getbyftp(u, fout)
elseif scheme == "http" then getbyhttp(u, fout)
else print("unknown scheme" .. scheme) end
end
-- main program
arg = arg or {}
if #arg < 1 then
io.write("Usage:\n lua get.lua <remote-url> [<local-file>]\n")
os.exit(1)
else get(arg[1], arg[2]) end

View file

@ -0,0 +1,17 @@
<a href="http://www.cs.princeton.edu"> bla </a>
<a href="http://www.princeton.edu"> bla </a>
<a href="http://www.tecgraf.puc-rio.br"> bla </a>
<a href="http://www.inf.puc-rio.br"> bla </a>
<a href="http://www.puc-rio.br"> bla </a>
<a href="http://www.impa.br"> bla </a>
<a href="http://www.lua.org"> bla </a>
<a href="http://www.lua-users.org"> bla </a>
<a href="http://www.amazon.com"> bla </a>
<a href="http://www.google.com"> bla </a>
<a href="http://www.nytimes.com"> bla </a>
<a href="http://www.bbc.co.uk"> bla </a>
<a href="http://oglobo.globo.com"> bla </a>
<a href="http://slate.msn.com"> bla </a>
<a href="http://www.apple.com"> bla </a>
<a href="http://www.microsoft.com"> bla </a>
<a href="http://www.nasa.gov"> bla </a>

View file

@ -0,0 +1,323 @@
-----------------------------------------------------------------------------
-- LPD support for the Lua language
-- LuaSocket toolkit.
-- Author: David Burgess
-- Modified by Diego Nehab, but David is in charge
-----------------------------------------------------------------------------
--[[
if you have any questions: RFC 1179
]]
-- make sure LuaSocket is loaded
local io = require("io")
local base = _G
local os = require("os")
local math = require("math")
local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
module("socket.lp")
-- default port
PORT = 515
SERVER = os.getenv("SERVER_NAME") or os.getenv("COMPUTERNAME") or "localhost"
PRINTER = os.getenv("PRINTER") or "printer"
local function connect(localhost, option)
local host = option.host or SERVER
local port = option.port or PORT
local skt
local try = socket.newtry(function() if skt then skt:close() end end)
if option.localbind then
-- bind to a local port (if we can)
local localport = 721
local done, err
repeat
skt = socket.try(socket.tcp())
try(skt:settimeout(30))
done, err = skt:bind(localhost, localport)
if not done then
localport = localport + 1
skt:close()
skt = nil
else break end
until localport > 731
socket.try(skt, err)
else skt = socket.try(socket.tcp()) end
try(skt:connect(host, port))
return { skt = skt, try = try }
end
--[[
RFC 1179
5.3 03 - Send queue state (short)
+----+-------+----+------+----+
| 03 | Queue | SP | List | LF |
+----+-------+----+------+----+
Command code - 3
Operand 1 - Printer queue name
Other operands - User names or job numbers
If the user names or job numbers or both are supplied then only those
jobs for those users or with those numbers will be sent.
The response is an ASCII stream which describes the printer queue.
The stream continues until the connection closes. Ends of lines are
indicated with ASCII LF control characters. The lines may also
contain ASCII HT control characters.
5.4 04 - Send queue state (long)
+----+-------+----+------+----+
| 04 | Queue | SP | List | LF |
+----+-------+----+------+----+
Command code - 4
Operand 1 - Printer queue name
Other operands - User names or job numbers
If the user names or job numbers or both are supplied then only those
jobs for those users or with those numbers will be sent.
The response is an ASCII stream which describes the printer queue.
The stream continues until the connection closes. Ends of lines are
indicated with ASCII LF control characters. The lines may also
contain ASCII HT control characters.
]]
-- gets server acknowledement
local function recv_ack(con)
local ack = con.skt:receive(1)
con.try(string.char(0) == ack, "failed to receive server acknowledgement")
end
-- sends client acknowledement
local function send_ack(con)
local sent = con.skt:send(string.char(0))
con.try(sent == 1, "failed to send acknowledgement")
end
-- sends queue request
-- 5.2 02 - Receive a printer job
--
-- +----+-------+----+
-- | 02 | Queue | LF |
-- +----+-------+----+
-- Command code - 2
-- Operand - Printer queue name
--
-- Receiving a job is controlled by a second level of commands. The
-- daemon is given commands by sending them over the same connection.
-- The commands are described in the next section (6).
--
-- After this command is sent, the client must read an acknowledgement
-- octet from the daemon. A positive acknowledgement is an octet of
-- zero bits. A negative acknowledgement is an octet of any other
-- pattern.
local function send_queue(con, queue)
queue = queue or PRINTER
local str = string.format("\2%s\10", queue)
local sent = con.skt:send(str)
con.try(sent == string.len(str), "failed to send print request")
recv_ack(con)
end
-- sends control file
-- 6.2 02 - Receive control file
--
-- +----+-------+----+------+----+
-- | 02 | Count | SP | Name | LF |
-- +----+-------+----+------+----+
-- Command code - 2
-- Operand 1 - Number of bytes in control file
-- Operand 2 - Name of control file
--
-- The control file must be an ASCII stream with the ends of lines
-- indicated by ASCII LF. The total number of bytes in the stream is
-- sent as the first operand. The name of the control file is sent as
-- the second. It should start with ASCII "cfA", followed by a three
-- digit job number, followed by the host name which has constructed the
-- control file. Acknowledgement processing must occur as usual after
-- the command is sent.
--
-- The next "Operand 1" octets over the same TCP connection are the
-- intended contents of the control file. Once all of the contents have
-- been delivered, an octet of zero bits is sent as an indication that
-- the file being sent is complete. A second level of acknowledgement
-- processing must occur at this point.
-- sends data file
-- 6.3 03 - Receive data file
--
-- +----+-------+----+------+----+
-- | 03 | Count | SP | Name | LF |
-- +----+-------+----+------+----+
-- Command code - 3
-- Operand 1 - Number of bytes in data file
-- Operand 2 - Name of data file
--
-- The data file may contain any 8 bit values at all. The total number
-- of bytes in the stream may be sent as the first operand, otherwise
-- the field should be cleared to 0. The name of the data file should
-- start with ASCII "dfA". This should be followed by a three digit job
-- number. The job number should be followed by the host name which has
-- constructed the data file. Interpretation of the contents of the
-- data file is determined by the contents of the corresponding control
-- file. If a data file length has been specified, the next "Operand 1"
-- octets over the same TCP connection are the intended contents of the
-- data file. In this case, once all of the contents have been
-- delivered, an octet of zero bits is sent as an indication that the
-- file being sent is complete. A second level of acknowledgement
-- processing must occur at this point.
local function send_hdr(con, control)
local sent = con.skt:send(control)
con.try(sent and sent >= 1 , "failed to send header file")
recv_ack(con)
end
local function send_control(con, control)
local sent = con.skt:send(control)
con.try(sent and sent >= 1, "failed to send control file")
send_ack(con)
end
local function send_data(con,fh,size)
local buf
while size > 0 do
buf,message = fh:read(8192)
if buf then
st = con.try(con.skt:send(buf))
size = size - st
else
con.try(size == 0, "file size mismatch")
end
end
recv_ack(con) -- note the double acknowledgement
send_ack(con)
recv_ack(con)
return size
end
--[[
local control_dflt = {
"H"..string.sub(socket.hostname,1,31).."\10", -- host
"C"..string.sub(socket.hostname,1,31).."\10", -- class
"J"..string.sub(filename,1,99).."\10", -- jobname
"L"..string.sub(user,1,31).."\10", -- print banner page
"I"..tonumber(indent).."\10", -- indent column count ('f' only)
"M"..string.sub(mail,1,128).."\10", -- mail when printed user@host
"N"..string.sub(filename,1,131).."\10", -- name of source file
"P"..string.sub(user,1,31).."\10", -- user name
"T"..string.sub(title,1,79).."\10", -- title for banner ('p' only)
"W"..tonumber(width or 132).."\10", -- width of print f,l,p only
"f"..file.."\10", -- formatted print (remove control chars)
"l"..file.."\10", -- print
"o"..file.."\10", -- postscript
"p"..file.."\10", -- pr format - requires T, L
"r"..file.."\10", -- fortran format
"U"..file.."\10", -- Unlink (data file only)
}
]]
-- generate a varying job number
local seq = 0
local function newjob(connection)
seq = seq + 1
return math.floor(socket.gettime() * 1000 + seq)%1000
end
local format_codes = {
binary = 'l',
text = 'f',
ps = 'o',
pr = 'p',
fortran = 'r',
l = 'l',
r = 'r',
o = 'o',
p = 'p',
f = 'f'
}
-- lp.send{option}
-- requires option.file
send = socket.protect(function(option)
socket.try(option and base.type(option) == "table", "invalid options")
local file = option.file
socket.try(file, "invalid file name")
local fh = socket.try(io.open(file,"rb"))
local datafile_size = fh:seek("end") -- get total size
fh:seek("set") -- go back to start of file
local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME")
or "localhost"
local con = connect(localhost, option)
-- format the control file
local jobno = newjob()
local localip = socket.dns.toip(localhost)
localhost = string.sub(localhost,1,31)
local user = string.sub(option.user or os.getenv("LPRUSER") or
os.getenv("USERNAME") or os.getenv("USER") or "anonymous", 1,31)
local lpfile = string.format("dfA%3.3d%-s", jobno, localhost);
local fmt = format_codes[option.format] or 'l'
local class = string.sub(option.class or localip or localhost,1,31)
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
ctlfn = string.sub(ctlfn or file,1,131)
local cfile =
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
localhost,
class,
option.job or "LuaSocket",
user,
fmt, lpfile,
lpfile,
ctlfn); -- mandatory part of ctl file
if (option.banner) then cfile = cfile .. 'L'..user..'\10' end
if (option.indent) then cfile = cfile .. 'I'..base.tonumber(option.indent)..'\10' end
if (option.mail) then cfile = cfile .. 'M'..string.sub((option.mail),1,128)..'\10' end
if (fmt == 'p' and option.title) then cfile = cfile .. 'T'..string.sub((option.title),1,79)..'\10' end
if ((fmt == 'p' or fmt == 'l' or fmt == 'f') and option.width) then
cfile = cfile .. 'W'..base.tonumber(option,width)..'\10'
end
con.skt:settimeout(option.timeout or 65)
-- send the queue header
send_queue(con, option.queue)
-- send the control file header
local cfilecmd = string.format("\2%d cfA%3.3d%-s\n",string.len(cfile), jobno, localhost);
send_hdr(con,cfilecmd)
-- send the control file
send_control(con,cfile)
-- send the data file header
local dfilecmd = string.format("\3%d dfA%3.3d%-s\n",datafile_size, jobno, localhost);
send_hdr(con,dfilecmd)
-- send the data file
send_data(con,fh,datafile_size)
fh:close()
con.skt:close();
return jobno, datafile_size
end)
--
-- lp.query({host=,queue=printer|'*', format='l'|'s', list=})
--
query = socket.protect(function(p)
p = p or {}
local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME")
or "localhost"
local con = connect(localhost,p)
local fmt
if string.sub(p.format or 's',1,1) == 's' then fmt = 3 else fmt = 4 end
con.try(con.skt:send(string.format("%c%s %s\n", fmt, p.queue or "*",
p.list or "")))
local data = con.try(con.skt:receive("*a"))
con.skt:close()
return data
end)

View file

@ -0,0 +1,23 @@
-----------------------------------------------------------------------------
-- Little program to convert to and from Quoted-Printable
-- LuaSocket sample files
-- Author: Diego Nehab
-----------------------------------------------------------------------------
local ltn12 = require("ltn12")
local mime = require("mime")
local convert
arg = arg or {}
local mode = arg and arg[1] or "-et"
if mode == "-et" then
local normalize = mime.normalize()
local qp = mime.encode("quoted-printable")
local wrap = mime.wrap("quoted-printable")
convert = ltn12.filter.chain(normalize, qp, wrap)
elseif mode == "-eb" then
local qp = mime.encode("quoted-printable", "binary")
local wrap = mime.wrap("quoted-printable")
convert = ltn12.filter.chain(qp, wrap)
else convert = mime.decode("quoted-printable") end
local source = ltn12.source.chain(ltn12.source.file(io.stdin), convert)
local sink = ltn12.sink.file(io.stdout)
ltn12.pump.all(source, sink)

View file

@ -0,0 +1,154 @@
-----------------------------------------------------------------------------
-- TFTP support for the Lua language
-- LuaSocket toolkit.
-- Author: Diego Nehab
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Load required files
-----------------------------------------------------------------------------
local base = _G
local table = require("table")
local math = require("math")
local string = require("string")
local socket = require("socket")
local ltn12 = require("ltn12")
local url = require("socket.url")
module("socket.tftp")
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
local char = string.char
local byte = string.byte
PORT = 69
local OP_RRQ = 1
local OP_WRQ = 2
local OP_DATA = 3
local OP_ACK = 4
local OP_ERROR = 5
local OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"}
-----------------------------------------------------------------------------
-- Packet creation functions
-----------------------------------------------------------------------------
local function RRQ(source, mode)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
end
local function WRQ(source, mode)
return char(0, OP_RRQ) .. source .. char(0) .. mode .. char(0)
end
local function ACK(block)
local low, high
low = math.mod(block, 256)
high = (block - low)/256
return char(0, OP_ACK, high, low)
end
local function get_OP(dgram)
local op = byte(dgram, 1)*256 + byte(dgram, 2)
return op
end
-----------------------------------------------------------------------------
-- Packet analysis functions
-----------------------------------------------------------------------------
local function split_DATA(dgram)
local block = byte(dgram, 3)*256 + byte(dgram, 4)
local data = string.sub(dgram, 5)
return block, data
end
local function get_ERROR(dgram)
local code = byte(dgram, 3)*256 + byte(dgram, 4)
local msg
_,_, msg = string.find(dgram, "(.*)\000", 5)
return string.format("error code %d: %s", code, msg)
end
-----------------------------------------------------------------------------
-- The real work
-----------------------------------------------------------------------------
local function tget(gett)
local retries, dgram, sent, datahost, dataport, code
local last = 0
socket.try(gett.host, "missing host")
local con = socket.try(socket.udp())
local try = socket.newtry(function() con:close() end)
-- convert from name to ip if needed
gett.host = try(socket.dns.toip(gett.host))
con:settimeout(1)
-- first packet gives data host/port to be used for data transfers
local path = string.gsub(gett.path or "", "^/", "")
path = url.unescape(path)
retries = 0
repeat
sent = try(con:sendto(RRQ(path, "octet"), gett.host, gett.port))
dgram, datahost, dataport = con:receivefrom()
retries = retries + 1
until dgram or datahost ~= "timeout" or retries > 5
try(dgram, datahost)
-- associate socket with data host/port
try(con:setpeername(datahost, dataport))
-- default sink
local sink = gett.sink or ltn12.sink.null()
-- process all data packets
while 1 do
-- decode packet
code = get_OP(dgram)
try(code ~= OP_ERROR, get_ERROR(dgram))
try(code == OP_DATA, "unhandled opcode " .. code)
-- get data packet parts
local block, data = split_DATA(dgram)
-- if not repeated, write
if block == last+1 then
try(sink(data))
last = block
end
-- last packet brings less than 512 bytes of data
if string.len(data) < 512 then
try(con:send(ACK(block)))
try(con:close())
try(sink(nil))
return 1
end
-- get the next packet
retries = 0
repeat
sent = try(con:send(ACK(last)))
dgram, err = con:receive()
retries = retries + 1
until dgram or err ~= "timeout" or retries > 5
try(dgram, err)
end
end
local default = {
port = PORT,
path ="/",
scheme = "tftp"
}
local function parse(u)
local t = socket.try(url.parse(u, default))
socket.try(t.scheme == "tftp", "invalid scheme '" .. t.scheme .. "'")
socket.try(t.host, "invalid host")
return t
end
local function sget(u)
local gett = parse(u)
local t = {}
gett.sink = ltn12.sink.table(t)
tget(gett)
return table.concat(t)
end
get = socket.protect(function(gett)
if base.type(gett) == "string" then return sget(gett)
else return tget(gett) end
end)

View file

@ -0,0 +1,4 @@
local CRLF = "\013\010"
local input = source.chain(source.file(io.stdin), normalize(CRLF))
local output = sink.file(io.stdout)
pump.all(input, output)

View file

@ -0,0 +1,17 @@
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
if chunk and ret then return 1
else return nil, src_err or snk_err end
end
function pump.all(src, snk, step)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then
if err then return nil, err
else return 1 end
end
end
end

View file

@ -0,0 +1,7 @@
local input = source.chain(
source.file(io.open("input.bin", "rb")),
encode("base64"))
local output = sink.chain(
wrap(76),
sink.file(io.open("output.b64", "w")))
pump.all(input, output)

View file

@ -0,0 +1,34 @@
local smtp = require"socket.smtp"
local mime = require"mime"
local ltn12 = require"ltn12"
CRLF = "\013\010"
local message = smtp.message{
headers = {
from = "Sicrano <sicrano@example.com>",
to = "Fulano <fulano@example.com>",
subject = "A message with an attachment"},
body = {
preamble = "Hope you can see the attachment" .. CRLF,
[1] = {
body = "Here is our logo" .. CRLF},
[2] = {
headers = {
["content-type"] = 'image/png; name="luasocket.png"',
["content-disposition"] =
'attachment; filename="luasocket.png"',
["content-description"] = 'LuaSocket logo',
["content-transfer-encoding"] = "BASE64"},
body = ltn12.source.chain(
ltn12.source.file(io.open("luasocket.png", "rb")),
ltn12.filter.chain(
mime.encode("base64"),
mime.wrap()))}}}
assert(smtp.send{
rcpt = "<diego@cs.princeton.edu>",
from = "<diego@cs.princeton.edu>",
server = "localhost",
port = 2525,
source = message})

View file

@ -0,0 +1,11 @@
function filter.cycle(lowlevel, context, extra)
return function(chunk)
local ret
ret, context = lowlevel(context, chunk, extra)
return ret
end
end
function normalize(marker)
return filter.cycle(eol, 0, marker)
end

View file

@ -0,0 +1,15 @@
local function chainpair(f1, f2)
return function(chunk)
local ret = f2(f1(chunk))
if chunk then return ret
else return (ret or "") .. (f2() or "") end
end
end
function filter.chain(...)
local f = select(1, ...)
for i = 2, select('#', ...) do
f = chainpair(f, select(i, ...))
end
return f
end

View file

@ -0,0 +1,5 @@
local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
wrap("quoted-printable"))
local input = source.chain(source.file(io.stdin), qp)
local output = sink.file(io.stdout)
pump.all(input, output)

View file

@ -0,0 +1,15 @@
function source.empty(err)
return function()
return nil, err
end
end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(20)
if not chunk then handle:close() end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end

View file

@ -0,0 +1,14 @@
function source.chain(src, f)
return function()
if not src then
return nil
end
local chunk, err = src()
if not chunk then
src = nil
return f(nil)
else
return f(chunk)
end
end
end

View file

@ -0,0 +1,16 @@
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
local function null()
return 1
end
function sink.null()
return null
end

View file

@ -0,0 +1,5 @@
local input = source.file(io.stdin)
local output, t = sink.table()
output = sink.chain(normalize(CRLF), output)
pump.all(input, output)
io.write(table.concat(t))

View file

@ -0,0 +1,3 @@
for chunk in source.file(io.stdin) do
io.write(chunk)
end

View file

@ -0,0 +1,54 @@
#include "lua.h"
#include "lauxlib.h"
#define CR '\xD'
#define LF '\xA'
#define CRLF "\xD\xA"
#define candidate(c) (c == CR || c == LF)
static int pushchar(int c, int last, const char *marker,
luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last)
luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_putchar(buffer, c);
return 0;
}
}
static int eol(lua_State *L) {
int context = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
while (input < last)
context = pushchar(*input++, context, marker, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, context);
return 2;
}
static luaL_reg func[] = {
{ "eol", eol },
{ NULL, NULL }
};
int luaopen_gem(lua_State *L) {
luaL_openlib(L, "gem", func, 0);
return 0;
}

View file

@ -0,0 +1,206 @@
iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAtU0lEQVR42u19eXRURdb4rarXa5LO
RshKEshC2MLOBIjsCoMLGJhRPnUEcUGZEX7j4Iw6zqd+zjkzzowL6gzKMOoBRHAAPyQKUZQlxLAk
EIEkQkhCyEoISegs3f1eVf3+qPTj0Z3udEJImN/Pe/rkdF6/V6/q3qp7b92tEOccfoT+A9zfHfj/
HX4kQD/DjwToZ/iRAP0MPxKgn+FHAvQz/EiAfgapvzvQQ3DfviCE+rtTPYH/AAKouEYIcc4ForUX
tXeKexhj6k8IIe2DvdUl0SYAcN7RGYQ63oAQ4hx8fBu6BXfC6vBcsHyDeNRi7cYboZQjBIRgl/lB
KQcAQnyl+q1IAC9YU7/s2bOnsrKSUupwOHQ63cMPP2wymRhjGOOrV6/m5ORYLJbg4OABAwZYLBaD
waBtQUsD34mqRT0hHc/abEpNjbWlxYEQCgw0RET463QEABjjjHFfyND/LEg737XsQpblhoaGioqK
CxcunD9/fv78+ampqepgZFk2mUwBAQEYY6PRSAhRG7Tb7cXFxXa73W63W63Wn/zkJ4sXL1YfVHGB
EFI5VZc0EDcwxjnnkoRbWhw7dxZt316Yn19TW9siyxQADAZddHRAWlrMffeNnDcvUa8nlDKEAGNv
7ffbClCnoYoFFRFiIufn53/88cfBwcERERERERHjxo2LjIz0ZbaqFLXb7ZcuXZIkKSoqShAYY7xn
z576+vpJkybFxcUZjUZfOJKKfQBACP75z/yXXtpfXX0JAAFIAAQAAXAADsAAZAA0dGjMa6/Nueee
FEoZQsgLDfqTAFqWIstyRUVFXFycJEniJ6vV2tTUFBUVRQhxkb0q2TTS7xr9tNxG/bdjtAjl5eXl
5ubW1dUhhJKTkzMyMkwmk0p4AMAYq91Tv1DKCMENDW0PPLBj797vEdJjrAfgjF2HP+d8B8YcAMry
5VP//vf5Oh3h3OM66P8V0NTU9N133+Xl5SmKsnr16qCgIBc8MsbE5HXXgjqdU9oRie8YY5c2W1tb
CwsLS0tLFy5cqEoILWnFI84rHGNUXW29/fYPCwsvSpI/pQLxntYNxxhjDIpinTNn1K5d/2Uy6Zwd
cNWO+o4A7mjFGOfk5OzcuTMsLGzixInjxo2zWCwqIlSpAL2k47tMc+18FN8vXLgAAHFxce4Cqa1N
njlzw9GjZZLkryiK6KP3twEgnY7I8tWf/WzCtm33McZVJVV7H3nppZf6BvXaL+rAFEVJSEhYvHjx
4MGDDQaDykxAw1h6S38XLxUcRnRGnXyiM4cOHdqyZUtDQ0N0dLSfn5/4SUz/Z57Zs3PnCZ0uQFEU
ANQV9jvIwxiTJOPp0xdCQgLS0gZRyjF2Hc5NXwEu866lpUWv1+v1enVBqFsnwWS0dLrZ4K7dlpSU
ZGZmVlVVpaen33PPPYL1HzlSOXnyewCk+6gSo2OhocaCgl9GR1vEOtCO7qbbglQsY4yPHj366quv
nj59GjScWtBGq0f2mVHBZbVxzhMSElatWvXzn//cORUAANau/Y5zB8YYoLsUQJxzQqSGhqb1648D
gFClXO+4eSNUZ9alS5e2b99eXl4+d+7cqVOnCrl361hvOt2LCNWlttY6bNjbTU22Hk9WhBDnjhEj
IgoKVoqdc1+vAFmW//WvfymK8uyzz86aNUvlP72HPrjBWaR2RkgIoXeJ2ZqbW9nUdBVj0uPGOecA
ujNn6s+cuQRui6CXd8JaJUedSsJUEBoaqtfrtdd9p4HQ3rTGL9UE1ik2BZ/trmnMRePinAFAQUEt
AMMYuXMP34EQRKnjzJlLqakRLr3uTQJoJarLzigyMpIxJiStVr/0pTXOQdgAMEaEYACOEPb+tKCU
UOEVhYq9qKCKTwYyzW0XL169cUaNEAJglZVXwc2Q3msE0GKfEFJYWGg2m+Pj41UtyMeJr8W7olCB
dFVS2mxKZeXVqqqrFRXN9fVtDQ1tbW2yw0EBQK8nJpNuwABTWJjfoEGB0dEBMTEWk0mHEBYPU8oY
Y04S+roEbTalt1Bkt1P3i728AjjnhJCjR49u3rw5IyNDEACcvBW8ajgqRhSFCUsvQhghVF/fmptb
efjwxWPHqs6da6iutlLqAFA86yQIQCJEHxkZkJQUMnFi9JQpg9LSYsLD/THusCtw3mHR7JIMfn66
3sKP2dxJU70sAzDGBw4c2Llz5/333z958mRVqfD+lBb1GCNhxa2oaP788x8++6z4yJFKq9UKQAGI
+CCkw1jvqVkhPylllZVXKivrv/22EID4+wdMmhS9YEHKggVD4+KCxAqjlHkig9DfASA+PkismO7r
oNeAMQ6A4+ODwG0K9o4aqtoajx07tnnz5mXLlo0ePVplO12iXhjZMUYYI1mme/aUrF+f/9VXJTZb
CwAG0GFMhDHLxfjlHQTTF/KTMQogAzCDwW/27ITHHhs/f36SXk+8GO4VhUkSzsoqmTv3XxgbbkQI
A3BJQmfO/DI5eYAQhL1JAK0l68qVK1euXElMTOyS6av6EqViI4bb2+WNGwveeCO3uLgSAAAMhBCA
Dh/TjQMhCABRSgHsAJCUFL16ddrDD4/289OrfQDNahBGiKYm2/Dha2tqrAj1YCcMAIAxYsw+aVLs
kSMr3G2IN7QPcOqFXJ3IISEhCQkJvmBfaIeKIqQifPDBiREj3n3iiW3FxTUYmwgxCWT1FvYBgFJO
KQVAhJgwNp07V7ty5afDh7+7fn0e50AIVhTGmNZiCIrCgoKMixYNB7D3aCcMTvalPPjgGNEHl597
vgI8Gd8FL/JkLnaf+IcPV6xatScv7zxCEsYGdQd0k6HDvs2Yg3PH6NFD3npr3vTp8Wqv1D0Hxqik
5MrYse+0tFCn48X3LSTHGDMmJySEnDjxy4AAfa+tAK1yWVpampubqxJDMLhOub9W2BKC29uVX/7y
i/T09/LyygjxQ0hPKe0T7AMAYoxTShGSCPEvKKiYMWP9E0/sbm11iKXgHAIoCktMDHnxxVkAbTpd
t9DFnahW/vSneQEBHYzOBS09IYA62THGra2tmzZtOnfunO9PCeF25Ejl+PHr3n13PyE6jI1O1Pex
dQgxBpRSjA2E6N9//+DYseuysyskCVPKBTsiBDHGn302ffHiCbJs1ekkJ3K7GC5CSKfDlFrXrJm1
ePFwShnGnYyuJwTQ+vk2bdrk5+e3ZMkS9Scv2GeMU8p1OvLOO0enTn3v7Nk6QvwpFQbRfjTMIcYY
pZwQ/9LS+mnT3n/99e8kCQtmKNYB53zTpkV33jlGlpslSWzIPZFBhKUQjLksW596auZrr92hYt8d
Pz1cAQKhmZmZpaWlS5culSRJsKNOJYrWqY0xeuKJz3/1q38DYIz1lIrNYT9gHyFXAxGlFGM9xtIz
z+xctuwzYUESXnXOQacj//u/S3796zsUxU6pDSGQJEKIsHB0fAhBkkQQ4pS2Ygyvv77o3XfvFNjv
zagIVZLs27cvMDBwwoQJqpHHE98Xno3WVvlnP9v65ZcFkhSgKKybAu0GgQMgse2iVIQviIFjjDHG
YnvccZskYUWxzp49cseO+y0Wg+i82DFIEj58uOL55/cdPFgKYHfuDcUoGAAFYISY77572B//OGv4
8DBFYd6jg3pIAE8hCF6w39xsu+uuTdnZZyXJv2+x34F6xhjndgAOoPfzM5nNEqXcarXLsg1AAdBh
rIcOB5GgQcukSQlffPGL0FCTGIJgSmI65+VV79xZnJNzsby8UQ3MSkgImT49PiNjWHJyqBrC5d3u
1A0CuHstvOv7KufBGFmtjnnzPsrJKZEkP0WhfTnxnV1t0+mMs2YlLVyYMnFiVHS0xWzWUcqammzn
zl359tuyf/+7sKSkGiEJIT1jFAAkiShK68SJg7OylgYFGcVAAECrqiKEZJm2tysIgdmsc14EWRY2
FY/q+A0RQG3Re2yIerMsszvv3Pj114WS5N/n2McACufKz38+/uWXZ6SkDHDvs4rH7duLXnjh69LS
GkLMlHIALmgwbVry3r0PGwwd4T3gNDcJkqiUUC8SgjEWPoyuba6+CmFtAMH+/ftra2s7COjVuim0
iEcf/axfsI8x5twRGGjYufPhrVsXJyeHUsrEdlf7oZTLMiUE33//yFOnVj7yyBRK2wgBAKQoVJL8
Dh78YenSHerqV13cOl2HhUr1DmGMdDpSX3/p22/3C1+3FnU3RAC1obNnz+7atau9vd1L007WzwnB
r756YOPGI/0y9xmTo6IsBw8+vnBhiixT4dIRWNN+CEE6HRF7LoOBbNiw4JVX5lNqwxg5aeC/deux
F1/cRwimVJV/AM79ppAK6opvb2/ftWtXSUlJl9iHbsUFiXds2rQpOTl52rRpnoydzoAfJkk4M/Ps
Y4/twNjotIH0ndQFYP7+ur17l40ZEyHLVJKwpy26+q/Q7hWFzZw5uKVFyck5R4gwjQDGhgMHzqam
Ro8YMVBs472YuYKDg69cuVJQUJCWlubi5nQHn1aAuu5OnDhRU1MzZ84c7/cLda2mpuWJJz4DQJx3
14Ryo4AxAnC8+ead48dHORxUhIx7R4Rzb48IwYyx116bm56eRGm7sMFxDgDSU0/9b0VFsyRhL/YS
8Yrbb7+9trY2Ly9Pxd4NEUCFc+fOTZgwYeDAgWL6u9+g2kcB4Omnd1dVNRCi57wvN7rC/mWbNWvo
8uXjKWU6He5SErrQQAjb116bCyAJAwnnjBBdXV3jr36122WY7sAYCwsLGz9+vOBCXbzURy3Iydap
oijafIfr7+kw4UoS3rLl1H/912ZCTJT2tZkBIcS5PTNz6fz5yaIzvicMqWillEsSzsjYsnNnASEm
oRQRgilt+/DD+x9+eKyzZe6GhA7M2O12Qoga7O3pdb6yIPEXY+w1qodzziUJNzXZXnghC0ByKgJ9
BxgD546UlIjbb08AAEKuCUwfQTu0hx4aDYDUKcoYB9D9/vdfX77c5oURiZWk1+tFYD14FcVdEECr
fbq8wH36g9Ph8Ne/ZpeV1fU581HRp8ycOVinI6pVuQftCH1/6tTYoCALY1SIUs45IfrKyvo///mQ
kx6uyHVHTqc49JUA2na1Ar2zUXHOQZJweXnTO+/kAhj7nvmoMG5c9I08rlpABw70T0oKBVCc4xV+
JNM//nHk3LkGwdw6fVz7txc2YoyxrVu3lpaWImecs4fbOACsXftdc7OVEOlGwgh6DJwDAImNDdTi
omcghhMTYwFg2glNCGltbX3jjRzoLNhWizSEUHl5+datW51G307AGwFU/amqqur48eOSJHm9EyQJ
V1Vd/fDDEwCG/jLxc84BkNEoAXRD8HpoCgDAZNJdP5PEIjBs2lRQXt4kFoEXFi9J0vHjxysrK8GD
PurTCvj+++9jYmJiY2O9CHQxFz766ERjYxMh0s1OO/AEIoDH4VBUDN4g2GyK20zihEhW69UPPsgD
z4tACIOYmJiYmBgRkd8pdEEAsXssKioaOnQoeBAj4pokYYeDbtpUAKDrD+eiOmwAoCIKE3ywBHgd
OwKAqqqrAC68XvBh/ebN37e3y5KEPWOGA0BycnJRURFowgOve0uX/bBarYqiCAJ4gI44hm++KS0q
qkVI31/TX2AHAPLza26kCTU5oKGhraTkCgBxGRHngLHu/PlLWVkl0FmwiRaGDx8uy3JTU1Onv3at
hgYEBKxevTo2NhY8y3TRvU8/PQ1ARZbnTcaytw4DSPv3lzHGvMxN39qB3NyLDQ3NGEvubYjYrU8/
PeOpBRVXMTExq1evDgwM7PQ2bwRQce2Siu4OkoStVntW1vn+5T8AwBhHSHfqVPWBAxfAq5biCdSg
MQDYvPl7pwrE3V8EoP/669LGxnZP+qgAQojJZPLkG/BIAHXiMK/bWTWO6tixqsrKKwjp+rv2hBgk
FWqi6Ex3nU6UMknCBQW1//73GQADpZ1MKc4BY6murik3txKgI4PBS8ue3ANdywDkBPDo/AIA2Lev
FEDpNPSlbwExxhEyff756W3bTksSVhSP4RpuA7mWmgAAzz2XJcs2LxGJgtL79p33gjoXBLpDFwRo
bGwsLi7W1gXopAmMACAn56K7sOonEGUbpJUrPz93rkGnI7JMVX+Wx2ec2JdlJkn4j3888OWXZwgx
ednQcM4ByHffXVSR4OEeYIz98MMPjY2N3SCAQHphYeG2bdu8+h0BY9TY2H7mzCUA7+o/BwBJwuKD
8Q1F3HsFYVWWLl+23nXXxoqKZkED1UnrptJ0/KsojFKu15O///3Y73+/F2NTp8zn+gelwsLLly61
CiO2xw4htHXr1sLCQnBj6dhz0wAADQ0N4eHhXpawuF5aeqW+vsVrKnOHl0pRWsSHMYcz1vWm0IAx
hrHh7NlLU6a8n51dIXwyAsXOND+uutFlmQonEsbouee+XrlyB8Z6sey9vINzQAg3NbWWlDQAeHMP
IIQiIyMvXboE18cVgpcMGTHrm5qagoKCwHMqj2iqqOgygEyI5FkjRgA0JMT/oYemMMbNZik7u+Lw
4dKbKbQ7aFBV1Txjxvqnnpry/PO3RUT4u3gyEOpYxAihb74pW7MmKz+/lBATpeCLFw9jRKlcVHR5
ypRY7wMJCQnpdCvQBQFqampGjRrllQAcAM6fvwLAvOTxYIwYYxER/m++OU+WqU5H/vzn7MOHfyDE
IIzGN48GCOk452+/vf/DD/MXLhy+cGHK2LER4eH+BgNhjLe0OMrKmg4evLBly+mjR0sBgBA/Sn2N
GxNDPn/+CnheAeK62WwWDjIXNHZBgGnTpkVFRUFX4ebl5U2+ONc45yIwRKcjvZh54R1FnDPOESF+
Vqt948bcjRuP6HTmsDA/k0lijDc12RsbW0SQIcZGABBJHD5uZYTtr7y8CTy4SVS8DR8+XPASn1iQ
2sqUKVPUnAsPdwIA1Na2+DhfCMGS1FHWrk8IAKJjlFIATIiZc5BlWl3d6JzjCIBIkr8QBt0NHhDR
QLW1LeDZ9C2iZuPi4uLj413Q65EAmjypTqrruOAUABobbW4Wq1sN1KhCBIAQujZwkSmlva27LTc2
2gDAwxS9LoPapRwXdOkPgK58GkL/bWlx9GuAfzeQ5RyaWu/gWnC5Om7fmxMsqLXVIaLYfbv/OvDG
grR830vrjHFZ7gPvu8hX6ZhBIkyhM6q73MY830Mo5ZxTkQ/sXBmYENJVRTJXbMkyY4x7spZ5R6a3
fUBLS8uWLVvq6+vBqzlFNQfdzG2wCM6hYg9BaZsT+7yz2xTnbe2aeobqDYKjUkVp4dxuNOojI4Ni
YkIiIgJNJj3nsqK0cE67lRPp3RAkfrpy5cqWLVuam5tdEOUtU16W5ZMnT6alpYWFhXnxhWGMhOHX
R5NLDwAhxLmSmDhw6dIxisIaG9vffvuou5EAIcS5nJoac999IxWFVVdffe+945p7OIDI226LjBzw
4INjfvrTxKSk0MBAA8ZI5AqUlFzZu/f8Bx/k1dZewdjkm2OVq3GPngiAEGptbT1x4oQIKtQi0xsB
JEkym83ecSra0uvJTfUBYIwoVZKSQl54YRoAlJc3/f3vx9yttOK21NTw55+/DQAKCmrfe++YBoMI
IWDM9sQT6X/961x/f9cAJ4vFEBUVMH16/G9/O3X58s+2by/A2OidBsJwrdcTX5Q6s9ks/Oq+pqmK
ux0Oh1cCdHS9D5wwKsZFioTnLl2z7WgvY4w4t/2f/zNt3bq7jUZJWEnb2uTy8qZz5xpqaqxCkDoc
1GIxbNt23223JTDmS342t1gMahKcJ7DZbACg07nW6/C2AvR6vUhE7Wq0KDTUBNC9ALQegLrKnUmK
ncO11S1h7UXG5Li4ga+8MotzTgi6etX+4ovf7thRePlyG6XcYCCDBwc//fRPHntsvMNB9Xry7LO3
HTpUKp72/C4AYCEhRuiq8Ep7eztCSK/Xd4MAGOPHHntM1PL0nH8KABAdbfEgFW8VEEabO+5I9Pc3
tLXJZrPu/vs/3bPnBMZ+jImodKWwsOrxxz9ubZVXr04DgPHjowIC/K1WG0Letzg8OtqiosIdBOqS
kpIef/xx99CeLvwB4eHhQgx42oWJ9e6s6dLfaO4KxoyJBACzWXfgQNmePWckKciZ44gAMCEGAOMn
n5wUN1ssBn9/PYA3didsQaIOjXcsmUymiIgI9xsk762L8nVqRpj78+JKSkooAOmrKgM9AcY6nPWt
rQ4AyM4uBxD7gA59X5hFAXBbm+K7QUIUAkpJGQDXMwltipxKg04R6G0jxjVlNzyB2AkPHTqAEEM/
BoN2CZxzAN2nn5749NPjAICQjhADAEeoo2QQ54xzBaAlPn6okyRdj4UxBmBwEuAa6kGjC6hGuk43
Yt6iDcUKsFqtfn5+nuISRVNxcUFxcUGlpZcRkm5VixAC4BgbCUGEYIdDobTdyV4wgC4gwBgVFTB9
+k9efHG6ry0i4JzGxAQPHhwMzrmoTSRV+YdLQrX2YhcEqK+vX7du3YoVK8LDwz3xOEqZwSCNHRtR
WlqLsa6v7Mw9Ac5BURRZtpnNAWPHJo0eHT506IDBg4NiYizh4f4DBpj1euKJV7iD2HaMGRMhSj6p
GawIIVGhua2tbefOnQ888IBIquCaepLqsujCHxAYGMg5r62tDQ8PBw9iQEz5GTPit28/0d8Y9oZ8
hDDnsr+/Yc2a2cuXj42OtrjkPAuk1NW1DhhgliRfeCkC4NOnx6tI4M6ikQcPHszOzo6MjLRarcXF
xXFxcRaLRSS3MsbKysqioqLE8RHehDDn3Gg0hoWFlZeXjx492jOlOABMnz4Yof7MCegCVQhxLkdF
WfbsWTpq1EBhvUEItbfLVVXWysqrZWWNZ8827N9fTik7cuQx8MG0RSkD0M+cORg6WLHgchgApkyZ
Eh8fn5WVxRj7/PPPbTabxWKJiopKTEwMDAz8+OOPn3zySXEgiDcCCGIOGjSouLgYPAgl9YyUUaPC
x42LyMu7eMP17W4UtPsvFUSm0IYN944aNdBmU4xG6fDhin/841hOzsXKyquybAdQMAbG6MiR8T7y
H8Yco0ZFjh0bKf510gA45xaLJSgoqLq6OiIiYuTIkefPn7948eKFCxf279/f0NCQkpISGRkJLn6J
zpArVMyU9vZ2tR5Kp3dSyiUJ3XNPSl5eGUJGgJu7DrwkmwLwyEg/l6uEIErtkycPmTcvyeGgRqP0
t79995vf7EKIca5T62ASgh0Ouyj02hWIIgjyXXcNxRiJkihOSndwaUrpnDlzBMYSEhKGDBkixHJj
Y6PZbAY199UL9gVPTEpKSk5O9u6cEZczMob/z/8cuHkZ8S6ntbj/DsABsJiSLmMBoGlpMQCg15Pq
auvLL2cBSJKkUxQm3DLCNwDABUftCkSahnHx4hHunXGWLcCHDh3Ky8tDCA0aNGjq1KkiwCc0NFSV
85zzLjxiWsekp4Q/5KzNOXJk+OzZgwEcvgQoIoQAsBqn5eXj3CJdA6NRMplc3B8dWbQDBwbOnDmk
09GEh/uLb+XlV6xWGWNJRGupN0gSAXAMGxaqGbtHCzyAfcaM+HHjotQCNi5427VrV2ZmZnJycmJi
Yk5OjsPhOHnypOpcUbUgn6xa2mM/PBn9Bd9/9NEJaje8E4BzGaBFUVrVUC1PH84V56JmAKAoLDzc
f9y4CACbXt9R+EGSCCEYoPU3v7ltwACzqCbtAlZrh1k3IiJAr8ecc0lSH0eSRByOlvDw0Fdeud05
duHkwm7hNuI7f/TR8eAWgC12r3V1dceOHVuxYsX8+fMTEhLi4uIGDRqUm5u7bds2uD5+ouvSxej6
2kyeQDDBBQuGjRoVfepUDcZ6T6JYrI/x4wc98sjtAQEGr1l/YDJJu3efLS6uA5AqKpplmYrH//Sn
eXPm1FitzSK0i3PKOaxcOXvNmnS1sI8WKQD4++9rAcDhoEOGhDz2WNq77+5jTM8YEtoj5zBpUuLG
jfeKoiqEYEIwxgqAnXOjtmAlQpgxx9ChkYsWjQC38A6BpbKystDQUBEGcezYsYSEBAC4995733nn
ncrKypiYGLXUQBcEUGNSDh482NzcfPfdd3dapAA5yyHqdHjVqsmPProNIYO7KBaF6MUsnjVryJw5
CV62PMLxK0m4vr61uPiiJPn98EPd4cMVM2YMttuVSZOi8/OfWrs2Ny+vRlFYQkLwL34xZt68RADY
uLHgrruSQ0PN6pZQxPLv23e+pKQhMTFUlunatT/9yU+it207U1fXoteThISQBQtS7rwzyWCQGhvb
jUbJaEQGg/SrX6W/8UZua6ujudnmHAvHGFOqPP30ZOFUEDWxtKgAAD8/v6tXrzocDs55ZWXlrFmz
AMBisRiNRhf/iq95wnq9/rvvvrNarWpghadF8NBDY1JTB1HaiStD6KyEYEKQpyqCngBjBMDWrNnb
0uIwGCRZpoMHB61dOz87+5EjRx7bvHnRHXckAMBf/5rzyiv7goONoIlY5hwwJm1tbatXfymyORnj
Dz00eteuJUeOPJ6dvfzDDxcuXJhiMEj5+TXp6RvKyhoRQna7smpVWlXVMw8/PAbARggSyg+l9pSU
qGXLxrlMf62eMmzYMKPRuHXr1ry8vIEDB0ZHRwPA6dOnKaXiu08uSe1948aNy8rKOnny5G233ebJ
LCoWgV5P/vCHmYsXb3KZzgCorU0+dOiC78YixlhgoLG2tgUAKwrD2HD8+IVZsz745z8XpqaGq3HO
oj/Nze0vv3zgzTe/iY+PPHSowmzWnTp1SdsUxsbMzNNz5360bt09Q4YEO+cQF1HTly+3vv320ddf
P9Ta2rxhw4m//W2uWoxAOFydwQ3AOX3xxZkmk+v0V3l1W1ub2Wx+5JFHNm7cKPhPTk5OTU1Nbm5u
RkaGwWDQchGf4gkFF9q9e/fJkyefe+457dmCbljukEJ33bUxM/MMIWZnpJ/qrunBeQgEAKsBDYzZ
JUmaPj1xxoy4uLggnY5cvtyan1+7e/cP9fUNGJsZY863IAA1XxyphVSMRuOcOUnp6bExMRaEUG2t
9ejR6qysksbGKxibADBjjgULRt5zT4rJJFVVWf/1r/yiolqEJIQQY+1z5qR89dVS7cFsKkIF9r/4
4osFCxbodDpZlk+dOnXq1Kn6+nqz2Zyeni7OI9VObp8IIO6ur6/funXrkiVLhCbrKVZXBBsXFdVP
nPiP1lbFibsOGvTAaaNWkxT/OQ9BsQOoQZxC2OjV8Gz1LW7hPeJxUT6ROTmw+rhOhOUihDi3qSH1
AHonq+BGI8rNXTF6dIRaDVQb+EYIaWxsfOutt1asWBEREUEpdT8IE67Hgk8pSuJLaGjok08+6QX7
HS1ipChs2LCwV16ZA2BzMQyIXU+3Pi7dYYxxDoQYJcmfEDMhJvEFIaI66zXPos4eR86nTNc/TtXH
CTGpjSMkidgTgPY//GHW6NERatF3AfX19QL7lNLg4OCwsDCRGAwaxb2trU1dKNpJ373kKRfC+MaI
ThPi52RE/6HACSGUtt1+e0pW1jXmI5Bgs9lef/31gICABQsWDBo0CCH0zTffHDlyJCUlpbGx0Waz
ORyOpqamMWPGLFy40L3OW/fKVoLGeOuJBiLaUj2BdPLkdRUVTRjr+7tAdM+xL0rQR0YG5OauiI0N
FEPT8pPa2tq9e/eeOXNm6NChCxcuBIC33norPDw8MDDQZDL5+fkZDIbU1NROmUf3YtmcWZy0tbU1
ICDAMw2u1e07ePDCnDkbZFn1Cv1n0aDj9BiEWFbWstmzh7gXylLnYmVl5e7du0tLS8ePH19RUbFg
wYLk5GRtbdtO0dW9mnGilYKCgrffflsEunRKvw5nm4QVhU2bFrdhwyIAu6hZeMvGrXQ6XBHKyLn9
/ffvnT17iKi+6C5UBURHR69YsWLFihX19fXV1dUHDhxoaWkRKoOQLp1O1m4fZ4sQCgkJOXz4cFNT
0/Dhw9UW3TNDOOeEYEWhY8dG+vub9+49TYj+epXmVgYOgCQJUdr6xz/euWpVmkjs6TQHpr29/bPP
PtuxY0dRUdGkSZOmTZsWExNTVFSUlZVlt9tjY2NFPFanWUbdI4DQeXU6XVhY2K5duxISEgRf8xCa
isQ5RpTy9PRYQvTffHNGkv4jaNCBfUVpfeGFef/93zO0ey4XwwNj7P33329sbExPT9fr9YmJiQI/
aWlpFoslPz9/xIgRJpMJPOjg3ZYB4NRwPv7448rKymeffRa8pvAh5ylVkoT/9Kfs5577nBAjY7jv
y8n5PkqEMMac0vaXX57/hz9M91SCXjipjh07lpWVtWbNGrWcoSzLe/bsSU9PDw4OppS6HMbuAt07
yE3b0J133nnlirfsQO39hICi0N/9Lj0kxLRixQ7OMSG6W1I35RgTzmVK6TvvLF65cqIn7KuGkKqq
qoiICL1eL8syxlhUNTlx4oSiKPfee2+X7+v5ESYWi2Xw4MEuEqlTd42TBliW6eOPj//yy0eCg42U
tkuScKrcImJZJPITxtoDAgyff7505cqJskxdsK8OkznPlIuKiqqoqGhtbRWRz4qi6HS66dOni6TU
Ls9w7DYBtL1Rjy1xiezw9IgkYVmmc+cmHD/+1MSJgxWlhRDo6flcvYx9jDEhoCgtY8bEHj/+5F13
JQudx9MACSFiso8dO9ZsNn/44YeiUqu48/Lly2qCu/cXd1sLguvLMoovly5dUhTFZDJ5OstE02+s
KCwkxLRs2Vi7nWRnn+dcIUTv9Oj2PUfqyBdjzME5Xb165iefLB440F/oPNrxav2INpvt8OHDR48e
tVqt0dHRI0eOzM7OPnjwoF6vlyQpNzf38OHD9913X1BQkJcM347GbySpSDWUbtiwwWq1Pv300ypt
vItlcWCLOI9lxYrdp0+XI2TEWHKu674hA3dGSimc21JSYtetu+v6s9w6hgiaEAWEUGNj4/r16yml
AwcOLCsrE5bnkJCQL7/8sqCgQJZlPz+/u+++e8SIEVor6U0hgIrQq1evvvHGG3FxcUuXLgXPSpH2
EVU1stuVd9459uqr+5uaGvuKDNeh3mIJfP756atWpQkPl/ASg5PBqtNfDeh8//33CSHLly8HgLa2
to8//ri0tHTVqlXh4eF2u729vT0gIEA1gnYZ5dgTFnQdARFijBmNxmHDhu3Zs+fixYujR4/2/mIt
OxJG3alTY5ctGwugP3WqzmazAiCMJe8FYHqGdwDkFKoK5+1+fuaVK9O3bFk8b16SKJWrMn2xshlj
Fy9erK2t9fPz0+v1CKGmpqY9e/YsWrQoKCiIUmowGMaNG1dcXHzmzJlJkyYRQoxGI3Kecuc9lkfA
jZ4nrHY0PDx8+fLl3377rcPhMBgM4HUdqNNKnISgKCwszO8vf7n9179Oe++9vPXr86qr6wEAQC8E
XbdOse3sdcI9KU4HdQBARMSARx8dt2LFhOhoC2PcRdcUgyopKdm5c6fVahWCbfHixampqeJXNW1L
WPx/+tOfrl+/vq6uLjw8XCj+XmoL9DIBtNSOj49ftmyZOgzBSbyXOVBrjgosRET4v/TSjDVrpmRm
nvvoo5P795e1tVkBAEAHIKk4UvPcPaFbcA6V0XGuUKoAcJMpYNq05IcfHn333UNFlqTgOcLCIxoU
6M7Pz//kk09mzJiRnp5OCMnMzBTFZgIDA+Pi4r766qvhw4cTQhRFAYCgoCBCiN1uB429wUffU68d
6KyuXK28cr/i4XEQfFk9XlkMoLraundvyZ49JTk5FysrmwDEKWDCQyk+1zXpNHIw50ds9PRRUUFT
pgyaNy9x7tzEmJiOoGj1CGn3GOnGxsa//OUv99xzT1pamjYmU8yn+vr6N998MyEh4cEHH9TpdAih
L7/88uTJk7/97W99n/i9TACVDNfaRSgvLy8iIiI6OrrL7bg7ISnlCF07q6u9Xf7hh4a8vOrvv68r
LKyvrLx66VKr1eqQZVlzJh4CwDqd5O+vHzjQLybGMmxYWGpq+PjxUcOGDTCZdFoFzNP5aoKlZGdn
Hzhw4He/+506lxFCLS0ttbW1JpMpOjq6srLygw8+UBRlxIgRjY2NFy9efOSRR4YMGeLLIeIu0Jtn
yrsYab///vtt27YtW7YsJSVFXQq+tAAA6lmaooSM0SiNGRMxenQ4dIh93txsa262NzfbbDZFVKrQ
6bDRKAUGGi0WQ1CQ0WVqi7P7xKmFWut8px0wGAytra1NTU2hoaGKopSXlx85cqS4uNhms1FKp0yZ
snjx4meeeSY3N/f8+fMhISH33nvvwIEDuQ8ZXZ0MuRdXgArq8L744ouvvvrqjjvumD17ttejNzy1
I8JAROHBDtYv+IYXh6jTRX7tLFRN8lAXJdWdC679jTfeYIwlJiaWl5c3NDRERUVNmDBhyJAhZWVl
27dv/8UvfjF27NgunS39QwAt98cYnzlzZvPmzUuWLBk1apSWn/asu2pvPVVkVaN3tP92t32EUHV1
dWZmZnNzc0JCwsSJE0U0lfhp3bp1gYGBS5YsURRF3eX2gPvfLAK406ClpcVgMOh0Og361KolXWvK
fQlaa4/LF+HVkiTp7bffjo6OzsjIELLtBvvfwyPNvYM6u4Uyqk2yFIYUdffgyX7Xl6BqONq9K3cm
1MmyzJ1nF0qSdOjQocrKysmTJ4NTON/g7OlNIawFtVtaHU5c+eijjzDGGRkZAwYM8FE43yTQmnVB
M+XVBVpXV/fBBx/Mnj07NTX16tWr+/bty8vLe+CBByIjIz2dpNZtRPXZ7FOXc2lp6RdffFFRUTF2
7NhZs2aJBNjr+tQj8dDdzqjTXFWRtdtGZ2CHsmvXrtzcXJPJpChKWFhYRkZGbGyslwOsuwt9vfxV
Mpw9e3bHjh1JSUmLFi1y2eyoJtxep4SLyFH/LS8vz8zMHD16dHp6urtuc+nSpbq6uuDg4KioKME5
u9xa3ooEUMejVmJUFEVRFJEuK8Zjs9lUY1ZH/9yQ1bP3goa0Ku7sdntOTk5+fn59fX1CQsIdd9wR
FxenfbX7svDdyuYj3CwZ4A7qNk0MQARTqmfNAYDNZlu7dq3FYpkwYUJSUpI4ckKrh2hnnIvBw9O7
tPeD2ykuIm8rMTHxoYceEjsp7SMuEkIVxb27KPtHA3HX9gTDPXv27MmTJ8+fP2+1WtPS0jIyMnqw
uXdRIgU0NzdXVlYWFhaOHz8+ISFBZXoqu+uyQupNgr5bAVpwd2oCgCRJw4YNGz58uKIo586dcxED
R44cqampGTRoUGBgoMViCQ4OFhsLLaIZY4qiUEpFjSN1J7hjxw5ZlgkhgYGBqampLj1RVaA+EP6d
oKJ/dXABWg4LTkah5d0iSe3YsWMOh8Nms8myvHLlyujoaDGR29vb169f39LSIqwI4eHhK1euBKdh
ubq6uqioaMiQIZGRkULegJvZqh93grcEAQRop7N2q6xlVoyx1tZWq9U6YMAAbSDU8ePHEULiANOg
oKDY2FithHCRFv0y0z3BLUQAT6C6d7TaIfiAR5c9bZcBA/0C/wEEEKDtZ6duHy1a3Wtk37LwH0OA
/1fhphjjfgTf4f8C4VLHz/5KLxoAAAA8dEVYdGNvbW1lbnQAIEltYWdlIGdlbmVyYXRlZCBieSBH
TlUgR2hvc3RzY3JpcHQgKGRldmljZT1wbm1yYXcpCvqLFvMAAAAASUVORK5CYII=

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,695 @@
\documentclass[10pt]{article}
\usepackage{fancyvrb}
\usepackage{url}
\DefineVerbatimEnvironment{lua}{Verbatim}{fontsize=\small,commandchars=\@\#\%}
\DefineVerbatimEnvironment{C}{Verbatim}{fontsize=\small,commandchars=\@\#\%}
\DefineVerbatimEnvironment{mime}{Verbatim}{fontsize=\small,commandchars=\$\#\%}
\newcommand{\stick}[1]{\vbox{\setlength{\parskip}{0pt}#1}}
\newcommand{\bl}{\ensuremath{\mathtt{\backslash}}}
\newcommand{\CR}{\texttt{CR}}
\newcommand{\LF}{\texttt{LF}}
\newcommand{\CRLF}{\texttt{CR~LF}}
\newcommand{\nil}{\texttt{nil}}
\title{Filters, sources, sinks, and pumps\\
{\large or Functional programming for the rest of us}}
\author{Diego Nehab}
\begin{document}
\maketitle
\begin{abstract}
Certain data processing operations can be implemented in the
form of filters. A filter is a function that can process
data received in consecutive invocations, returning partial
results each time it is called. Examples of operations that
can be implemented as filters include the end-of-line
normalization for text, Base64 and Quoted-Printable transfer
content encodings, the breaking of text into lines, SMTP
dot-stuffing, and there are many others. Filters become
even more powerful when we allow them to be chained together
to create composite filters. In this context, filters can be
seen as the internal links in a chain of data transformations.
Sources and sinks are the corresponding end points in these
chains. A source is a function that produces data, chunk by
chunk, and a sink is a function that takes data, chunk by
chunk. Finally, pumps are procedures that actively drive
data from a source to a sink, and indirectly through all
intervening filters. In this article, we describe the design of an
elegant interface for filters, sources, sinks, chains, and
pumps, and we illustrate each step with concrete examples.
\end{abstract}
\section{Introduction}
Within the realm of networking applications, we are often
required to apply transformations to streams of data. Examples
include the end-of-line normalization for text, Base64 and
Quoted-Printable transfer content encodings, breaking text
into lines with a maximum number of columns, SMTP
dot-stuffing, \texttt{gzip} compression, HTTP chunked
transfer coding, and the list goes on.
Many complex tasks require a combination of two or more such
transformations, and therefore a general mechanism for
promoting reuse is desirable. In the process of designing
\texttt{LuaSocket~2.0}, we repeatedly faced this problem.
The solution we reached proved to be very general and
convenient. It is based on the concepts of filters, sources,
sinks, and pumps, which we introduce below.
\emph{Filters} are functions that can be repeatedly invoked
with chunks of input, successively returning processed
chunks of output. Naturally, the result of
concatenating all the output chunks must be the same as the
result of applying the filter to the concatenation of all
input chunks. In fancier language, filters \emph{commute}
with the concatenation operator. More importantly, filters
must handle input data correctly no matter how the stream
has been split into chunks.
A \emph{chain} is a function that transparently combines the
effect of one or more filters. The interface of a chain is
indistinguishable from the interface of its component
filters. This allows a chained filter to be used wherever
an atomic filter is accepted. In particular, chains can be
themselves chained to create arbitrarily complex operations.
Filters can be seen as internal nodes in a network through
which data will flow, potentially being transformed many
times along the way. Chains connect these nodes together.
The initial and final nodes of the network are
\emph{sources} and \emph{sinks}, respectively. Less
abstractly, a source is a function that produces new chunks
of data every time it is invoked. Conversely, sinks are
functions that give a final destination to the chunks of
data they receive in sucessive calls. Naturally, sources
and sinks can also be chained with filters to produce
filtered sources and sinks.
Finally, filters, chains, sources, and sinks are all passive
entities: they must be repeatedly invoked in order for
anything to happen. \emph{Pumps} provide the driving force
that pushes data through the network, from a source to a
sink, and indirectly through all intervening filters.
In the following sections, we start with a simplified
interface, which we later refine. The evolution we present
is not contrived: it recreates the steps we ourselves
followed as we consolidated our understanding of these
concepts within our application domain.
\subsection{A simple example}
The end-of-line normalization of text is a good
example to motivate our initial filter interface.
Assume we are given text in an unknown end-of-line
convention (including possibly mixed conventions) out of the
commonly found Unix (\LF), Mac OS (\CR), and
DOS (\CRLF) conventions. We would like to be able to
use the folowing code to normalize the end-of-line markers:
\begin{quote}
\begin{lua}
@stick#
local CRLF = "\013\010"
local input = source.chain(source.file(io.stdin), normalize(CRLF))
local output = sink.file(io.stdout)
pump.all(input, output)
%
\end{lua}
\end{quote}
This program should read data from the standard input stream
and normalize the end-of-line markers to the canonic
\CRLF\ marker, as defined by the MIME standard.
Finally, the normalized text should be sent to the standard output
stream. We use a \emph{file source} that produces data from
standard input, and chain it with a filter that normalizes
the data. The pump then repeatedly obtains data from the
source, and passes it to the \emph{file sink}, which sends
it to the standard output.
In the code above, the \texttt{normalize} \emph{factory} is a
function that creates our normalization filter, which
replaces any end-of-line marker with the canonic marker.
The initial filter interface is
trivial: a filter function receives a chunk of input data,
and returns a chunk of processed data. When there are no
more input data left, the caller notifies the filter by invoking
it with a \nil\ chunk. The filter responds by returning
the final chunk of processed data (which could of course be
the empty string).
Although the interface is extremely simple, the
implementation is not so obvious. A normalization filter
respecting this interface needs to keep some kind of context
between calls. This is because a chunk boundary may lie between
the \CR\ and \LF\ characters marking the end of a single line. This
need for contextual storage motivates the use of
factories: each time the factory is invoked, it returns a
filter with its own context so that we can have several
independent filters being used at the same time. For
efficiency reasons, we must avoid the obvious solution of
concatenating all the input into the context before
producing any output chunks.
To that end, we break the implementation into two parts:
a low-level filter, and a factory of high-level filters. The
low-level filter is implemented in C and does not maintain
any context between function calls. The high-level filter
factory, implemented in Lua, creates and returns a
high-level filter that maintains whatever context the low-level
filter needs, but isolates the user from its internal
details. That way, we take advantage of C's efficiency to
perform the hard work, and take advantage of Lua's
simplicity for the bookkeeping.
\subsection{The Lua part of the filter}
Below is the complete implementation of the factory of high-level
end-of-line normalization filters:
\begin{quote}
\begin{lua}
@stick#
function filter.cycle(lowlevel, context, extra)
return function(chunk)
local ret
ret, context = lowlevel(context, chunk, extra)
return ret
end
end
%
@stick#
function normalize(marker)
return filter.cycle(eol, 0, marker)
end
%
\end{lua}
\end{quote}
The \texttt{normalize} factory simply calls a more generic
factory, the \texttt{cycle}~factory, passing the low-level
filter~\texttt{eol}. The \texttt{cycle}~factory receives a
low-level filter, an initial context, and an extra
parameter, and returns a new high-level filter. Each time
the high-level filer is passed a new chunk, it invokes the
low-level filter with the previous context, the new chunk,
and the extra argument. It is the low-level filter that
does all the work, producing the chunk of processed data and
a new context. The high-level filter then replaces its
internal context, and returns the processed chunk of data to
the user. Notice that we take advantage of Lua's lexical
scoping to store the context in a closure between function
calls.
\subsection{The C part of the filter}
As for the low-level filter, we must first accept
that there is no perfect solution to the end-of-line marker
normalization problem. The difficulty comes from an
inherent ambiguity in the definition of empty lines within
mixed input. However, the following solution works well for
any consistent input, as well as for non-empty lines in
mixed input. It also does a reasonable job with empty lines
and serves as a good example of how to implement a low-level
filter.
The idea is to consider both \CR\ and~\LF\ as end-of-line
\emph{candidates}. We issue a single break if any candidate
is seen alone, or if it is followed by a different
candidate. In other words, \CR~\CR~and \LF~\LF\ each issue
two end-of-line markers, whereas \CR~\LF~and \LF~\CR\ issue
only one marker each. It is easy to see that this method
correctly handles the most common end-of-line conventions.
With this in mind, we divide the low-level filter into two
simple functions. The inner function~\texttt{pushchar} performs the
normalization itself. It takes each input character in turn,
deciding what to output and how to modify the context. The
context tells if the last processed character was an
end-of-line candidate, and if so, which candidate it was.
For efficiency, we use Lua's auxiliary library's buffer
interface:
\begin{quote}
\begin{C}
@stick#
@#define candidate(c) (c == CR || c == LF)
static int pushchar(int c, int last, const char *marker,
luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last)
luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_pushchar(buffer, c);
return 0;
}
}
%
\end{C}
\end{quote}
The outer function~\texttt{eol} simply interfaces with Lua.
It receives the context and input chunk (as well as an
optional custom end-of-line marker), and returns the
transformed output chunk and the new context.
Notice that if the input chunk is \nil, the operation
is considered to be finished. In that case, the loop will
not execute a single time and the context is reset to the
initial state. This allows the filter to be reused many
times:
\begin{quote}
\begin{C}
@stick#
static int eol(lua_State *L) {
int context = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
while (input < last)
context = pushchar(*input++, context, marker, &buffer);
luaL_pushresult(&buffer);
lua_pushnumber(L, context);
return 2;
}
%
\end{C}
\end{quote}
When designing filters, the challenging part is usually
deciding what to store in the context. For line breaking, for
instance, it could be the number of bytes that still fit in the
current line. For Base64 encoding, it could be a string
with the bytes that remain after the division of the input
into 3-byte atoms. The MIME module in the \texttt{LuaSocket}
distribution has many other examples.
\section{Filter chains}
Chains greatly increase the power of filters. For example,
according to the standard for Quoted-Printable encoding,
text should be normalized to a canonic end-of-line marker
prior to encoding. After encoding, the resulting text must
be broken into lines of no more than 76 characters, with the
use of soft line breaks (a line terminated by the \texttt{=}
sign). To help specifying complex transformations like
this, we define a chain factory that creates a composite
filter from one or more filters. A chained filter passes
data through all its components, and can be used wherever a
primitive filter is accepted.
The chaining factory is very simple. The auxiliary
function~\texttt{chainpair} chains two filters together,
taking special care if the chunk is the last. This is
because the final \nil\ chunk notification has to be
pushed through both filters in turn:
\begin{quote}
\begin{lua}
@stick#
local function chainpair(f1, f2)
return function(chunk)
local ret = f2(f1(chunk))
if chunk then return ret
else return ret .. f2() end
end
end
%
@stick#
function filter.chain(...)
local f = select(1, ...)
for i = 2, select('@#', ...) do
f = chainpair(f, select(i, ...))
end
return f
end
%
\end{lua}
\end{quote}
Thanks to the chain factory, we can
define the Quoted-Printable conversion as such:
\begin{quote}
\begin{lua}
@stick#
local qp = filter.chain(normalize(CRLF), encode("quoted-printable"),
wrap("quoted-printable"))
local input = source.chain(source.file(io.stdin), qp)
local output = sink.file(io.stdout)
pump.all(input, output)
%
\end{lua}
\end{quote}
\section{Sources, sinks, and pumps}
The filters we introduced so far act as the internal nodes
in a network of transformations. Information flows from node
to node (or rather from one filter to the next) and is
transformed along the way. Chaining filters together is our
way to connect nodes in this network. As the starting point
for the network, we need a source node that produces the
data. In the end of the network, we need a sink node that
gives a final destination to the data.
\subsection{Sources}
A source returns the next chunk of data each time it is
invoked. When there is no more data, it simply returns~\nil.
In the event of an error, the source can inform the
caller by returning \nil\ followed by the error message.
Below are two simple source factories. The \texttt{empty} source
returns no data, possibly returning an associated error
message. The \texttt{file} source yields the contents of a file
in a chunk by chunk fashion:
\begin{quote}
\begin{lua}
@stick#
function source.empty(err)
return function()
return nil, err
end
end
%
@stick#
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(2048)
if not chunk then handle:close() end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
%
\end{lua}
\end{quote}
\subsection{Filtered sources}
A filtered source passes its data through the
associated filter before returning it to the caller.
Filtered sources are useful when working with
functions that get their input data from a source (such as
the pumps in our examples). By chaining a source with one or
more filters, such functions can be transparently provided
with filtered data, with no need to change their interfaces.
Here is a factory that does the job:
\begin{quote}
\begin{lua}
@stick#
function source.chain(src, f)
return function()
if not src then
return nil
end
local chunk, err = src()
if not chunk then
src = nil
return f(nil)
else
return f(chunk)
end
end
end
%
\end{lua}
\end{quote}
\subsection{Sinks}
Just as we defined an interface for a source of data, we can
also define an interface for a data destination. We call
any function respecting this interface a sink. In our first
example, we used a file sink connected to the standard
output.
Sinks receive consecutive chunks of data, until the end of
data is signaled by a \nil\ input chunk. A sink can be
notified of an error with an optional extra argument that
contains the error message, following a \nil\ chunk.
If a sink detects an error itself, and
wishes not to be called again, it can return \nil,
followed by an error message. A return value that
is not \nil\ means the sink will accept more data.
Below are two useful sink factories.
The table factory creates a sink that stores
individual chunks into an array. The data can later be
efficiently concatenated into a single string with Lua's
\texttt{table.concat} library function. The \texttt{null} sink
simply discards the chunks it receives:
\begin{quote}
\begin{lua}
@stick#
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
%
@stick#
local function null()
return 1
end
function sink.null()
return null
end
%
\end{lua}
\end{quote}
Naturally, filtered sinks are just as useful as filtered
sources. A filtered sink passes each chunk it receives
through the associated filter before handing it down to the
original sink. In the following example, we use a source
that reads from the standard input. The input chunks are
sent to a table sink, which has been coupled with a
normalization filter. The filtered chunks are then
concatenated from the output array, and finally sent to
standard out:
\begin{quote}
\begin{lua}
@stick#
local input = source.file(io.stdin)
local output, t = sink.table()
output = sink.chain(normalize(CRLF), output)
pump.all(input, output)
io.write(table.concat(t))
%
\end{lua}
\end{quote}
\subsection{Pumps}
Although not on purpose, our interface for sources is
compatible with Lua iterators. That is, a source can be
neatly used in conjunction with \texttt{for} loops. Using
our file source as an iterator, we can write the following
code:
\begin{quote}
\begin{lua}
@stick#
for chunk in source.file(io.stdin) do
io.write(chunk)
end
%
\end{lua}
\end{quote}
Loops like this will always be present because everything
we designed so far is passive. Sources, sinks, filters: none
of them can do anything on their own. The operation of
pumping all data a source can provide into a sink is so
common that it deserves its own function:
\begin{quote}
\begin{lua}
@stick#
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
if chunk and ret then return 1
else return nil, src_err or snk_err end
end
%
@stick#
function pump.all(src, snk, step)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then
if err then return nil, err
else return 1 end
end
end
end
%
\end{lua}
\end{quote}
The \texttt{pump.step} function moves one chunk of data from
the source to the sink. The \texttt{pump.all} function takes
an optional \texttt{step} function and uses it to pump all the
data from the source to the sink.
Here is an example that uses the Base64 and the
line wrapping filters from the \texttt{LuaSocket}
distribution. The program reads a binary file from
disk and stores it in another file, after encoding it to the
Base64 transfer content encoding:
\begin{quote}
\begin{lua}
@stick#
local input = source.chain(
source.file(io.open("input.bin", "rb")),
encode("base64"))
local output = sink.chain(
wrap(76),
sink.file(io.open("output.b64", "w")))
pump.all(input, output)
%
\end{lua}
\end{quote}
The way we split the filters here is not intuitive, on
purpose. Alternatively, we could have chained the Base64
encode filter and the line-wrap filter together, and then
chain the resulting filter with either the file source or
the file sink. It doesn't really matter.
\section{Exploding filters}
Our current filter interface has one serious shortcoming.
Consider for example a \texttt{gzip} decompression filter.
During decompression, a small input chunk can be exploded
into a huge amount of data. To address this problem, we
decided to change the filter interface and allow exploding
filters to return large quantities of output data in a chunk
by chunk manner.
More specifically, after passing each chunk of input to
a filter, and collecting the first chunk of output, the
user must now loop to receive other chunks from the filter until no
filtered data is left. Within these secondary calls, the
caller passes an empty string to the filter. The filter
responds with an empty string when it is ready for the next
input chunk. In the end, after the user passes a
\nil\ chunk notifying the filter that there is no
more input data, the filter might still have to produce too
much output data to return in a single chunk. The user has
to loop again, now passing \nil\ to the filter each time,
until the filter itself returns \nil\ to notify the
user it is finally done.
Fortunately, it is very easy to modify a filter to respect
the new interface. In fact, the end-of-line translation
filter we presented earlier already conforms to it. The
complexity is encapsulated within the chaining functions,
which must now include a loop. Since these functions only
have to be written once, the user is rarely affected.
Interestingly, the modifications do not have a measurable
negative impact in the performance of filters that do
not need the added flexibility. On the other hand, for a
small price in complexity, the changes make exploding
filters practical.
\section{A complex example}
The LTN12 module in the \texttt{LuaSocket} distribution
implements all the ideas we have described. The MIME
and SMTP modules are tightly integrated with LTN12,
and can be used to showcase the expressive power of filters,
sources, sinks, and pumps. Below is an example
of how a user would proceed to define and send a
multipart message, with attachments, using \texttt{LuaSocket}:
\begin{quote}
\begin{mime}
local smtp = require"socket.smtp"
local mime = require"mime"
local ltn12 = require"ltn12"
local message = smtp.message{
headers = {
from = "Sicrano <sicrano@example.com>",
to = "Fulano <fulano@example.com>",
subject = "A message with an attachment"},
body = {
preamble = "Hope you can see the attachment" .. CRLF,
[1] = {
body = "Here is our logo" .. CRLF},
[2] = {
headers = {
["content-type"] = 'image/png; name="luasocket.png"',
["content-disposition"] =
'attachment; filename="luasocket.png"',
["content-description"] = 'LuaSocket logo',
["content-transfer-encoding"] = "BASE64"},
body = ltn12.source.chain(
ltn12.source.file(io.open("luasocket.png", "rb")),
ltn12.filter.chain(
mime.encode("base64"),
mime.wrap()))}}}
assert(smtp.send{
rcpt = "<fulano@example.com>",
from = "<sicrano@example.com>",
source = message})
\end{mime}
\end{quote}
The \texttt{smtp.message} function receives a table
describing the message, and returns a source. The
\texttt{smtp.send} function takes this source, chains it with the
SMTP dot-stuffing filter, connects a socket sink
with the server, and simply pumps the data. The message is never
assembled in memory. Everything is produced on demand,
transformed in small pieces, and sent to the server in chunks,
including the file attachment which is loaded from disk and
encoded on the fly. It just works.
\section{Conclusions}
In this article, we introduced the concepts of filters,
sources, sinks, and pumps to the Lua language. These are
useful tools for stream processing in general. Sources provide
a simple abstraction for data acquisition. Sinks provide an
abstraction for final data destinations. Filters define an
interface for data transformations. The chaining of
filters, sources and sinks provides an elegant way to create
arbitrarily complex data transformations from simpler
components. Pumps simply push the data through.
\section{Acknowledgements}
The concepts described in this text are the result of long
discussions with David Burgess. A version of this text has
been released on-line as the Lua Technical Note 012, hence
the name of the corresponding LuaSocket module, LTN12. Wim
Couwenberg contributed to the implementation of the module,
and Adrian Sietsma was the first to notice the
correspondence between sources and Lua iterators.
\end{document}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,113 @@
#!/bin/sh -
do_opt=1
best=0
rot=0
a4=0
eps=0
usage="Usage: $0 [-no_opt] [-best] [-rot] [-a4] [-eps] in.ps [out.pdf]"
case "x$1" in
"x-no_opt") do_opt=0 ; shift ;;
esac
case "x$1" in
"x-best") best=1 ; shift ;;
esac
case "x$1" in
"x-rot") rot=1 ; shift ;;
esac
case "x$1" in
"x-a4") a4=1 ; shift ;;
esac
case "x$1" in
"x-eps") eps=1 ; shift ;;
esac
case $# in
2) ifilename=$1 ; ofilename=$2 ;;
1) ifilename=$1
if `echo $1 | grep -i '\.e*ps$' > /dev/null`
then
ofilename=`echo $1 | sed 's/\..*$/.pdf/'`
else
echo "$usage" 1>&2
exit 1
fi ;;
*) echo "$usage" 1>&2 ; exit 1 ;;
esac
if [ $best == 1 ]
then
options="-dPDFSETTINGS=/prepress \
-r1200 \
-dMonoImageResolution=1200 \
-dGrayImageResolution=1200 \
-dColorImageResolution=1200 \
-dDownsampleMonoImages=false \
-dDownsampleGrayImages=false \
-dDownsampleColorImages=false \
-dAutoFilterMonoImages=false \
-dAutoFilterGrayImages=false \
-dAutoFilterColorImages=false \
-dMonoImageFilter=/FlateEncode \
-dGrayImageFilter=/FlateEncode \
-dColorImageFilter=/FlateEncode"
else
options="-dPDFSETTINGS=/prepress \
-r600 \
-dDownsampleMonoImages=true \
-dDownsampleGrayImages=true \
-dDownsampleColorImages=true \
-dMonoImageDownsampleThreshold=2.0 \
-dGrayImageDownsampleThreshold=1.5 \
-dColorImageDownsampleThreshold=1.5 \
-dMonoImageResolution=600 \
-dGrayImageResolution=600 \
-dColorImageResolution=600 \
-dAutoFilterMonoImages=false \
-dMonoImageFilter=/FlateEncode \
-dAutoFilterGrayImages=true \
-dAutoFilterColorImages=true"
fi
if [ $rot == 1 ]
then
options="$options -dAutoRotatePages=/PageByPage"
fi
if [ $eps == 1 ]
then
options="$options -dEPSCrop"
fi
set -x
if [ $a4 == 1 ]
then
# Resize from A4 to letter size
psresize -Pa4 -pletter "$ifilename" myps2pdf.temp.ps
ifilename=myps2pdf.temp.ps
fi
gs -q -dSAFER -dNOPAUSE -dBATCH \
-sDEVICE=pdfwrite -sPAPERSIZE=letter -sOutputFile=myps2pdf.temp.pdf \
-dCompatibilityLevel=1.3 \
$options \
-dMaxSubsetPct=100 \
-dSubsetFonts=true \
-dEmbedAllFonts=true \
-dColorConversionStrategy=/LeaveColorUnchanged \
-dDoThumbnails=true \
-dPreserveEPSInfo=true \
-c .setpdfwrite -f "$ifilename"
if [ $do_opt == 1 ]
then
pdfopt myps2pdf.temp.pdf $ofilename
else
mv myps2pdf.temp.pdf $ofilename
fi
rm -f myps2pdf.temp.pdf myps2pdf.temp.ps

View file

@ -0,0 +1,25 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.chain
dofile("ex6.lua")
-- source.file
dofile("ex5.lua")
-- normalize
require"gem"
eol = gem.eol
dofile("ex2.lua")
-- sink.file
require"ltn12"
sink.file = ltn12.sink.file
-- pump.all
dofile("ex10.lua")
-- run test
dofile("ex1.lua")

View file

@ -0,0 +1,5 @@
this is a test file
it should have been saved as lf eol
but t1.lua will convert it to crlf eol
otherwise it is broken!

View file

@ -0,0 +1,36 @@
source = {}
sink = {}
pump = {}
filter = {}
-- filter.chain
dofile("ex3.lua")
-- normalize
require"gem"
eol = gem.eol
dofile("ex2.lua")
-- encode
require"mime"
encode = mime.encode
-- wrap
wrap = mime.wrap
-- source.chain
dofile("ex6.lua")
-- source.file
dofile("ex5.lua")
-- sink.file
require"ltn12"
sink.file = ltn12.sink.file
-- pump.all
dofile("ex10.lua")
-- run test
CRLF = "\013\010"
dofile("ex4.lua")

View file

@ -0,0 +1,4 @@
esse é um texto com acentos
quoted-printable tem que quebrar linhas longas, com mais que 76 linhas de texto
fora que as quebras de linhas têm que ser normalizadas
vamos ver o que dá isso aqui

View file

@ -0,0 +1,5 @@
esse =E9 um texto com acentos
quoted-printable tem que quebrar linhas longas, com mais que 76 linhas de t=
exto
fora que as quebras de linhas t=EAm que ser normalizadas
vamos ver o que d=E1 isso aqui

View file

@ -0,0 +1,25 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.file
dofile("ex5.lua")
-- sink.table
dofile("ex7.lua")
-- sink.chain
require"ltn12"
sink.chain = ltn12.sink.chain
-- normalize
require"gem"
eol = gem.eol
dofile("ex2.lua")
-- pump.all
dofile("ex10.lua")
-- run test
dofile("ex8.lua")

View file

@ -0,0 +1,10 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.file
dofile("ex5.lua")
-- run test
dofile("ex9.lua")

View file

@ -0,0 +1,30 @@
source = {}
sink = {}
pump = {}
filter = {}
-- source.chain
dofile("ex6.lua")
-- source.file
dofile("ex5.lua")
-- encode
require"mime"
encode = mime.encode
-- sink.chain
require"ltn12"
sink.chain = ltn12.sink.chain
-- wrap
wrap = mime.wrap
-- sink.file
sink.file = ltn12.sink.file
-- pump.all
dofile("ex10.lua")
-- run test
dofile("ex11.lua")

View file

@ -0,0 +1,46 @@
function readfile(n)
local f = io.open(n, "rb")
local s = f:read("*a")
f:close()
return s
end
lf = readfile("t1lf.txt")
os.remove("t1crlf.txt")
os.execute("lua t1.lua < t1lf.txt > t1crlf.txt")
crlf = readfile("t1crlf.txt")
assert(crlf == string.gsub(lf, "\010", "\013\010"), "broken")
gt = readfile("t2gt.qp")
os.remove("t2.qp")
os.execute("lua t2.lua < t2.txt > t2.qp")
t2 = readfile("t2.qp")
assert(gt == t2, "broken")
os.remove("t1crlf.txt")
os.execute("lua t3.lua < t1lf.txt > t1crlf.txt")
crlf = readfile("t1crlf.txt")
assert(crlf == string.gsub(lf, "\010", "\013\010"), "broken")
t = readfile("test.lua")
os.execute("lua t4.lua < test.lua > t")
t2 = readfile("t")
assert(t == t2, "broken")
os.remove("output.b64")
gt = readfile("gt.b64")
os.execute("lua t5.lua")
t5 = readfile("output.b64")
assert(gt == t5, "failed")
print("1 2 5 6 10 passed")
print("2 3 4 5 6 10 passed")
print("2 5 6 7 8 10 passed")
print("5 9 passed")
print("5 6 10 11 passed")
os.remove("t")
os.remove("t2.qp")
os.remove("t1crlf.txt")
os.remove("t11.b64")
os.remove("output.b64")

View file

@ -0,0 +1 @@
make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/ubuntu/include LUAPREFIX_linux=/home/diego/build/ubuntu

View file

@ -0,0 +1,210 @@
%!PS-Adobe-2.0 EPSF-2.0
%%Title: Lua logo
%%Creator: lua@tecgraf.puc-rio.br
%%CreationDate: Wed Nov 29 19:04:04 EDT 2000
%%BoundingBox: -45 0 1035 1080
%%Pages: 1
%%EndComments
%%EndProlog
%------------------------------------------------------------------------------
%
% Copyright (C) 1998-2000. All rights reserved.
% Graphic design by Alexandre Nakonechny (nako@openlink.com.br).
% PostScript programming by the Lua team (lua@tecgraf.puc-rio.br).
%
% Permission is hereby granted, without written agreement and without license
% or royalty fees, to use, copy, and distribute this logo for any purpose,
% including commercial applications, subject to the following conditions:
%
% * The origin of this logo must not be misrepresented; you must not
% claim that you drew the original logo. We recommend that you give credit
% to the graphics designer in all printed matter that includes the logo.
%
% * The only modification you can make is to adapt the orbiting text to
% your product name.
%
% * The logo can be used in any scale as long as the relative proportions
% of its elements are maintained.
%
%------------------------------------------------------------------------------
/LABEL (tekcoS) def
%-- DO NOT CHANGE ANYTHING BELOW THIS LINE ------------------------------------
/PLANETCOLOR {0 0 0.5 setrgbcolor} bind def
/HOLECOLOR {1.0 setgray} bind def
/ORBITCOLOR {0.5 setgray} bind def
/LOGOFONT {/Helvetica 0.90} def
/LABELFONT {/Helvetica 0.36} def
%------------------------------------------------------------------------------
/MOONCOLOR {PLANETCOLOR} bind def
/LOGOCOLOR {HOLECOLOR} bind def
/LABELCOLOR {ORBITCOLOR} bind def
/LABELANGLE 325 def
/LOGO (Lua) def
/DASHANGLE 10 def
/HALFDASHANGLE DASHANGLE 2 div def
% moon radius. planet radius is 1.
/r 1 2 sqrt 2 div sub def
/D {0 360 arc fill} bind def
/F {exch findfont exch scalefont setfont} bind def
% place it nicely on the paper
/RESOLUTION 1024 def
RESOLUTION 2 div dup translate
RESOLUTION 2 div 2 sqrt div dup scale
%-------------------------------------------------------------------- planet --
PLANETCOLOR
0 0 1 D
%---------------------------------------------------------------------- hole --
HOLECOLOR
1 2 r mul sub dup r D
%---------------------------------------------------------------------- moon --
MOONCOLOR
1 1 r D
%---------------------------------------------------------------------- logo --
LOGOCOLOR
LOGOFONT
F
LOGO stringwidth pop 2 div neg
-0.5 moveto
LOGO show
%------------------------------------------------------------------------------
% based on code from Blue Book Program 10, on pages 167--169
% available at ftp://ftp.adobe.com/pub/adobe/displaypostscript/bluebook.shar
% str ptsize centerangle radius outsidecircletext --
/outsidecircletext {
circtextdict begin
/radius exch def
/centerangle exch def
/ptsize exch def
/str exch def
gsave
str radius ptsize findhalfangle
centerangle
add rotate
str
{ /charcode exch def
( ) dup 0 charcode put outsideplacechar
} forall
grestore
end
} def
% string radius ptsize findhalfangle halfangle
/findhalfangle {
4 div add
exch
stringwidth pop 2 div
exch
2 mul 3.1415926535 mul div 360 mul
} def
/circtextdict 16 dict def
circtextdict begin
/outsideplacechar {
/char exch def
/halfangle char radius ptsize findhalfangle def
gsave
halfangle neg rotate
1.4 0 translate
90 rotate
char stringwidth pop 2 div neg 0 moveto
char show
grestore
halfangle 2 mul neg rotate
} def
end
%--------------------------------------------------------------------- label --
LABELFONT
F
/LABELSIZE LABELFONT exch pop def
/LABELRADIUS LABELSIZE 3 div 1 r add sub neg 1.02 mul def
/HALFANGLE
LABEL LABELRADIUS LABELSIZE findhalfangle
HALFDASHANGLE div ceiling HALFDASHANGLE mul
def
/LABELANGLE
60 LABELANGLE HALFANGLE sub
lt
{
HALFANGLE
HALFANGLE DASHANGLE div floor DASHANGLE mul
eq
{LABELANGLE DASHANGLE div ceiling DASHANGLE mul}
{LABELANGLE HALFDASHANGLE sub DASHANGLE div round DASHANGLE mul HALFDASHANGLE add}
ifelse
}
{HALFANGLE 60 add}
ifelse
def
LABELCOLOR
LABEL
LABELSIZE
LABELANGLE
LABELRADIUS
outsidecircletext
%--------------------------------------------------------------------- orbit --
ORBITCOLOR
0.03 setlinewidth
[1 r add 3.1415926535 180 div HALFDASHANGLE mul mul] 0 setdash
newpath
0 0
1 r add
3 copy
30
LABELANGLE HALFANGLE add
arcn
stroke
60
LABELANGLE HALFANGLE sub
2 copy
lt {arc stroke} {4 {pop} repeat} ifelse
%------------------------------------------------------------------ copyright --
/COPYRIGHT
(Graphic design by A. Nakonechny. Copyright (c) 1998, All rights reserved.)
def
LABELCOLOR
LOGOFONT
32 div
F
2 sqrt 0.99 mul
dup
neg
moveto
COPYRIGHT
90 rotate
%show
%---------------------------------------------------------------------- done --
showpage
%%Trailer
%%EOF

View file

@ -0,0 +1,393 @@
===Filters, sources and sinks: design, motivation and examples===
==or Functional programming for the rest of us==
by DiegoNehab
{{{
}}}
===Abstract===
Certain operations can be implemented in the form of filters. A filter is a function that processes data received in consecutive function calls, returning partial results chunk by chunk. Examples of operations that can be implemented as filters include the end-of-line normalization for text, Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing, and there are many others. Filters become even more powerful when we allow them to be chained together to create composite filters. Filters can be seen as middle nodes in a chain of data transformations. Sources an sinks are the corresponding end points of these chains. A source is a function that produces data, chunk by chunk, and a sink is a function that takes data, chunk by chunk. In this technical note, we define an elegant interface for filters, sources, sinks and chaining. We evolve our interface progressively, until we reach a high degree of generality. We discuss difficulties that arise during the implementation of this interface and we provide solutions and examples.
===Introduction===
Applications sometimes have too much information to process to fit in memory and are thus forced to process data in smaller parts. Even when there is enough memory, processing all the data atomically may take long enough to frustrate a user that wants to interact with the application. Furthermore, complex transformations can often be defined as series of simpler operations. Several different complex transformations might share the same simpler operations, so that an uniform interface to combine them is desirable. The following concepts constitute our solution to these problems.
''Filters'' are functions that accept successive chunks of input, and produce successive chunks of output. Furthermore, the result of concatenating all the output data is the same as the result of applying the filter over the concatenation of the input data. As a consequence, boundaries are irrelevant: filters have to handle input data split arbitrarily by the user.
A ''chain'' is a function that combines the effect of two (or more) other functions, but whose interface is indistinguishable from the interface of one of its components. Thus, a chained filter can be used wherever an atomic filter can be used. However, its effect on data is the combined effect of its component filters. Note that, as a consequence, chains can be chained themselves to create arbitrarily complex operations that can be used just like atomic operations.
Filters can be seen as internal nodes in a network through which data flows, potentially being transformed along its way. Chains connect these nodes together. To complete the picture, we need ''sources'' and ''sinks'' as initial and final nodes of the network, respectively. Less abstractly, a source is a function that produces new data every time it is called. On the other hand, sinks are functions that give a final destination to the data they receive. Naturally, sources and sinks can be chained with filters.
Finally, filters, chains, sources, and sinks are all passive entities: they need to be repeatedly called in order for something to happen. ''Pumps'' provide the driving force that pushes data through the network, from a source to a sink.
Hopefully, these concepts will become clear with examples. In the following sections, we start with simplified interfaces, which we improve several times until we can find no obvious shortcomings. The evolution we present is not contrived: it follows the steps we followed ourselves as we consolidated our understanding of these concepts.
== A concrete example ==
Some data transformations are easier to implement as filters than others. Examples of operations that can be implemented as filters include the end-of-line normalization for text, the Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing, and many others. Let's use the end-of-line normalization as an example to define our initial filter interface. We later discuss why the implementation might not be trivial.
Assume we are given text in an unknown end-of-line convention (including possibly mixed conventions) out of the commonly found Unix (LF), Mac OS (CR), and DOS (CRLF) conventions. We would like to be able to write code like the following:
{{{
input = source.chain(source.file(io.stdin), normalize("\r\n"))
output = sink.file(io.stdout)
pump(input, output)
}}}
This program should read data from the standard input stream and normalize the end-of-line markers to the canonic CRLF marker defined by the MIME standard, finally sending the results to the standard output stream. For that, we use a ''file source'' to produce data from standard input, and chain it with a filter that normalizes the data. The pump then repeatedly gets data from the source, and moves it to the ''file sink'' that sends it to standard output.
To make the discussion even more concrete, we start by discussing the implementation of the normalization filter. The {{normalize}} ''factory'' is a function that creates such a filter. Our initial filter interface is as follows: the filter receives a chunk of input data, and returns a chunk of processed data. When there is no more input data, the user notifies the filter by invoking it with a {{nil}} chunk. The filter then returns the final chunk of processed data.
Although the interface is extremely simple, the implementation doesn't seem so obvious. Any filter respecting this interface needs to keep some kind of context between calls. This is because chunks can be broken between the CR and LF characters marking the end of a line. This need for context storage is what motivates the use of factories: each time the factory is called, it returns a filter with its own context so that we can have several independent filters being used at the same time. For the normalization filter, we know that the obvious solution (i.e. concatenating all the input into the context before producing any output) is not good enough, so we will have to find another way.
We will break the implementation in two parts: a low-level filter, and a factory of high-level filters. The low-level filter will be implemented in C and will not carry any context between function calls. The high-level filter factory, implemented in Lua, will create and return a high-level filter that keeps whatever context the low-level filter needs, but isolates the user from its internal details. That way, we take advantage of C's efficiency to perform the dirty work, and take advantage of Lua's simplicity for the bookkeeping.
==The Lua part of the implementation==
Below is the implementation of the factory of high-level end-of-line normalization filters:
{{{
function filter.cycle(low, ctx, extra)
return function(chunk)
local ret
ret, ctx = low(ctx, chunk, extra)
return ret
end
end
function normalize(marker)
return cycle(eol, 0, marker)
end
}}}
The {{normalize}} factory simply calls a more generic factory, the {{cycle}} factory. This factory receives a low-level filter, an initial context and some extra value and returns the corresponding high-level filter. Each time the high level filer is called with a new chunk, it calls the low-level filter passing the previous context, the new chunk and the extra argument. The low-level filter produces the chunk of processed data and a new context. Finally, the high-level filter updates its internal context and returns the processed chunk of data to the user. It is the low-level filter that does all the work. Notice that this implementation takes advantage of the Lua 5.0 lexical scoping rules to store the context locally, between function calls.
Moving to the low-level filter, we notice there is no perfect solution to the end-of-line marker normalization problem itself. The difficulty comes from an inherent ambiguity on the definition of empty lines within mixed input. However, the following solution works well for any consistent input, as well as for non-empty lines in mixed input. It also does a reasonable job with empty lines and serves as a good example of how to implement a low-level filter.
Here is what we do: CR and LF are considered candidates for line break. We issue ''one'' end-of-line line marker if one of the candidates is seen alone, or followed by a ''different'' candidate. That is, CR&nbsp;CR and LF&nbsp;LF issue two end of line markers each, but CR&nbsp;LF and LF&nbsp;CR issue only one marker. This idea takes care of Mac OS, Mac OS X, VMS and Unix, DOS and MIME, as well as probably other more obscure conventions.
==The C part of the implementation==
The low-level filter is divided into two simple functions. The inner function actually does the conversion. It takes each input character in turn, deciding what to output and how to modify the context. The context tells if the last character seen was a candidate and, if so, which candidate it was.
{{{
#define candidate(c) (c == CR || c == LF)
static int process(int c, int last, const char *marker, luaL_Buffer *buffer) {
if (candidate(c)) {
if (candidate(last)) {
if (c == last) luaL_addstring(buffer, marker);
return 0;
} else {
luaL_addstring(buffer, marker);
return c;
}
} else {
luaL_putchar(buffer, c);
return 0;
}
}
}}}
The inner function makes use of Lua's auxiliary library's buffer interface for its efficiency and ease of use. The outer function simply interfaces with Lua. It receives the context and the input chunk (as well as an optional end-of-line marker), and returns the transformed output and the new context.
{{{
static int eol(lua_State *L) {
int ctx = luaL_checkint(L, 1);
size_t isize = 0;
const char *input = luaL_optlstring(L, 2, NULL, &isize);
const char *last = input + isize;
const char *marker = luaL_optstring(L, 3, CRLF);
luaL_Buffer buffer;
luaL_buffinit(L, &amp;buffer);
if (!input) {
lua_pushnil(L);
lua_pushnumber(L, 0);
return 2;
}
while (input &lt; last)
ctx = process(*input++, ctx, marker, &amp;buffer);
luaL_pushresult(&amp;buffer);
lua_pushnumber(L, ctx);
return 2;
}
}}}
Notice that if the input chunk is {{nil}}, the operation is considered to be finished. In that case, the loop will not execute a single time and the context is reset to the initial state. This allows the filter to be reused indefinitely. It is a good idea to write filters like this, when possible.
Besides the end-of-line normalization filter shown above, many other filters can be implemented with the same ideas. Examples include Base64 and Quoted-Printable transfer content encodings, the breaking of text into lines, SMTP byte stuffing etc. The challenging part is to decide what will be the context. For line breaking, for instance, it could be the number of bytes left in the current line. For Base64 encoding, it could be the bytes that remain in the division of the input into 3-byte atoms.
===Chaining===
Filters become more powerful when the concept of chaining is introduced. Suppose you have a filter for Quoted-Printable encoding and you want to encode some text. According to the standard, the text has to be normalized into its canonic form prior to encoding. A nice interface that simplifies this task is a factory that creates a composite filter that passes data through multiple filters, but that can be used wherever a primitive filter is used.
{{{
local function chain2(f1, f2)
return function(chunk)
local ret = f2(f1(chunk))
if chunk then return ret
else return ret .. f2() end
end
end
function filter.chain(...)
local arg = {...}
local f = arg[1]
for i = 2, #arg do
f = chain2(f, arg[i])
end
return f
end
local chain = filter.chain(normalize("\r\n"), encode("quoted-printable"))
while 1 do
local chunk = io.read(2048)
io.write(chain(chunk))
if not chunk then break end
end
}}}
The chaining factory is very simple. All it does is return a function that passes data through all filters and returns the result to the user. It uses the simpler auxiliary function that knows how to chain two filters together. In the auxiliary function, special care must be taken if the chunk is final. This is because the final chunk notification has to be pushed through both filters in turn. Thanks to the chain factory, it is easy to perform the Quoted-Printable conversion, as the above example shows.
===Sources, sinks, and pumps===
As we noted in the introduction, the filters we introduced so far act as the internal nodes in a network of transformations. Information flows from node to node (or rather from one filter to the next) and is transformed on its way out. Chaining filters together is the way we found to connect nodes in the network. But what about the end nodes? In the beginning of the network, we need a node that provides the data, a source. In the end of the network, we need a node that takes in the data, a sink.
==Sources==
We start with two simple sources. The first is the {{empty}} source: It simply returns no data, possibly returning an error message. The second is the {{file}} source, which produces the contents of a file in a chunk by chunk fashion, closing the file handle when done.
{{{
function source.empty(err)
return function()
return nil, err
end
end
function source.file(handle, io_err)
if handle then
return function()
local chunk = handle:read(2048)
if not chunk then handle:close() end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
}}}
A source returns the next chunk of data each time it is called. When there is no more data, it just returns {{nil}}. If there is an error, the source can inform the caller by returning {{nil}} followed by an error message. Adrian Sietsma noticed that, although not on purpose, the interface for sources is compatible with the idea of iterators in Lua 5.0. That is, a data source can be nicely used in conjunction with {{for}} loops. Using our file source as an iterator, we can rewrite our first example:
{{{
local process = normalize("\r\n")
for chunk in source.file(io.stdin) do
io.write(process(chunk))
end
io.write(process(nil))
}}}
Notice that the last call to the filter obtains the last chunk of processed data. The loop terminates when the source returns {{nil}} and therefore we need that final call outside of the loop.
==Maintaining state between calls==
It is often the case that a source needs to change its behavior after some event. One simple example would be a file source that wants to make sure it returns {{nil}} regardless of how many times it is called after the end of file, avoiding attempts to read past the end of the file. Another example would be a source that returns the contents of several files, as if they were concatenated, moving from one file to the next until the end of the last file is reached.
One way to implement this kind of source is to have the factory declare extra state variables that the source can use via lexical scoping. Our file source could set the file handle itself to {{nil}} when it detects the end-of-file. Then, every time the source is called, it could check if the handle is still valid and act accordingly:
{{{
function source.file(handle, io_err)
if handle then
return function()
if not handle then return nil end
local chunk = handle:read(2048)
if not chunk then
handle:close()
handle = nil
end
return chunk
end
else return source.empty(io_err or "unable to open file") end
end
}}}
Another way to implement this behavior involves a change in the source interface to makes it more flexible. Let's allow a source to return a second value, besides the next chunk of data. If the returned chunk is {{nil}}, the extra return value tells us what happened. A second {{nil}} means that there is just no more data and the source is empty. Any other value is considered to be an error message. On the other hand, if the chunk was ''not'' {{nil}}, the second return value tells us whether the source wants to be replaced. If it is {{nil}}, we should proceed using the same source. Otherwise it has to be another source, which we have to use from then on, to get the remaining data.
This extra freedom is good for someone writing a source function, but it is a pain for those that have to use it. Fortunately, given one of these ''fancy'' sources, we can transform it into a simple source that never needs to be replaced, using the following factory.
{{{
function source.simplify(src)
return function()
local chunk, err_or_new = src()
src = err_or_new or src
if not chunk then return nil, err_or_new
else return chunk end
end
end
}}}
The simplification factory allows us to write fancy sources and use them as if they were simple. Therefore, our next functions will only produce simple sources, and functions that take sources will assume they are simple.
Going back to our file source, the extended interface allows for a more elegant implementation. The new source just asks to be replaced by an empty source as soon as there is no more data. There is no repeated checking of the handle. To make things simpler to the user, the factory itself simplifies the the fancy file source before returning it to the user:
{{{
function source.file(handle, io_err)
if handle then
return source.simplify(function()
local chunk = handle:read(2048)
if not chunk then
handle:close()
return "", source.empty()
end
return chunk
end)
else return source.empty(io_err or "unable to open file") end
end
}}}
We can make these ideas even more powerful if we use a new feature of Lua 5.0: coroutines. Coroutines suffer from a great lack of advertisement, and I am going to play my part here. Just like lexical scoping, coroutines taste odd at first, but once you get used with the concept, it can save your day. I have to admit that using coroutines to implement our file source would be overkill, so let's implement a concatenated source factory instead.
{{{
function source.cat(...)
local arg = {...}
local co = coroutine.create(function()
local i = 1
while i <= #arg do
local chunk, err = arg[i]()
if chunk then coroutine.yield(chunk)
elseif err then return nil, err
else i = i + 1 end
end
end)
return function()
return shift(coroutine.resume(co))
end
end
}}}
The factory creates two functions. The first is an auxiliary that does all the work, in the form of a coroutine. It reads a chunk from one of the sources. If the chunk is {{nil}}, it moves to the next source, otherwise it just yields returning the chunk. When it is resumed, it continues from where it stopped and tries to read the next chunk. The second function is the source itself, and just resumes the execution of the auxiliary coroutine, returning to the user whatever chunks it returns (skipping the first result that tells us if the coroutine terminated). Imagine writing the same function without coroutines and you will notice the simplicity of this implementation. We will use coroutines again when we make the filter interface more powerful.
==Chaining Sources==
What does it mean to chain a source with a filter? The most useful interpretation is that the combined source-filter is a new source that produces data and passes it through the filter before returning it. Here is a factory that does it:
{{{
function source.chain(src, f)
return source.simplify(function()
local chunk, err = src()
if not chunk then return f(nil), source.empty(err)
else return f(chunk) end
end)
end
}}}
Our motivating example in the introduction chains a source with a filter. The idea of chaining a source with a filter is useful when one thinks about functions that might get their input data from a source. By chaining a simple source with one or more filters, the same function can be provided with filtered data even though it is unaware of the filtering that is happening behind its back.
==Sinks==
Just as we defined an interface for an initial source of data, we can also define an interface for a final destination of data. We call any function respecting that interface a ''sink''. Below are two simple factories that return sinks. The table factory creates a sink that stores all obtained data into a table. The data can later be efficiently concatenated into a single string with the {{table.concat}} library function. As another example, we introduce the {{null}} sink: A sink that simply discards the data it receives.
{{{
function sink.table(t)
t = t or {}
local f = function(chunk, err)
if chunk then table.insert(t, chunk) end
return 1
end
return f, t
end
local function null()
return 1
end
function sink.null()
return null
end
}}}
Sinks receive consecutive chunks of data, until the end of data is notified with a {{nil}} chunk. An error is notified by an extra argument giving an error message after the {{nil}} chunk. If a sink detects an error itself and wishes not to be called again, it should return {{nil}}, optionally followed by an error message. A return value that is not {{nil}} means the source will accept more data. Finally, just as sources can choose to be replaced, so can sinks, following the same interface. Once again, it is easy to implement a {{sink.simplify}} factory that transforms a fancy sink into a simple sink.
As an example, let's create a source that reads from the standard input, then chain it with a filter that normalizes the end-of-line convention and let's use a sink to place all data into a table, printing the result in the end.
{{{
local load = source.chain(source.file(io.stdin), normalize("\r\n"))
local store, t = sink.table()
while 1 do
local chunk = load()
store(chunk)
if not chunk then break end
end
print(table.concat(t))
}}}
Again, just as we created a factory that produces a chained source-filter from a source and a filter, it is easy to create a factory that produces a new sink given a sink and a filter. The new sink passes all data it receives through the filter before handing it in to the original sink. Here is the implementation:
{{{
function sink.chain(f, snk)
return function(chunk, err)
local r, e = snk(f(chunk))
if not r then return nil, e end
if not chunk then return snk(nil, err) end
return 1
end
end
}}}
==Pumps==
There is a while loop that has been around for too long in our examples. It's always there because everything that we designed so far is passive. Sources, sinks, filters: None of them will do anything on their own. The operation of pumping all data a source can provide into a sink is so common that we will provide a couple helper functions to do that for us.
{{{
function pump.step(src, snk)
local chunk, src_err = src()
local ret, snk_err = snk(chunk, src_err)
return chunk and ret and not src_err and not snk_err, src_err or snk_err
end
function pump.all(src, snk, step)
step = step or pump.step
while true do
local ret, err = step(src, snk)
if not ret then return not err, err end
end
end
}}}
The {{pump.step}} function moves one chunk of data from the source to the sink. The {{pump.all}} function takes an optional {{step}} function and uses it to pump all the data from the source to the sink. We can now use everything we have to write a program that reads a binary file from disk and stores it in another file, after encoding it to the Base64 transfer content encoding:
{{{
local load = source.chain(
source.file(io.open("input.bin", "rb")),
encode("base64")
)
local store = sink.chain(
wrap(76),
sink.file(io.open("output.b64", "w")),
)
pump.all(load, store)
}}}
The way we split the filters here is not intuitive, on purpose. Alternatively, we could have chained the Base64 encode filter and the line-wrap filter together, and then chain the resulting filter with either the file source or the file sink. It doesn't really matter.
===One last important change===
Turns out we still have a problem. When David Burgess was writing his gzip filter, he noticed that the decompression filter can explode a small input chunk into a huge amount of data. Although we wished we could ignore this problem, we soon agreed we couldn't. The only solution is to allow filters to return partial results, and that is what we chose to do. After invoking the filter to pass input data, the user now has to loop invoking the filter to find out if it has more output data to return. Note that these extra calls can't pass more data to the filter.
More specifically, after passing a chunk of input data to a filter and collecting the first chunk of output data, the user invokes the filter repeatedly, passing the empty string, to get extra output chunks. When the filter itself returns an empty string, the user knows there is no more output data, and can proceed to pass the next input chunk. In the end, after the user passes a {{nil}} notifying the filter that there is no more input data, the filter might still have produced too much output data to return in a single chunk. The user has to loop again, this time passing {{nil}} each time, until the filter itself returns {{nil}} to notify the user it is finally done.
Most filters won't need this extra freedom. Fortunately, the new filter interface is easy to implement. In fact, the end-of-line translation filter we created in the introduction already conforms to it. On the other hand, the chaining function becomes much more complicated. If it wasn't for coroutines, I wouldn't be happy to implement it. Let me know if you can find a simpler implementation that does not use coroutines!
{{{
local function chain2(f1, f2)
local co = coroutine.create(function(chunk)
while true do
local filtered1 = f1(chunk)
local filtered2 = f2(filtered1)
local done2 = filtered1 and ""
while true do
if filtered2 == "" or filtered2 == nil then break end
coroutine.yield(filtered2)
filtered2 = f2(done2)
end
if filtered1 == "" then chunk = coroutine.yield(filtered1)
elseif filtered1 == nil then return nil
else chunk = chunk and "" end
end
end)
return function(chunk)
local _, res = coroutine.resume(co, chunk)
return res
end
end
}}}
Chaining sources also becomes more complicated, but a similar solution is possible with coroutines. Chaining sinks is just as simple as it has always been. Interestingly, these modifications do not have a measurable negative impact in the the performance of filters that didn't need the added flexibility. They do severely improve the efficiency of filters like the gzip filter, though, and that is why we are keeping them.
===Final considerations===
These ideas were created during the development of {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket] 2.0, and are available as the LTN12 module. As a result, {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket] implementation was greatly simplified and became much more powerful. The MIME module is especially integrated to LTN12 and provides many other filters. We felt these concepts deserved to be made public even to those that don't care about {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket], hence the LTN.
One extra application that deserves mentioning makes use of an identity filter. Suppose you want to provide some feedback to the user while a file is being downloaded into a sink. Chaining the sink with an identity filter (a filter that simply returns the received data unaltered), you can update a progress counter on the fly. The original sink doesn't have to be modified. Another interesting idea is that of a T sink: A sink that sends data to two other sinks. In summary, there appears to be enough room for many other interesting ideas.
In this technical note we introduced filters, sources, sinks, and pumps. These are useful tools for data processing in general. Sources provide a simple abstraction for data acquisition. Sinks provide an abstraction for final data destinations. Filters define an interface for data transformations. The chaining of filters, sources and sinks provides an elegant way to create arbitrarily complex data transformation from simpler transformations. Pumps just put the machinery to work.

View file

@ -0,0 +1,194 @@
===Using finalized exceptions===
==or How to get rid of all those if statements==
by DiegoNehab
{{{
}}}
===Abstract===
This little LTN describes a simple exception scheme that greatly simplifies error checking in Lua programs. All the needed functionality ships standard with Lua, but is hidden between the {{assert}} and {{pcall}} functions. To make it more evident, we stick to a convenient standard (you probably already use anyways) for Lua function return values, and define two very simple helper functions (either in C or in Lua itself).
===Introduction===
Most Lua functions return {{nil}} in case of error, followed by a message describing the error. If you don't use this convention, you probably have good reasons. Hopefully, after reading on, you will realize your reasons are not good enough.
If you are like me, you hate error checking. Most nice little code snippets that look beautiful when you first write them lose some of their charm when you add all that error checking code. Yet, error checking is as important as the rest of the code. How sad.
Even if you stick to a return convention, any complex task involving several function calls makes error checking both boring and error-prone (do you see the ''error'' below?)
{{{
function task(arg1, arg2, ...)
local ret1, err = task1(arg1)
if not ret1 then
cleanup1()
return nil, error
end
local ret2, err = task2(arg2)
if not ret then
cleanup2()
return nil, error
end
...
end
}}}
The standard {{assert}} function provides an interesting alternative. To use it, simply nest every function call to be error checked with a call to {{assert}}. The {{assert}} function checks the value of its first argument. If it is {{nil}}, {{assert}} throws the second argument as an error message. Otherwise, {{assert}} lets all arguments through as if had not been there. The idea greatly simplifies error checking:
{{{
function task(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end
}}}
If any task fails, the execution is aborted by {{assert}} and the error message is displayed to the user as the cause of the problem. If no error happens, the task completes as before. There isn't a single {{if}} statement and this is great. However, there are some problems with the idea.
First, the topmost {{task}} function doesn't respect the protocol followed by the lower-level tasks: It raises an error instead of returning {{nil}} followed by the error messages. Here is where the standard {{pcall}} comes in handy.
{{{
function xtask(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end
function task(arg1, arg2, ...)
local ok, ret_or_err = pcall(xtask, arg1, arg2, ...)
if ok then return ret_or_err
else return nil, ret_or_err end
end
}}}
Our new {{task}} function is well behaved. {{Pcall}} catches any error raised by the calls to {{assert}} and returns it after the status code. That way, errors don't get propagated to the user of the high level {{task}} function.
These are the main ideas for our exception scheme, but there are still a few glitches to fix:
* Directly using {{pcall}} ruined the simplicity of the code;
* What happened to the cleanup function calls? What if we have to, say, close a file?
* {{Assert}} messes with the error message before raising the error (it adds line number information).
Fortunately, all these problems are very easy to solve and that's what we do in the following sections.
== Introducing the {{protect}} factory ==
We used the {{pcall}} function to shield the user from errors that could be raised by the underlying implementation. Instead of directly using {{pcall}} (and thus duplicating code) every time we prefer a factory that does the same job:
{{{
local function pack(ok, ...)
return ok, {...}
end
function protect(f)
return function(...)
local ok, ret = pack(pcall(f, ...))
if ok then return unpack(ret)
else return nil, ret[1] end
end
end
}}}
The {{protect}} factory receives a function that might raise exceptions and returns a function that respects our return value convention. Now we can rewrite the top-level {{task}} function in a much cleaner way:
{{{
task = protect(function(arg1, arg2, ...)
local ret1 = assert(task1(arg1))
local ret2 = assert(task2(arg2))
...
end)
}}}
The Lua implementation of the {{protect}} factory suffers with the creation of tables to hold multiple arguments and return values. It is possible (and easy) to implement the same function in C, without any table creation.
{{{
static int safecall(lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
lua_pushnil(L);
lua_insert(L, 1);
return 2;
} else return lua_gettop(L);
}
static int protect(lua_State *L) {
lua_pushcclosure(L, safecall, 1);
return 1;
}
}}}
===The {{newtry}} factory===
Let's solve the two remaining issues with a single shot and use a concrete example to illustrate the proposed solution. Suppose you want to write a function to download an HTTP document. You have to connect, send the request and read the reply. Each of these tasks can fail, but if something goes wrong after you connected, you have to close the connection before returning the error message.
{{{
get = protect(function(host, path)
local c
-- create a try function with a finalizer to close the socket
local try = newtry(function()
if c then c:close() end
end)
-- connect and send request
c = try(connect(host, 80))
try(c:send("GET " .. path .. " HTTP/1.0\r\n\r\n"))
-- get headers
local h = {}
while 1 do
l = try(c:receive())
if l == "" then break end
table.insert(h, l)
end
-- get body
local b = try(c:receive("*a"))
c:close()
return b, h
end)
}}}
The {{newtry}} factory returns a function that works just like {{assert}}. The differences are that the {{try}} function doesn't mess with the error message and it calls an optional ''finalizer'' before raising the error. In our example, the finalizer simply closes the socket.
Even with a simple example like this, we see that the finalized exceptions simplified our life. Let's see what we gain in general, not just in this example:
* We don't need to declare dummy variables to hold error messages in case any ever shows up;
* We avoid using a variable to hold something that could either be a return value or an error message;
* We didn't have to use several ''if'' statements to check for errors;
* If an error happens, we know our finalizer is going to be invoked automatically;
* Exceptions get propagated, so we don't repeat these ''if'' statements until the error reaches the user.
Try writing the same function without the tricks we used above and you will see that the code gets ugly. Longer sequences of operations with error checking would get even uglier. So let's implement the {{newtry}} function in Lua:
{{{
function newtry(f)
return function(...)
if not arg[1] then
if f then f() end
error(arg[2], 0)
else
return ...
end
end
end
}}}
Again, the implementation suffers from the creation of tables at each function call, so we prefer the C version:
{{{
static int finalize(lua_State *L) {
if (!lua_toboolean(L, 1)) {
lua_pushvalue(L, lua_upvalueindex(1));
lua_pcall(L, 0, 0, 0);
lua_settop(L, 2);
lua_error(L);
return 0;
} else return lua_gettop(L);
}
static int do_nothing(lua_State *L) {
(void) L;
return 0;
}
static int newtry(lua_State *L) {
lua_settop(L, 1);
if (lua_isnil(L, 1))
lua_pushcfunction(L, do_nothing);
lua_pushcclosure(L, finalize, 1);
return 1;
}
}}}
===Final considerations===
The {{protect}} and {{newtry}} functions saved a ''lot'' of work in the implementation of {{LuaSocket}}[http://www.tecgraf.puc-rio.br/luasocket]. The size of some modules was cut in half by the these ideas. It's true the scheme is not as generic as the exception mechanism of programming languages like C++ or Java, but the power/simplicity ratio is favorable and I hope it serves you as well as it served {{LuaSocket}}.

View file

@ -0,0 +1,105 @@
package = "LuaSocket"
version = "scm-0"
source = {
url = "https://github.com/diegonehab/luasocket/archive/master.zip",
dir = "luasocket-master",
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core
that provides support for the TCP and UDP transport layers, and a set of Lua
modules that add support for functionality commonly needed by applications
that deal with the Internet.
]],
homepage = "http://luaforge.net/projects/luasocket/",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
local function make_plat(plat)
local defines = {
unix = {
"LUASOCKET_DEBUG",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
macosx = {
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
win32 = {
"LUASOCKET_DEBUG",
"NDEBUG",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
},
mingw32 = {
"LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON",
"WINVER=0x0501",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
}
}
local modules = {
["socket.core"] = {
sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c", "src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c", "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["mime.core"] = {
sources = { "src/mime.c", "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["socket.http"] = "src/http.lua",
["socket.url"] = "src/url.lua",
["socket.tp"] = "src/tp.lua",
["socket.ftp"] = "src/ftp.lua",
["socket.headers"] = "src/headers.lua",
["socket.smtp"] = "src/smtp.lua",
ltn12 = "src/ltn12.lua",
socket = "src/socket.lua",
mime = "src/mime.lua"
}
if plat == "unix" or plat == "macosx" or plat == "haiku" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
if plat == "haiku" then
modules["socket.core"].libraries = {"network"}
end
modules["socket.unix"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/unix.c" },
defines = defines[plat],
incdir = "/src"
}
modules["socket.serial"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/serial.c" },
defines = defines[plat],
incdir = "/src"
}
end
if plat == "win32" or plat == "mingw32" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
modules["socket.core"].libraries = { "ws2_32" }
end
return { modules = modules }
end
build = {
type = "builtin",
platforms = {
unix = make_plat("unix"),
macosx = make_plat("macosx"),
haiku = make_plat("haiku"),
win32 = make_plat("win32"),
mingw32 = make_plat("mingw32")
},
copy_directories = { "doc", "samples", "etc", "test" }
}

View file

@ -0,0 +1 @@
make DEBUG=DEBUG PLAT=macosx LUAINC_macosx_base=/Users/diego/build/macosx/include LUAPREFIX_macosx=/Users/diego/build/macosx install-both

View file

@ -0,0 +1,15 @@
#include <luashim.h>
int luaopen_socket_core(lua_State *L);
#ifdef _WIN32
__declspec(dllexport) int luaopen_luasocket(lua_State *L)
#else
int luaopen_luasocket(lua_State *L)
#endif
{
shimInitialize(L);
luaL_requiref(L, "socket", luaopen_socket_core, 1);
lua_pop(L, 1);
return 0;
}

View file

@ -0,0 +1,139 @@
#--------------------------------------------------------------------------
# Distribution makefile
#--------------------------------------------------------------------------
DIST = luasocket-3.0-rc1
TEST = \
test/README \
test/hello.lua \
test/testclnt.lua \
test/testsrvr.lua \
test/testsupport.lua
SAMPLES = \
samples/README \
samples/cddb.lua \
samples/daytimeclnt.lua \
samples/echoclnt.lua \
samples/echosrvr.lua \
samples/mclisten.lua \
samples/mcsend.lua \
samples/listener.lua \
samples/lpr.lua \
samples/talker.lua \
samples/tinyirc.lua
ETC = \
etc/README \
etc/b64.lua \
etc/check-links.lua \
etc/check-memory.lua \
etc/dict.lua \
etc/dispatch.lua \
etc/eol.lua \
etc/forward.lua \
etc/get.lua \
etc/lp.lua \
etc/qp.lua \
etc/tftp.lua
SRC = \
src/makefile \
src/auxiliar.c \
src/auxiliar.h \
src/buffer.c \
src/buffer.h \
src/except.c \
src/except.h \
src/inet.c \
src/inet.h \
src/io.c \
src/io.h \
src/luasocket.c \
src/luasocket.h \
src/mime.c \
src/mime.h \
src/options.c \
src/options.h \
src/select.c \
src/select.h \
src/socket.h \
src/tcp.c \
src/tcp.h \
src/timeout.c \
src/timeout.h \
src/udp.c \
src/udp.h \
src/unix.c \
src/serial.c \
src/unix.h \
src/usocket.c \
src/usocket.h \
src/wsocket.c \
src/wsocket.h \
src/ftp.lua \
src/http.lua \
src/ltn12.lua \
src/mime.lua \
src/smtp.lua \
src/socket.lua \
src/headers.lua \
src/tp.lua \
src/url.lua
MAKE = \
makefile \
luasocket.sln \
luasocket-scm-0.rockspec \
Lua51.props \
Lua52.props \
socket.vcxproj.filters \
mime.vcxproj.filters \
socket.vcxproj \
mime.vcxproj
DOC = \
doc/dns.html \
doc/ftp.html \
doc/index.html \
doc/http.html \
doc/installation.html \
doc/introduction.html \
doc/ltn12.html \
doc/luasocket.png \
doc/mime.html \
doc/reference.css \
doc/reference.html \
doc/smtp.html \
doc/socket.html \
doc/tcp.html \
doc/udp.html \
doc/url.html
dist:
mkdir -p $(DIST)
cp -vf NEW $(DIST)
cp -vf LICENSE $(DIST)
cp -vf README $(DIST)
cp -vf $(MAKE) $(DIST)
mkdir -p $(DIST)/etc
cp -vf $(ETC) $(DIST)/etc
mkdir -p $(DIST)/src
cp -vf $(SRC) $(DIST)/src
mkdir -p $(DIST)/doc
cp -vf $(DOC) $(DIST)/doc
mkdir -p $(DIST)/samples
cp -vf $(SAMPLES) $(DIST)/samples
mkdir -p $(DIST)/test
cp -vf $(TEST) $(DIST)/test
tar -zcvf $(DIST).tar.gz $(DIST)
zip -r $(DIST).zip $(DIST)
clean:
\rm -rf $(DIST) $(DIST).tar.gz $(DIST).zip

View file

@ -0,0 +1 @@
make PLAT=mingw LUAINC_mingw_base=/home/diego/build/mingw/include LUALIB_mingw_base=/home/diego/build/mingw/bin LUAPREFIX_mingw=/home/diego/build/mingw/bin DEBUG=DEBUG install-both

View file

@ -0,0 +1,51 @@
project "luasocket"
language "C"
kind "SharedLib"
warnings "extra"
includedirs
{
"../../contrib/lua/src",
"../../contrib/luashim"
}
links { 'luashim-lib' }
files
{
"src/*.c",
"src/*.h",
"src/*.lua",
"*.c"
}
filter "system:windows"
removefiles
{
"src/serial.c",
"src/unixdgram.*",
"src/unixstream.*",
"src/unix.*",
"src/usocket.*",
}
links { 'ws2_32' }
characterset "MBCS"
defines { "LUASOCKET_API=__declspec(dllexport)" }
filter "system:not windows"
removefiles
{
"src/wsocket.*",
}
pic "on"
defines { "LUASOCKET_API=__attribute__((visibility(\"default\")))" }
filter "configurations:Release"
targetdir "../../bin/release"
filter "configurations:Debug"
targetdir "../../bin/debug"

View file

@ -0,0 +1,105 @@
package = "LuaSocket"
version = "3.0rc2-1"
source = {
url = "git://github.com/diegonehab/luasocket.git",
tag = "v3.0-rc2",
}
description = {
summary = "Network support for the Lua language",
detailed = [[
LuaSocket is a Lua extension library that is composed by two parts: a C core
that provides support for the TCP and UDP transport layers, and a set of Lua
modules that add support for functionality commonly needed by applications
that deal with the Internet.
]],
homepage = "http://luaforge.net/projects/luasocket/",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
local function make_plat(plat)
local defines = {
unix = {
"LUASOCKET_DEBUG",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
macosx = {
"LUASOCKET_DEBUG",
"UNIX_HAS_SUN_LEN",
"LUASOCKET_API=__attribute__((visibility(\"default\")))",
"UNIX_API=__attribute__((visibility(\"default\")))",
"MIME_API=__attribute__((visibility(\"default\")))"
},
win32 = {
"LUASOCKET_DEBUG",
"NDEBUG",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
},
mingw32 = {
"LUASOCKET_DEBUG",
"LUASOCKET_INET_PTON",
"WINVER=0x0501",
"LUASOCKET_API=__declspec(dllexport)",
"MIME_API=__declspec(dllexport)"
}
}
local modules = {
["socket.core"] = {
sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c", "src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c", "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["mime.core"] = {
sources = { "src/mime.c", "src/compat.c" },
defines = defines[plat],
incdir = "/src"
},
["socket.http"] = "src/http.lua",
["socket.url"] = "src/url.lua",
["socket.tp"] = "src/tp.lua",
["socket.ftp"] = "src/ftp.lua",
["socket.headers"] = "src/headers.lua",
["socket.smtp"] = "src/smtp.lua",
ltn12 = "src/ltn12.lua",
socket = "src/socket.lua",
mime = "src/mime.lua"
}
if plat == "unix" or plat == "macosx" or plat == "haiku" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
if plat == "haiku" then
modules["socket.core"].libraries = {"network"}
end
modules["socket.unix"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/unix.c" },
defines = defines[plat],
incdir = "/src"
}
modules["socket.serial"] = {
sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/serial.c" },
defines = defines[plat],
incdir = "/src"
}
end
if plat == "win32" or plat == "mingw32" then
modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/wsocket.c"
modules["socket.core"].libraries = { "ws2_32" }
end
return { modules = modules }
end
build = {
type = "builtin",
platforms = {
unix = make_plat("unix"),
macosx = make_plat("macosx"),
haiku = make_plat("haiku"),
win32 = make_plat("win32"),
mingw32 = make_plat("mingw32")
},
copy_directories = { "doc", "samples", "etc", "test" }
}

Some files were not shown because too many files have changed in this diff Show more